diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/media/video/davinci | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/media/video/davinci')
23 files changed, 17738 insertions, 0 deletions
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig new file mode 100644 index 00000000000..60a456ebdc7 --- /dev/null +++ b/drivers/media/video/davinci/Kconfig | |||
@@ -0,0 +1,116 @@ | |||
1 | config DISPLAY_DAVINCI_DM646X_EVM | ||
2 | tristate "DM646x EVM Video Display" | ||
3 | depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM | ||
4 | select VIDEOBUF_DMA_CONTIG | ||
5 | select VIDEO_DAVINCI_VPIF | ||
6 | select VIDEO_ADV7343 | ||
7 | select VIDEO_THS7303 | ||
8 | help | ||
9 | Support for DM6467 based display device. | ||
10 | |||
11 | To compile this driver as a module, choose M here: the | ||
12 | module will be called vpif_display. | ||
13 | |||
14 | config CAPTURE_DAVINCI_DM646X_EVM | ||
15 | tristate "DM646x EVM Video Capture" | ||
16 | depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM | ||
17 | select VIDEOBUF_DMA_CONTIG | ||
18 | select VIDEO_DAVINCI_VPIF | ||
19 | help | ||
20 | Support for DM6467 based capture device. | ||
21 | |||
22 | To compile this driver as a module, choose M here: the | ||
23 | module will be called vpif_capture. | ||
24 | |||
25 | config VIDEO_DAVINCI_VPIF | ||
26 | tristate "DaVinci VPIF Driver" | ||
27 | depends on DISPLAY_DAVINCI_DM646X_EVM | ||
28 | help | ||
29 | Support for DaVinci VPIF Driver. | ||
30 | |||
31 | To compile this driver as a module, choose M here: the | ||
32 | module will be called vpif. | ||
33 | |||
34 | config VIDEO_VPSS_SYSTEM | ||
35 | tristate "VPSS System module driver" | ||
36 | depends on ARCH_DAVINCI | ||
37 | help | ||
38 | Support for vpss system module for video driver | ||
39 | |||
40 | config VIDEO_VPFE_CAPTURE | ||
41 | tristate "VPFE Video Capture Driver" | ||
42 | depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3) | ||
43 | select VIDEOBUF_DMA_CONTIG | ||
44 | help | ||
45 | Support for DMx/AMx VPFE based frame grabber. This is the | ||
46 | common V4L2 module for following DMx/AMx SoCs from Texas | ||
47 | Instruments:- DM6446, DM365, DM355 & AM3517/05. | ||
48 | |||
49 | To compile this driver as a module, choose M here: the | ||
50 | module will be called vpfe-capture. | ||
51 | |||
52 | config VIDEO_DM6446_CCDC | ||
53 | tristate "DM6446 CCDC HW module" | ||
54 | depends on VIDEO_VPFE_CAPTURE | ||
55 | select VIDEO_VPSS_SYSTEM | ||
56 | default y | ||
57 | help | ||
58 | Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces | ||
59 | with decoder modules such as TVP5146 over BT656 or | ||
60 | sensor module such as MT9T001 over a raw interface. This | ||
61 | module configures the interface and CCDC/ISIF to do | ||
62 | video frame capture from slave decoders. | ||
63 | |||
64 | To compile this driver as a module, choose M here: the | ||
65 | module will be called vpfe. | ||
66 | |||
67 | config VIDEO_DM355_CCDC | ||
68 | tristate "DM355 CCDC HW module" | ||
69 | depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE | ||
70 | select VIDEO_VPSS_SYSTEM | ||
71 | default y | ||
72 | help | ||
73 | Enables DM355 CCD hw module. DM355 CCDC hw interfaces | ||
74 | with decoder modules such as TVP5146 over BT656 or | ||
75 | sensor module such as MT9T001 over a raw interface. This | ||
76 | module configures the interface and CCDC/ISIF to do | ||
77 | video frame capture from a slave decoders | ||
78 | |||
79 | To compile this driver as a module, choose M here: the | ||
80 | module will be called vpfe. | ||
81 | |||
82 | config VIDEO_ISIF | ||
83 | tristate "ISIF HW module" | ||
84 | depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE | ||
85 | select VIDEO_VPSS_SYSTEM | ||
86 | default y | ||
87 | help | ||
88 | Enables ISIF hw module. This is the hardware module for | ||
89 | configuring ISIF in VPFE to capture Raw Bayer RGB data from | ||
90 | a image sensor or YUV data from a YUV source. | ||
91 | |||
92 | To compile this driver as a module, choose M here: the | ||
93 | module will be called vpfe. | ||
94 | |||
95 | config VIDEO_DM644X_VPBE | ||
96 | tristate "DM644X VPBE HW module" | ||
97 | depends on ARCH_DAVINCI_DM644x | ||
98 | select VIDEO_VPSS_SYSTEM | ||
99 | select VIDEOBUF_DMA_CONTIG | ||
100 | help | ||
101 | Enables VPBE modules used for display on a DM644x | ||
102 | SoC. | ||
103 | |||
104 | To compile this driver as a module, choose M here: the | ||
105 | module will be called vpbe. | ||
106 | |||
107 | |||
108 | config VIDEO_VPBE_DISPLAY | ||
109 | tristate "VPBE V4L2 Display driver" | ||
110 | depends on ARCH_DAVINCI_DM644x | ||
111 | select VIDEO_DM644X_VPBE | ||
112 | help | ||
113 | Enables VPBE V4L2 Display driver on a DM644x device | ||
114 | |||
115 | To compile this driver as a module, choose M here: the | ||
116 | module will be called vpbe_display. | ||
diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile new file mode 100644 index 00000000000..ae7dafb689a --- /dev/null +++ b/drivers/media/video/davinci/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # | ||
2 | # Makefile for the davinci video device drivers. | ||
3 | # | ||
4 | |||
5 | # VPIF | ||
6 | obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o | ||
7 | |||
8 | #DM646x EVM Display driver | ||
9 | obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o | ||
10 | #DM646x EVM Capture driver | ||
11 | obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o | ||
12 | |||
13 | # Capture: DM6446 and DM355 | ||
14 | obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o | ||
15 | obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o | ||
16 | obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o | ||
17 | obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o | ||
18 | obj-$(CONFIG_VIDEO_ISIF) += isif.o | ||
19 | obj-$(CONFIG_VIDEO_DM644X_VPBE) += vpbe.o vpbe_osd.o vpbe_venc.o | ||
20 | obj-$(CONFIG_VIDEO_VPBE_DISPLAY) += vpbe_display.o | ||
diff --git a/drivers/media/video/davinci/ccdc_hw_device.h b/drivers/media/video/davinci/ccdc_hw_device.h new file mode 100644 index 00000000000..86b9b351896 --- /dev/null +++ b/drivers/media/video/davinci/ccdc_hw_device.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * ccdc device API | ||
19 | */ | ||
20 | #ifndef _CCDC_HW_DEVICE_H | ||
21 | #define _CCDC_HW_DEVICE_H | ||
22 | |||
23 | #ifdef __KERNEL__ | ||
24 | #include <linux/videodev2.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <media/davinci/vpfe_types.h> | ||
27 | #include <media/davinci/ccdc_types.h> | ||
28 | |||
29 | /* | ||
30 | * ccdc hw operations | ||
31 | */ | ||
32 | struct ccdc_hw_ops { | ||
33 | /* Pointer to initialize function to initialize ccdc device */ | ||
34 | int (*open) (struct device *dev); | ||
35 | /* Pointer to deinitialize function */ | ||
36 | int (*close) (struct device *dev); | ||
37 | /* set ccdc base address */ | ||
38 | void (*set_ccdc_base)(void *base, int size); | ||
39 | /* Pointer to function to enable or disable ccdc */ | ||
40 | void (*enable) (int en); | ||
41 | /* reset sbl. only for 6446 */ | ||
42 | void (*reset) (void); | ||
43 | /* enable output to sdram */ | ||
44 | void (*enable_out_to_sdram) (int en); | ||
45 | /* Pointer to function to set hw parameters */ | ||
46 | int (*set_hw_if_params) (struct vpfe_hw_if_param *param); | ||
47 | /* get interface parameters */ | ||
48 | int (*get_hw_if_params) (struct vpfe_hw_if_param *param); | ||
49 | /* | ||
50 | * Pointer to function to set parameters. Used | ||
51 | * for implementing VPFE_S_CCDC_PARAMS | ||
52 | */ | ||
53 | int (*set_params) (void *params); | ||
54 | /* | ||
55 | * Pointer to function to get parameter. Used | ||
56 | * for implementing VPFE_G_CCDC_PARAMS | ||
57 | */ | ||
58 | int (*get_params) (void *params); | ||
59 | /* Pointer to function to configure ccdc */ | ||
60 | int (*configure) (void); | ||
61 | |||
62 | /* Pointer to function to set buffer type */ | ||
63 | int (*set_buftype) (enum ccdc_buftype buf_type); | ||
64 | /* Pointer to function to get buffer type */ | ||
65 | enum ccdc_buftype (*get_buftype) (void); | ||
66 | /* Pointer to function to set frame format */ | ||
67 | int (*set_frame_format) (enum ccdc_frmfmt frm_fmt); | ||
68 | /* Pointer to function to get frame format */ | ||
69 | enum ccdc_frmfmt (*get_frame_format) (void); | ||
70 | /* enumerate hw pix formats */ | ||
71 | int (*enum_pix)(u32 *hw_pix, int i); | ||
72 | /* Pointer to function to set buffer type */ | ||
73 | u32 (*get_pixel_format) (void); | ||
74 | /* Pointer to function to get pixel format. */ | ||
75 | int (*set_pixel_format) (u32 pixfmt); | ||
76 | /* Pointer to function to set image window */ | ||
77 | int (*set_image_window) (struct v4l2_rect *win); | ||
78 | /* Pointer to function to set image window */ | ||
79 | void (*get_image_window) (struct v4l2_rect *win); | ||
80 | /* Pointer to function to get line length */ | ||
81 | unsigned int (*get_line_length) (void); | ||
82 | |||
83 | /* Query CCDC control IDs */ | ||
84 | int (*queryctrl)(struct v4l2_queryctrl *qctrl); | ||
85 | /* Set CCDC control */ | ||
86 | int (*set_control)(struct v4l2_control *ctrl); | ||
87 | /* Get CCDC control */ | ||
88 | int (*get_control)(struct v4l2_control *ctrl); | ||
89 | |||
90 | /* Pointer to function to set frame buffer address */ | ||
91 | void (*setfbaddr) (unsigned long addr); | ||
92 | /* Pointer to function to get field id */ | ||
93 | int (*getfid) (void); | ||
94 | }; | ||
95 | |||
96 | struct ccdc_hw_device { | ||
97 | /* ccdc device name */ | ||
98 | char name[32]; | ||
99 | /* module owner */ | ||
100 | struct module *owner; | ||
101 | /* hw ops */ | ||
102 | struct ccdc_hw_ops hw_ops; | ||
103 | }; | ||
104 | |||
105 | /* Used by CCDC module to register & unregister with vpfe capture driver */ | ||
106 | int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); | ||
107 | void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); | ||
108 | |||
109 | #endif | ||
110 | #endif | ||
diff --git a/drivers/media/video/davinci/dm355_ccdc.c b/drivers/media/video/davinci/dm355_ccdc.c new file mode 100644 index 00000000000..c29ac88ffd7 --- /dev/null +++ b/drivers/media/video/davinci/dm355_ccdc.c | |||
@@ -0,0 +1,1082 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * CCDC hardware module for DM355 | ||
19 | * ------------------------------ | ||
20 | * | ||
21 | * This module is for configuring DM355 CCD controller of VPFE to capture | ||
22 | * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules | ||
23 | * such as Defect Pixel Correction, Color Space Conversion etc to | ||
24 | * pre-process the Bayer RGB data, before writing it to SDRAM. This | ||
25 | * module also allows application to configure individual | ||
26 | * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. | ||
27 | * To do so, application include dm355_ccdc.h and vpfe_capture.h header | ||
28 | * files. The setparams() API is called by vpfe_capture driver | ||
29 | * to configure module parameters | ||
30 | * | ||
31 | * TODO: 1) Raw bayer parameter settings and bayer capture | ||
32 | * 2) Split module parameter structure to module specific ioctl structs | ||
33 | * 3) add support for lense shading correction | ||
34 | * 4) investigate if enum used for user space type definition | ||
35 | * to be replaced by #defines or integer | ||
36 | */ | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | #include <linux/videodev2.h> | ||
40 | #include <linux/clk.h> | ||
41 | #include <linux/err.h> | ||
42 | |||
43 | #include <media/davinci/dm355_ccdc.h> | ||
44 | #include <media/davinci/vpss.h> | ||
45 | |||
46 | #include "dm355_ccdc_regs.h" | ||
47 | #include "ccdc_hw_device.h" | ||
48 | |||
49 | MODULE_LICENSE("GPL"); | ||
50 | MODULE_DESCRIPTION("CCDC Driver for DM355"); | ||
51 | MODULE_AUTHOR("Texas Instruments"); | ||
52 | |||
53 | static struct ccdc_oper_config { | ||
54 | struct device *dev; | ||
55 | /* CCDC interface type */ | ||
56 | enum vpfe_hw_if_type if_type; | ||
57 | /* Raw Bayer configuration */ | ||
58 | struct ccdc_params_raw bayer; | ||
59 | /* YCbCr configuration */ | ||
60 | struct ccdc_params_ycbcr ycbcr; | ||
61 | /* Master clock */ | ||
62 | struct clk *mclk; | ||
63 | /* slave clock */ | ||
64 | struct clk *sclk; | ||
65 | /* ccdc base address */ | ||
66 | void __iomem *base_addr; | ||
67 | } ccdc_cfg = { | ||
68 | /* Raw configurations */ | ||
69 | .bayer = { | ||
70 | .pix_fmt = CCDC_PIXFMT_RAW, | ||
71 | .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, | ||
72 | .win = CCDC_WIN_VGA, | ||
73 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
74 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
75 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
76 | .gain = { | ||
77 | .r_ye = 256, | ||
78 | .gb_g = 256, | ||
79 | .gr_cy = 256, | ||
80 | .b_mg = 256 | ||
81 | }, | ||
82 | .config_params = { | ||
83 | .datasft = 2, | ||
84 | .mfilt1 = CCDC_NO_MEDIAN_FILTER1, | ||
85 | .mfilt2 = CCDC_NO_MEDIAN_FILTER2, | ||
86 | .alaw = { | ||
87 | .gama_wd = 2, | ||
88 | }, | ||
89 | .blk_clamp = { | ||
90 | .sample_pixel = 1, | ||
91 | .dc_sub = 25 | ||
92 | }, | ||
93 | .col_pat_field0 = { | ||
94 | .olop = CCDC_GREEN_BLUE, | ||
95 | .olep = CCDC_BLUE, | ||
96 | .elop = CCDC_RED, | ||
97 | .elep = CCDC_GREEN_RED | ||
98 | }, | ||
99 | .col_pat_field1 = { | ||
100 | .olop = CCDC_GREEN_BLUE, | ||
101 | .olep = CCDC_BLUE, | ||
102 | .elop = CCDC_RED, | ||
103 | .elep = CCDC_GREEN_RED | ||
104 | }, | ||
105 | }, | ||
106 | }, | ||
107 | /* YCbCr configuration */ | ||
108 | .ycbcr = { | ||
109 | .win = CCDC_WIN_PAL, | ||
110 | .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, | ||
111 | .frm_fmt = CCDC_FRMFMT_INTERLACED, | ||
112 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
113 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
114 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
115 | .bt656_enable = 1, | ||
116 | .pix_order = CCDC_PIXORDER_CBYCRY, | ||
117 | .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED | ||
118 | }, | ||
119 | }; | ||
120 | |||
121 | |||
122 | /* Raw Bayer formats */ | ||
123 | static u32 ccdc_raw_bayer_pix_formats[] = | ||
124 | {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; | ||
125 | |||
126 | /* Raw YUV formats */ | ||
127 | static u32 ccdc_raw_yuv_pix_formats[] = | ||
128 | {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; | ||
129 | |||
130 | /* register access routines */ | ||
131 | static inline u32 regr(u32 offset) | ||
132 | { | ||
133 | return __raw_readl(ccdc_cfg.base_addr + offset); | ||
134 | } | ||
135 | |||
136 | static inline void regw(u32 val, u32 offset) | ||
137 | { | ||
138 | __raw_writel(val, ccdc_cfg.base_addr + offset); | ||
139 | } | ||
140 | |||
141 | static void ccdc_enable(int en) | ||
142 | { | ||
143 | unsigned int temp; | ||
144 | temp = regr(SYNCEN); | ||
145 | temp &= (~CCDC_SYNCEN_VDHDEN_MASK); | ||
146 | temp |= (en & CCDC_SYNCEN_VDHDEN_MASK); | ||
147 | regw(temp, SYNCEN); | ||
148 | } | ||
149 | |||
150 | static void ccdc_enable_output_to_sdram(int en) | ||
151 | { | ||
152 | unsigned int temp; | ||
153 | temp = regr(SYNCEN); | ||
154 | temp &= (~(CCDC_SYNCEN_WEN_MASK)); | ||
155 | temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK); | ||
156 | regw(temp, SYNCEN); | ||
157 | } | ||
158 | |||
159 | static void ccdc_config_gain_offset(void) | ||
160 | { | ||
161 | /* configure gain */ | ||
162 | regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN); | ||
163 | regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN); | ||
164 | regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN); | ||
165 | regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN); | ||
166 | /* configure offset */ | ||
167 | regw(ccdc_cfg.bayer.ccdc_offset, OFFSET); | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * ccdc_restore_defaults() | ||
172 | * This function restore power on defaults in the ccdc registers | ||
173 | */ | ||
174 | static int ccdc_restore_defaults(void) | ||
175 | { | ||
176 | int i; | ||
177 | |||
178 | dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults..."); | ||
179 | /* set all registers to zero */ | ||
180 | for (i = 0; i <= CCDC_REG_LAST; i += 4) | ||
181 | regw(0, i); | ||
182 | |||
183 | /* now override the values with power on defaults in registers */ | ||
184 | regw(MODESET_DEFAULT, MODESET); | ||
185 | /* no culling support */ | ||
186 | regw(CULH_DEFAULT, CULH); | ||
187 | regw(CULV_DEFAULT, CULV); | ||
188 | /* Set default Gain and Offset */ | ||
189 | ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT; | ||
190 | ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT; | ||
191 | ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT; | ||
192 | ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT; | ||
193 | ccdc_config_gain_offset(); | ||
194 | regw(OUTCLIP_DEFAULT, OUTCLIP); | ||
195 | regw(LSCCFG2_DEFAULT, LSCCFG2); | ||
196 | /* select ccdc input */ | ||
197 | if (vpss_select_ccdc_source(VPSS_CCDCIN)) { | ||
198 | dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source"); | ||
199 | return -EFAULT; | ||
200 | } | ||
201 | /* select ccdc clock */ | ||
202 | if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) { | ||
203 | dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock"); | ||
204 | return -EFAULT; | ||
205 | } | ||
206 | dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults..."); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int ccdc_open(struct device *device) | ||
211 | { | ||
212 | return ccdc_restore_defaults(); | ||
213 | } | ||
214 | |||
215 | static int ccdc_close(struct device *device) | ||
216 | { | ||
217 | /* disable clock */ | ||
218 | vpss_enable_clock(VPSS_CCDC_CLOCK, 0); | ||
219 | /* do nothing for now */ | ||
220 | return 0; | ||
221 | } | ||
222 | /* | ||
223 | * ccdc_setwin() | ||
224 | * This function will configure the window size to | ||
225 | * be capture in CCDC reg. | ||
226 | */ | ||
227 | static void ccdc_setwin(struct v4l2_rect *image_win, | ||
228 | enum ccdc_frmfmt frm_fmt, int ppc) | ||
229 | { | ||
230 | int horz_start, horz_nr_pixels; | ||
231 | int vert_start, vert_nr_lines; | ||
232 | int mid_img = 0; | ||
233 | |||
234 | dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); | ||
235 | |||
236 | /* | ||
237 | * ppc - per pixel count. indicates how many pixels per cell | ||
238 | * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. | ||
239 | * raw capture this is 1 | ||
240 | */ | ||
241 | horz_start = image_win->left << (ppc - 1); | ||
242 | horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; | ||
243 | |||
244 | /* Writing the horizontal info into the registers */ | ||
245 | regw(horz_start, SPH); | ||
246 | regw(horz_nr_pixels, NPH); | ||
247 | vert_start = image_win->top; | ||
248 | |||
249 | if (frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
250 | vert_nr_lines = (image_win->height >> 1) - 1; | ||
251 | vert_start >>= 1; | ||
252 | /* Since first line doesn't have any data */ | ||
253 | vert_start += 1; | ||
254 | /* configure VDINT0 and VDINT1 */ | ||
255 | regw(vert_start, VDINT0); | ||
256 | } else { | ||
257 | /* Since first line doesn't have any data */ | ||
258 | vert_start += 1; | ||
259 | vert_nr_lines = image_win->height - 1; | ||
260 | /* configure VDINT0 and VDINT1 */ | ||
261 | mid_img = vert_start + (image_win->height / 2); | ||
262 | regw(vert_start, VDINT0); | ||
263 | regw(mid_img, VDINT1); | ||
264 | } | ||
265 | regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0); | ||
266 | regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1); | ||
267 | regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV); | ||
268 | dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); | ||
269 | } | ||
270 | |||
271 | static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) | ||
272 | { | ||
273 | if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT || | ||
274 | ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) { | ||
275 | dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n"); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 || | ||
280 | ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) { | ||
281 | dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n"); | ||
282 | return -EINVAL; | ||
283 | } | ||
284 | |||
285 | if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 || | ||
286 | ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) { | ||
287 | dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n"); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | if ((ccdcparam->med_filt_thres < 0) || | ||
292 | (ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) { | ||
293 | dev_dbg(ccdc_cfg.dev, | ||
294 | "Invalid value of median filter thresold\n"); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | if (ccdcparam->data_sz < CCDC_DATA_16BITS || | ||
299 | ccdcparam->data_sz > CCDC_DATA_8BITS) { | ||
300 | dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n"); | ||
301 | return -EINVAL; | ||
302 | } | ||
303 | |||
304 | if (ccdcparam->alaw.enable) { | ||
305 | if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || | ||
306 | ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { | ||
307 | dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); | ||
308 | return -EINVAL; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | if (ccdcparam->blk_clamp.b_clamp_enable) { | ||
313 | if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS || | ||
314 | ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) { | ||
315 | dev_dbg(ccdc_cfg.dev, | ||
316 | "Invalid value of sample pixel\n"); | ||
317 | return -EINVAL; | ||
318 | } | ||
319 | if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES || | ||
320 | ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) { | ||
321 | dev_dbg(ccdc_cfg.dev, | ||
322 | "Invalid value of sample lines\n"); | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* Parameter operations */ | ||
330 | static int ccdc_set_params(void __user *params) | ||
331 | { | ||
332 | struct ccdc_config_params_raw ccdc_raw_params; | ||
333 | int x; | ||
334 | |||
335 | /* only raw module parameters can be set through the IOCTL */ | ||
336 | if (ccdc_cfg.if_type != VPFE_RAW_BAYER) | ||
337 | return -EINVAL; | ||
338 | |||
339 | x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); | ||
340 | if (x) { | ||
341 | dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" | ||
342 | "params, %d\n", x); | ||
343 | return -EFAULT; | ||
344 | } | ||
345 | |||
346 | if (!validate_ccdc_param(&ccdc_raw_params)) { | ||
347 | memcpy(&ccdc_cfg.bayer.config_params, | ||
348 | &ccdc_raw_params, | ||
349 | sizeof(ccdc_raw_params)); | ||
350 | return 0; | ||
351 | } | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | /* This function will configure CCDC for YCbCr video capture */ | ||
356 | static void ccdc_config_ycbcr(void) | ||
357 | { | ||
358 | struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; | ||
359 | u32 temp; | ||
360 | |||
361 | /* first set the CCDC power on defaults values in all registers */ | ||
362 | dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); | ||
363 | ccdc_restore_defaults(); | ||
364 | |||
365 | /* configure pixel format & video frame format */ | ||
366 | temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) << | ||
367 | CCDC_INPUT_MODE_SHIFT) | | ||
368 | ((params->frm_fmt & CCDC_FRM_FMT_MASK) << | ||
369 | CCDC_FRM_FMT_SHIFT)); | ||
370 | |||
371 | /* setup BT.656 sync mode */ | ||
372 | if (params->bt656_enable) { | ||
373 | regw(CCDC_REC656IF_BT656_EN, REC656IF); | ||
374 | /* | ||
375 | * configure the FID, VD, HD pin polarity fld,hd pol positive, | ||
376 | * vd negative, 8-bit pack mode | ||
377 | */ | ||
378 | temp |= CCDC_VD_POL_NEGATIVE; | ||
379 | } else { /* y/c external sync mode */ | ||
380 | temp |= (((params->fid_pol & CCDC_FID_POL_MASK) << | ||
381 | CCDC_FID_POL_SHIFT) | | ||
382 | ((params->hd_pol & CCDC_HD_POL_MASK) << | ||
383 | CCDC_HD_POL_SHIFT) | | ||
384 | ((params->vd_pol & CCDC_VD_POL_MASK) << | ||
385 | CCDC_VD_POL_SHIFT)); | ||
386 | } | ||
387 | |||
388 | /* pack the data to 8-bit */ | ||
389 | temp |= CCDC_DATA_PACK_ENABLE; | ||
390 | |||
391 | regw(temp, MODESET); | ||
392 | |||
393 | /* configure video window */ | ||
394 | ccdc_setwin(¶ms->win, params->frm_fmt, 2); | ||
395 | |||
396 | /* configure the order of y cb cr in SD-RAM */ | ||
397 | temp = (params->pix_order << CCDC_Y8POS_SHIFT); | ||
398 | temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC; | ||
399 | regw(temp, CCDCFG); | ||
400 | |||
401 | /* | ||
402 | * configure the horizontal line offset. This is done by rounding up | ||
403 | * width to a multiple of 16 pixels and multiply by two to account for | ||
404 | * y:cb:cr 4:2:2 data | ||
405 | */ | ||
406 | regw(((params->win.width * 2 + 31) >> 5), HSIZE); | ||
407 | |||
408 | /* configure the memory line offset */ | ||
409 | if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) { | ||
410 | /* two fields are interleaved in memory */ | ||
411 | regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST); | ||
412 | } | ||
413 | |||
414 | dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * ccdc_config_black_clamp() | ||
419 | * configure parameters for Optical Black Clamp | ||
420 | */ | ||
421 | static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) | ||
422 | { | ||
423 | u32 val; | ||
424 | |||
425 | if (!bclamp->b_clamp_enable) { | ||
426 | /* configure DCSub */ | ||
427 | regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB); | ||
428 | regw(0x0000, CLAMP); | ||
429 | return; | ||
430 | } | ||
431 | /* Enable the Black clamping, set sample lines and pixels */ | ||
432 | val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) | | ||
433 | ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << | ||
434 | CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE; | ||
435 | regw(val, CLAMP); | ||
436 | |||
437 | /* If Black clamping is enable then make dcsub 0 */ | ||
438 | val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK) | ||
439 | << CCDC_NUM_LINE_CALC_SHIFT; | ||
440 | regw(val, DCSUB); | ||
441 | } | ||
442 | |||
443 | /* | ||
444 | * ccdc_config_black_compense() | ||
445 | * configure parameters for Black Compensation | ||
446 | */ | ||
447 | static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) | ||
448 | { | ||
449 | u32 val; | ||
450 | |||
451 | val = (bcomp->b & CCDC_BLK_COMP_MASK) | | ||
452 | ((bcomp->gb & CCDC_BLK_COMP_MASK) << | ||
453 | CCDC_BLK_COMP_GB_COMP_SHIFT); | ||
454 | regw(val, BLKCMP1); | ||
455 | |||
456 | val = ((bcomp->gr & CCDC_BLK_COMP_MASK) << | ||
457 | CCDC_BLK_COMP_GR_COMP_SHIFT) | | ||
458 | ((bcomp->r & CCDC_BLK_COMP_MASK) << | ||
459 | CCDC_BLK_COMP_R_COMP_SHIFT); | ||
460 | regw(val, BLKCMP0); | ||
461 | } | ||
462 | |||
463 | /* | ||
464 | * ccdc_write_dfc_entry() | ||
465 | * write an entry in the dfc table. | ||
466 | */ | ||
467 | int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc) | ||
468 | { | ||
469 | /* TODO This is to be re-visited and adjusted */ | ||
470 | #define DFC_WRITE_WAIT_COUNT 1000 | ||
471 | u32 val, count = DFC_WRITE_WAIT_COUNT; | ||
472 | |||
473 | regw(dfc->dft_corr_vert[index], DFCMEM0); | ||
474 | regw(dfc->dft_corr_horz[index], DFCMEM1); | ||
475 | regw(dfc->dft_corr_sub1[index], DFCMEM2); | ||
476 | regw(dfc->dft_corr_sub2[index], DFCMEM3); | ||
477 | regw(dfc->dft_corr_sub3[index], DFCMEM4); | ||
478 | /* set WR bit to write */ | ||
479 | val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK; | ||
480 | regw(val, DFCMEMCTL); | ||
481 | |||
482 | /* | ||
483 | * Assume, it is very short. If we get an error, we need to | ||
484 | * adjust this value | ||
485 | */ | ||
486 | while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK) | ||
487 | count--; | ||
488 | /* | ||
489 | * TODO We expect the count to be non-zero to be successful. Adjust | ||
490 | * the count if write requires more time | ||
491 | */ | ||
492 | |||
493 | if (count) { | ||
494 | dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n"); | ||
495 | return -1; | ||
496 | } | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | /* | ||
501 | * ccdc_config_vdfc() | ||
502 | * configure parameters for Vertical Defect Correction | ||
503 | */ | ||
504 | static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc) | ||
505 | { | ||
506 | u32 val; | ||
507 | int i; | ||
508 | |||
509 | /* Configure General Defect Correction. The table used is from IPIPE */ | ||
510 | val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK; | ||
511 | |||
512 | /* Configure Vertical Defect Correction if needed */ | ||
513 | if (!dfc->ver_dft_en) { | ||
514 | /* Enable only General Defect Correction */ | ||
515 | regw(val, DFCCTL); | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | if (dfc->table_size > CCDC_DFT_TABLE_SIZE) | ||
520 | return -EINVAL; | ||
521 | |||
522 | val |= CCDC_DFCCTL_VDFC_DISABLE; | ||
523 | val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) << | ||
524 | CCDC_DFCCTL_VDFCSL_SHIFT; | ||
525 | val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) << | ||
526 | CCDC_DFCCTL_VDFCUDA_SHIFT; | ||
527 | val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) << | ||
528 | CCDC_DFCCTL_VDFLSFT_SHIFT; | ||
529 | regw(val , DFCCTL); | ||
530 | |||
531 | /* clear address ptr to offset 0 */ | ||
532 | val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT; | ||
533 | |||
534 | /* write defect table entries */ | ||
535 | for (i = 0; i < dfc->table_size; i++) { | ||
536 | /* increment address for non zero index */ | ||
537 | if (i != 0) | ||
538 | val = CCDC_DFCMEMCTL_INC_ADDR; | ||
539 | regw(val, DFCMEMCTL); | ||
540 | if (ccdc_write_dfc_entry(i, dfc) < 0) | ||
541 | return -EFAULT; | ||
542 | } | ||
543 | |||
544 | /* update saturation level and enable dfc */ | ||
545 | regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT); | ||
546 | val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK << | ||
547 | CCDC_DFCCTL_VDFCEN_SHIFT); | ||
548 | regw(val, DFCCTL); | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * ccdc_config_csc() | ||
554 | * configure parameters for color space conversion | ||
555 | * Each register CSCM0-7 has two values in S8Q5 format. | ||
556 | */ | ||
557 | static void ccdc_config_csc(struct ccdc_csc *csc) | ||
558 | { | ||
559 | u32 val1, val2; | ||
560 | int i; | ||
561 | |||
562 | if (!csc->enable) | ||
563 | return; | ||
564 | |||
565 | /* Enable the CSC sub-module */ | ||
566 | regw(CCDC_CSC_ENABLE, CSCCTL); | ||
567 | |||
568 | /* Converting the co-eff as per the format of the register */ | ||
569 | for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) { | ||
570 | if ((i % 2) == 0) { | ||
571 | /* CSCM - LSB */ | ||
572 | val1 = (csc->coeff[i].integer & | ||
573 | CCDC_CSC_COEF_INTEG_MASK) | ||
574 | << CCDC_CSC_COEF_INTEG_SHIFT; | ||
575 | /* | ||
576 | * convert decimal part to binary. Use 2 decimal | ||
577 | * precision, user values range from .00 - 0.99 | ||
578 | */ | ||
579 | val1 |= (((csc->coeff[i].decimal & | ||
580 | CCDC_CSC_COEF_DECIMAL_MASK) * | ||
581 | CCDC_CSC_DEC_MAX) / 100); | ||
582 | } else { | ||
583 | |||
584 | /* CSCM - MSB */ | ||
585 | val2 = (csc->coeff[i].integer & | ||
586 | CCDC_CSC_COEF_INTEG_MASK) | ||
587 | << CCDC_CSC_COEF_INTEG_SHIFT; | ||
588 | val2 |= (((csc->coeff[i].decimal & | ||
589 | CCDC_CSC_COEF_DECIMAL_MASK) * | ||
590 | CCDC_CSC_DEC_MAX) / 100); | ||
591 | val2 <<= CCDC_CSCM_MSB_SHIFT; | ||
592 | val2 |= val1; | ||
593 | regw(val2, (CSCM0 + ((i - 1) << 1))); | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * ccdc_config_color_patterns() | ||
600 | * configure parameters for color patterns | ||
601 | */ | ||
602 | static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0, | ||
603 | struct ccdc_col_pat *pat1) | ||
604 | { | ||
605 | u32 val; | ||
606 | |||
607 | val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) | | ||
608 | (pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) | | ||
609 | (pat1->elop << 12) | (pat1->elep << 14)); | ||
610 | regw(val, COLPTN); | ||
611 | } | ||
612 | |||
613 | /* This function will configure CCDC for Raw mode image capture */ | ||
614 | static int ccdc_config_raw(void) | ||
615 | { | ||
616 | struct ccdc_params_raw *params = &ccdc_cfg.bayer; | ||
617 | struct ccdc_config_params_raw *config_params = | ||
618 | &ccdc_cfg.bayer.config_params; | ||
619 | unsigned int val; | ||
620 | |||
621 | dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); | ||
622 | |||
623 | /* restore power on defaults to register */ | ||
624 | ccdc_restore_defaults(); | ||
625 | |||
626 | /* CCDCFG register: | ||
627 | * set CCD Not to swap input since input is RAW data | ||
628 | * set FID detection function to Latch at V-Sync | ||
629 | * set WENLOG - ccdc valid area to AND | ||
630 | * set TRGSEL to WENBIT | ||
631 | * set EXTRG to DISABLE | ||
632 | * disable latching function on VSYNC - shadowed registers | ||
633 | */ | ||
634 | regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC | | ||
635 | CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN | | ||
636 | CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG); | ||
637 | |||
638 | /* | ||
639 | * Set VDHD direction to input, input type to raw input | ||
640 | * normal data polarity, do not use external WEN | ||
641 | */ | ||
642 | val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL | | ||
643 | CCDC_EXWEN_DISABLE); | ||
644 | |||
645 | /* | ||
646 | * Configure the vertical sync polarity (MODESET.VDPOL), horizontal | ||
647 | * sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL), | ||
648 | * frame format(progressive or interlace), & pixel format (Input mode) | ||
649 | */ | ||
650 | val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | | ||
651 | ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | | ||
652 | ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | | ||
653 | ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | | ||
654 | ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT)); | ||
655 | |||
656 | /* set pack for alaw compression */ | ||
657 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
658 | config_params->alaw.enable) | ||
659 | val |= CCDC_DATA_PACK_ENABLE; | ||
660 | |||
661 | /* Configure for LPF */ | ||
662 | if (config_params->lpf_enable) | ||
663 | val |= (config_params->lpf_enable & CCDC_LPF_MASK) << | ||
664 | CCDC_LPF_SHIFT; | ||
665 | |||
666 | /* Configure the data shift */ | ||
667 | val |= (config_params->datasft & CCDC_DATASFT_MASK) << | ||
668 | CCDC_DATASFT_SHIFT; | ||
669 | regw(val , MODESET); | ||
670 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val); | ||
671 | |||
672 | /* Configure the Median Filter threshold */ | ||
673 | regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT); | ||
674 | |||
675 | /* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */ | ||
676 | val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT | | ||
677 | CCDC_CFA_MOSAIC; | ||
678 | |||
679 | /* Enable and configure aLaw register if needed */ | ||
680 | if (config_params->alaw.enable) { | ||
681 | val |= (CCDC_ALAW_ENABLE | | ||
682 | ((config_params->alaw.gama_wd & | ||
683 | CCDC_ALAW_GAMA_WD_MASK) << | ||
684 | CCDC_GAMMAWD_INPUT_SHIFT)); | ||
685 | } | ||
686 | |||
687 | /* Configure Median filter1 & filter2 */ | ||
688 | val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) | | ||
689 | (config_params->mfilt2 << CCDC_MFILT2_SHIFT)); | ||
690 | |||
691 | regw(val, GAMMAWD); | ||
692 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val); | ||
693 | |||
694 | /* configure video window */ | ||
695 | ccdc_setwin(¶ms->win, params->frm_fmt, 1); | ||
696 | |||
697 | /* Optical Clamp Averaging */ | ||
698 | ccdc_config_black_clamp(&config_params->blk_clamp); | ||
699 | |||
700 | /* Black level compensation */ | ||
701 | ccdc_config_black_compense(&config_params->blk_comp); | ||
702 | |||
703 | /* Vertical Defect Correction if needed */ | ||
704 | if (ccdc_config_vdfc(&config_params->vertical_dft) < 0) | ||
705 | return -EFAULT; | ||
706 | |||
707 | /* color space conversion */ | ||
708 | ccdc_config_csc(&config_params->csc); | ||
709 | |||
710 | /* color pattern */ | ||
711 | ccdc_config_color_patterns(&config_params->col_pat_field0, | ||
712 | &config_params->col_pat_field1); | ||
713 | |||
714 | /* Configure the Gain & offset control */ | ||
715 | ccdc_config_gain_offset(); | ||
716 | |||
717 | dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val); | ||
718 | |||
719 | /* Configure DATAOFST register */ | ||
720 | val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) << | ||
721 | CCDC_DATAOFST_H_SHIFT; | ||
722 | val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) << | ||
723 | CCDC_DATAOFST_V_SHIFT; | ||
724 | regw(val, DATAOFST); | ||
725 | |||
726 | /* configuring HSIZE register */ | ||
727 | val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) << | ||
728 | CCDC_HSIZE_FLIP_SHIFT; | ||
729 | |||
730 | /* If pack 8 is enable then 1 pixel will take 1 byte */ | ||
731 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
732 | config_params->alaw.enable) { | ||
733 | val |= (((params->win.width) + 31) >> 5) & | ||
734 | CCDC_HSIZE_VAL_MASK; | ||
735 | |||
736 | /* adjust to multiple of 32 */ | ||
737 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", | ||
738 | (((params->win.width) + 31) >> 5) & | ||
739 | CCDC_HSIZE_VAL_MASK); | ||
740 | } else { | ||
741 | /* else one pixel will take 2 byte */ | ||
742 | val |= (((params->win.width * 2) + 31) >> 5) & | ||
743 | CCDC_HSIZE_VAL_MASK; | ||
744 | |||
745 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n", | ||
746 | (((params->win.width * 2) + 31) >> 5) & | ||
747 | CCDC_HSIZE_VAL_MASK); | ||
748 | } | ||
749 | regw(val, HSIZE); | ||
750 | |||
751 | /* Configure SDOFST register */ | ||
752 | if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
753 | if (params->image_invert_enable) { | ||
754 | /* For interlace inverse mode */ | ||
755 | regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST); | ||
756 | dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", | ||
757 | CCDC_SDOFST_INTERLACE_INVERSE); | ||
758 | } else { | ||
759 | /* For interlace non inverse mode */ | ||
760 | regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST); | ||
761 | dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", | ||
762 | CCDC_SDOFST_INTERLACE_NORMAL); | ||
763 | } | ||
764 | } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { | ||
765 | if (params->image_invert_enable) { | ||
766 | /* For progessive inverse mode */ | ||
767 | regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST); | ||
768 | dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", | ||
769 | CCDC_SDOFST_PROGRESSIVE_INVERSE); | ||
770 | } else { | ||
771 | /* For progessive non inverse mode */ | ||
772 | regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST); | ||
773 | dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n", | ||
774 | CCDC_SDOFST_PROGRESSIVE_NORMAL); | ||
775 | } | ||
776 | } | ||
777 | dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); | ||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static int ccdc_configure(void) | ||
782 | { | ||
783 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
784 | return ccdc_config_raw(); | ||
785 | else | ||
786 | ccdc_config_ycbcr(); | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int ccdc_set_buftype(enum ccdc_buftype buf_type) | ||
791 | { | ||
792 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
793 | ccdc_cfg.bayer.buf_type = buf_type; | ||
794 | else | ||
795 | ccdc_cfg.ycbcr.buf_type = buf_type; | ||
796 | return 0; | ||
797 | } | ||
798 | static enum ccdc_buftype ccdc_get_buftype(void) | ||
799 | { | ||
800 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
801 | return ccdc_cfg.bayer.buf_type; | ||
802 | return ccdc_cfg.ycbcr.buf_type; | ||
803 | } | ||
804 | |||
805 | static int ccdc_enum_pix(u32 *pix, int i) | ||
806 | { | ||
807 | int ret = -EINVAL; | ||
808 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { | ||
809 | if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { | ||
810 | *pix = ccdc_raw_bayer_pix_formats[i]; | ||
811 | ret = 0; | ||
812 | } | ||
813 | } else { | ||
814 | if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { | ||
815 | *pix = ccdc_raw_yuv_pix_formats[i]; | ||
816 | ret = 0; | ||
817 | } | ||
818 | } | ||
819 | return ret; | ||
820 | } | ||
821 | |||
822 | static int ccdc_set_pixel_format(u32 pixfmt) | ||
823 | { | ||
824 | struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; | ||
825 | |||
826 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { | ||
827 | ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; | ||
828 | if (pixfmt == V4L2_PIX_FMT_SBGGR8) | ||
829 | alaw->enable = 1; | ||
830 | else if (pixfmt != V4L2_PIX_FMT_SBGGR16) | ||
831 | return -EINVAL; | ||
832 | } else { | ||
833 | if (pixfmt == V4L2_PIX_FMT_YUYV) | ||
834 | ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; | ||
835 | else if (pixfmt == V4L2_PIX_FMT_UYVY) | ||
836 | ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; | ||
837 | else | ||
838 | return -EINVAL; | ||
839 | } | ||
840 | return 0; | ||
841 | } | ||
842 | static u32 ccdc_get_pixel_format(void) | ||
843 | { | ||
844 | struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; | ||
845 | u32 pixfmt; | ||
846 | |||
847 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
848 | if (alaw->enable) | ||
849 | pixfmt = V4L2_PIX_FMT_SBGGR8; | ||
850 | else | ||
851 | pixfmt = V4L2_PIX_FMT_SBGGR16; | ||
852 | else { | ||
853 | if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) | ||
854 | pixfmt = V4L2_PIX_FMT_YUYV; | ||
855 | else | ||
856 | pixfmt = V4L2_PIX_FMT_UYVY; | ||
857 | } | ||
858 | return pixfmt; | ||
859 | } | ||
860 | static int ccdc_set_image_window(struct v4l2_rect *win) | ||
861 | { | ||
862 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
863 | ccdc_cfg.bayer.win = *win; | ||
864 | else | ||
865 | ccdc_cfg.ycbcr.win = *win; | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | static void ccdc_get_image_window(struct v4l2_rect *win) | ||
870 | { | ||
871 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
872 | *win = ccdc_cfg.bayer.win; | ||
873 | else | ||
874 | *win = ccdc_cfg.ycbcr.win; | ||
875 | } | ||
876 | |||
877 | static unsigned int ccdc_get_line_length(void) | ||
878 | { | ||
879 | struct ccdc_config_params_raw *config_params = | ||
880 | &ccdc_cfg.bayer.config_params; | ||
881 | unsigned int len; | ||
882 | |||
883 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { | ||
884 | if ((config_params->alaw.enable) || | ||
885 | (config_params->data_sz == CCDC_DATA_8BITS)) | ||
886 | len = ccdc_cfg.bayer.win.width; | ||
887 | else | ||
888 | len = ccdc_cfg.bayer.win.width * 2; | ||
889 | } else | ||
890 | len = ccdc_cfg.ycbcr.win.width * 2; | ||
891 | return ALIGN(len, 32); | ||
892 | } | ||
893 | |||
894 | static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) | ||
895 | { | ||
896 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
897 | ccdc_cfg.bayer.frm_fmt = frm_fmt; | ||
898 | else | ||
899 | ccdc_cfg.ycbcr.frm_fmt = frm_fmt; | ||
900 | return 0; | ||
901 | } | ||
902 | |||
903 | static enum ccdc_frmfmt ccdc_get_frame_format(void) | ||
904 | { | ||
905 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
906 | return ccdc_cfg.bayer.frm_fmt; | ||
907 | else | ||
908 | return ccdc_cfg.ycbcr.frm_fmt; | ||
909 | } | ||
910 | |||
911 | static int ccdc_getfid(void) | ||
912 | { | ||
913 | return (regr(MODESET) >> 15) & 1; | ||
914 | } | ||
915 | |||
916 | /* misc operations */ | ||
917 | static inline void ccdc_setfbaddr(unsigned long addr) | ||
918 | { | ||
919 | regw((addr >> 21) & 0x007f, STADRH); | ||
920 | regw((addr >> 5) & 0x0ffff, STADRL); | ||
921 | } | ||
922 | |||
923 | static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) | ||
924 | { | ||
925 | ccdc_cfg.if_type = params->if_type; | ||
926 | |||
927 | switch (params->if_type) { | ||
928 | case VPFE_BT656: | ||
929 | case VPFE_YCBCR_SYNC_16: | ||
930 | case VPFE_YCBCR_SYNC_8: | ||
931 | ccdc_cfg.ycbcr.vd_pol = params->vdpol; | ||
932 | ccdc_cfg.ycbcr.hd_pol = params->hdpol; | ||
933 | break; | ||
934 | default: | ||
935 | /* TODO add support for raw bayer here */ | ||
936 | return -EINVAL; | ||
937 | } | ||
938 | return 0; | ||
939 | } | ||
940 | |||
941 | static struct ccdc_hw_device ccdc_hw_dev = { | ||
942 | .name = "DM355 CCDC", | ||
943 | .owner = THIS_MODULE, | ||
944 | .hw_ops = { | ||
945 | .open = ccdc_open, | ||
946 | .close = ccdc_close, | ||
947 | .enable = ccdc_enable, | ||
948 | .enable_out_to_sdram = ccdc_enable_output_to_sdram, | ||
949 | .set_hw_if_params = ccdc_set_hw_if_params, | ||
950 | .set_params = ccdc_set_params, | ||
951 | .configure = ccdc_configure, | ||
952 | .set_buftype = ccdc_set_buftype, | ||
953 | .get_buftype = ccdc_get_buftype, | ||
954 | .enum_pix = ccdc_enum_pix, | ||
955 | .set_pixel_format = ccdc_set_pixel_format, | ||
956 | .get_pixel_format = ccdc_get_pixel_format, | ||
957 | .set_frame_format = ccdc_set_frame_format, | ||
958 | .get_frame_format = ccdc_get_frame_format, | ||
959 | .set_image_window = ccdc_set_image_window, | ||
960 | .get_image_window = ccdc_get_image_window, | ||
961 | .get_line_length = ccdc_get_line_length, | ||
962 | .setfbaddr = ccdc_setfbaddr, | ||
963 | .getfid = ccdc_getfid, | ||
964 | }, | ||
965 | }; | ||
966 | |||
967 | static int __init dm355_ccdc_probe(struct platform_device *pdev) | ||
968 | { | ||
969 | void (*setup_pinmux)(void); | ||
970 | struct resource *res; | ||
971 | int status = 0; | ||
972 | |||
973 | /* | ||
974 | * first try to register with vpfe. If not correct platform, then we | ||
975 | * don't have to iomap | ||
976 | */ | ||
977 | status = vpfe_register_ccdc_device(&ccdc_hw_dev); | ||
978 | if (status < 0) | ||
979 | return status; | ||
980 | |||
981 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
982 | if (!res) { | ||
983 | status = -ENODEV; | ||
984 | goto fail_nores; | ||
985 | } | ||
986 | |||
987 | res = request_mem_region(res->start, resource_size(res), res->name); | ||
988 | if (!res) { | ||
989 | status = -EBUSY; | ||
990 | goto fail_nores; | ||
991 | } | ||
992 | |||
993 | ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); | ||
994 | if (!ccdc_cfg.base_addr) { | ||
995 | status = -ENOMEM; | ||
996 | goto fail_nomem; | ||
997 | } | ||
998 | |||
999 | /* Get and enable Master clock */ | ||
1000 | ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); | ||
1001 | if (IS_ERR(ccdc_cfg.mclk)) { | ||
1002 | status = PTR_ERR(ccdc_cfg.mclk); | ||
1003 | goto fail_nomap; | ||
1004 | } | ||
1005 | if (clk_enable(ccdc_cfg.mclk)) { | ||
1006 | status = -ENODEV; | ||
1007 | goto fail_mclk; | ||
1008 | } | ||
1009 | |||
1010 | /* Get and enable Slave clock */ | ||
1011 | ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); | ||
1012 | if (IS_ERR(ccdc_cfg.sclk)) { | ||
1013 | status = PTR_ERR(ccdc_cfg.sclk); | ||
1014 | goto fail_mclk; | ||
1015 | } | ||
1016 | if (clk_enable(ccdc_cfg.sclk)) { | ||
1017 | status = -ENODEV; | ||
1018 | goto fail_sclk; | ||
1019 | } | ||
1020 | |||
1021 | /* Platform data holds setup_pinmux function ptr */ | ||
1022 | if (NULL == pdev->dev.platform_data) { | ||
1023 | status = -ENODEV; | ||
1024 | goto fail_sclk; | ||
1025 | } | ||
1026 | setup_pinmux = pdev->dev.platform_data; | ||
1027 | /* | ||
1028 | * setup Mux configuration for ccdc which may be different for | ||
1029 | * different SoCs using this CCDC | ||
1030 | */ | ||
1031 | setup_pinmux(); | ||
1032 | ccdc_cfg.dev = &pdev->dev; | ||
1033 | printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); | ||
1034 | return 0; | ||
1035 | fail_sclk: | ||
1036 | clk_put(ccdc_cfg.sclk); | ||
1037 | fail_mclk: | ||
1038 | clk_put(ccdc_cfg.mclk); | ||
1039 | fail_nomap: | ||
1040 | iounmap(ccdc_cfg.base_addr); | ||
1041 | fail_nomem: | ||
1042 | release_mem_region(res->start, resource_size(res)); | ||
1043 | fail_nores: | ||
1044 | vpfe_unregister_ccdc_device(&ccdc_hw_dev); | ||
1045 | return status; | ||
1046 | } | ||
1047 | |||
1048 | static int dm355_ccdc_remove(struct platform_device *pdev) | ||
1049 | { | ||
1050 | struct resource *res; | ||
1051 | |||
1052 | clk_put(ccdc_cfg.mclk); | ||
1053 | clk_put(ccdc_cfg.sclk); | ||
1054 | iounmap(ccdc_cfg.base_addr); | ||
1055 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1056 | if (res) | ||
1057 | release_mem_region(res->start, resource_size(res)); | ||
1058 | vpfe_unregister_ccdc_device(&ccdc_hw_dev); | ||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | static struct platform_driver dm355_ccdc_driver = { | ||
1063 | .driver = { | ||
1064 | .name = "dm355_ccdc", | ||
1065 | .owner = THIS_MODULE, | ||
1066 | }, | ||
1067 | .remove = __devexit_p(dm355_ccdc_remove), | ||
1068 | .probe = dm355_ccdc_probe, | ||
1069 | }; | ||
1070 | |||
1071 | static int __init dm355_ccdc_init(void) | ||
1072 | { | ||
1073 | return platform_driver_register(&dm355_ccdc_driver); | ||
1074 | } | ||
1075 | |||
1076 | static void __exit dm355_ccdc_exit(void) | ||
1077 | { | ||
1078 | platform_driver_unregister(&dm355_ccdc_driver); | ||
1079 | } | ||
1080 | |||
1081 | module_init(dm355_ccdc_init); | ||
1082 | 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 new file mode 100644 index 00000000000..d6d2ef0533b --- /dev/null +++ b/drivers/media/video/davinci/dm355_ccdc_regs.h | |||
@@ -0,0 +1,310 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _DM355_CCDC_REGS_H | ||
19 | #define _DM355_CCDC_REGS_H | ||
20 | |||
21 | /**************************************************************************\ | ||
22 | * Register OFFSET Definitions | ||
23 | \**************************************************************************/ | ||
24 | #define SYNCEN 0x00 | ||
25 | #define MODESET 0x04 | ||
26 | #define HDWIDTH 0x08 | ||
27 | #define VDWIDTH 0x0c | ||
28 | #define PPLN 0x10 | ||
29 | #define LPFR 0x14 | ||
30 | #define SPH 0x18 | ||
31 | #define NPH 0x1c | ||
32 | #define SLV0 0x20 | ||
33 | #define SLV1 0x24 | ||
34 | #define NLV 0x28 | ||
35 | #define CULH 0x2c | ||
36 | #define CULV 0x30 | ||
37 | #define HSIZE 0x34 | ||
38 | #define SDOFST 0x38 | ||
39 | #define STADRH 0x3c | ||
40 | #define STADRL 0x40 | ||
41 | #define CLAMP 0x44 | ||
42 | #define DCSUB 0x48 | ||
43 | #define COLPTN 0x4c | ||
44 | #define BLKCMP0 0x50 | ||
45 | #define BLKCMP1 0x54 | ||
46 | #define MEDFILT 0x58 | ||
47 | #define RYEGAIN 0x5c | ||
48 | #define GRCYGAIN 0x60 | ||
49 | #define GBGGAIN 0x64 | ||
50 | #define BMGGAIN 0x68 | ||
51 | #define OFFSET 0x6c | ||
52 | #define OUTCLIP 0x70 | ||
53 | #define VDINT0 0x74 | ||
54 | #define VDINT1 0x78 | ||
55 | #define RSV0 0x7c | ||
56 | #define GAMMAWD 0x80 | ||
57 | #define REC656IF 0x84 | ||
58 | #define CCDCFG 0x88 | ||
59 | #define FMTCFG 0x8c | ||
60 | #define FMTPLEN 0x90 | ||
61 | #define FMTSPH 0x94 | ||
62 | #define FMTLNH 0x98 | ||
63 | #define FMTSLV 0x9c | ||
64 | #define FMTLNV 0xa0 | ||
65 | #define FMTRLEN 0xa4 | ||
66 | #define FMTHCNT 0xa8 | ||
67 | #define FMT_ADDR_PTR_B 0xac | ||
68 | #define FMT_ADDR_PTR(i) (FMT_ADDR_PTR_B + (i * 4)) | ||
69 | #define FMTPGM_VF0 0xcc | ||
70 | #define FMTPGM_VF1 0xd0 | ||
71 | #define FMTPGM_AP0 0xd4 | ||
72 | #define FMTPGM_AP1 0xd8 | ||
73 | #define FMTPGM_AP2 0xdc | ||
74 | #define FMTPGM_AP3 0xe0 | ||
75 | #define FMTPGM_AP4 0xe4 | ||
76 | #define FMTPGM_AP5 0xe8 | ||
77 | #define FMTPGM_AP6 0xec | ||
78 | #define FMTPGM_AP7 0xf0 | ||
79 | #define LSCCFG1 0xf4 | ||
80 | #define LSCCFG2 0xf8 | ||
81 | #define LSCH0 0xfc | ||
82 | #define LSCV0 0x100 | ||
83 | #define LSCKH 0x104 | ||
84 | #define LSCKV 0x108 | ||
85 | #define LSCMEMCTL 0x10c | ||
86 | #define LSCMEMD 0x110 | ||
87 | #define LSCMEMQ 0x114 | ||
88 | #define DFCCTL 0x118 | ||
89 | #define DFCVSAT 0x11c | ||
90 | #define DFCMEMCTL 0x120 | ||
91 | #define DFCMEM0 0x124 | ||
92 | #define DFCMEM1 0x128 | ||
93 | #define DFCMEM2 0x12c | ||
94 | #define DFCMEM3 0x130 | ||
95 | #define DFCMEM4 0x134 | ||
96 | #define CSCCTL 0x138 | ||
97 | #define CSCM0 0x13c | ||
98 | #define CSCM1 0x140 | ||
99 | #define CSCM2 0x144 | ||
100 | #define CSCM3 0x148 | ||
101 | #define CSCM4 0x14c | ||
102 | #define CSCM5 0x150 | ||
103 | #define CSCM6 0x154 | ||
104 | #define CSCM7 0x158 | ||
105 | #define DATAOFST 0x15c | ||
106 | #define CCDC_REG_LAST DATAOFST | ||
107 | /************************************************************** | ||
108 | * Define for various register bit mask and shifts for CCDC | ||
109 | * | ||
110 | **************************************************************/ | ||
111 | #define CCDC_RAW_IP_MODE 0 | ||
112 | #define CCDC_VDHDOUT_INPUT 0 | ||
113 | #define CCDC_YCINSWP_RAW (0 << 4) | ||
114 | #define CCDC_EXWEN_DISABLE 0 | ||
115 | #define CCDC_DATAPOL_NORMAL 0 | ||
116 | #define CCDC_CCDCFG_FIDMD_LATCH_VSYNC 0 | ||
117 | #define CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC (1 << 6) | ||
118 | #define CCDC_CCDCFG_WENLOG_AND 0 | ||
119 | #define CCDC_CCDCFG_TRGSEL_WEN 0 | ||
120 | #define CCDC_CCDCFG_EXTRG_DISABLE 0 | ||
121 | #define CCDC_CFA_MOSAIC 0 | ||
122 | #define CCDC_Y8POS_SHIFT 11 | ||
123 | |||
124 | #define CCDC_VDC_DFCVSAT_MASK 0x3fff | ||
125 | #define CCDC_DATAOFST_MASK 0x0ff | ||
126 | #define CCDC_DATAOFST_H_SHIFT 0 | ||
127 | #define CCDC_DATAOFST_V_SHIFT 8 | ||
128 | #define CCDC_GAMMAWD_CFA_MASK 1 | ||
129 | #define CCDC_GAMMAWD_CFA_SHIFT 5 | ||
130 | #define CCDC_GAMMAWD_INPUT_SHIFT 2 | ||
131 | #define CCDC_FID_POL_MASK 1 | ||
132 | #define CCDC_FID_POL_SHIFT 4 | ||
133 | #define CCDC_HD_POL_MASK 1 | ||
134 | #define CCDC_HD_POL_SHIFT 3 | ||
135 | #define CCDC_VD_POL_MASK 1 | ||
136 | #define CCDC_VD_POL_SHIFT 2 | ||
137 | #define CCDC_VD_POL_NEGATIVE (1 << 2) | ||
138 | #define CCDC_FRM_FMT_MASK 1 | ||
139 | #define CCDC_FRM_FMT_SHIFT 7 | ||
140 | #define CCDC_DATA_SZ_MASK 7 | ||
141 | #define CCDC_DATA_SZ_SHIFT 8 | ||
142 | #define CCDC_VDHDOUT_MASK 1 | ||
143 | #define CCDC_VDHDOUT_SHIFT 0 | ||
144 | #define CCDC_EXWEN_MASK 1 | ||
145 | #define CCDC_EXWEN_SHIFT 5 | ||
146 | #define CCDC_INPUT_MODE_MASK 3 | ||
147 | #define CCDC_INPUT_MODE_SHIFT 12 | ||
148 | #define CCDC_PIX_FMT_MASK 3 | ||
149 | #define CCDC_PIX_FMT_SHIFT 12 | ||
150 | #define CCDC_DATAPOL_MASK 1 | ||
151 | #define CCDC_DATAPOL_SHIFT 6 | ||
152 | #define CCDC_WEN_ENABLE (1 << 1) | ||
153 | #define CCDC_VDHDEN_ENABLE (1 << 16) | ||
154 | #define CCDC_LPF_ENABLE (1 << 14) | ||
155 | #define CCDC_ALAW_ENABLE 1 | ||
156 | #define CCDC_ALAW_GAMA_WD_MASK 7 | ||
157 | #define CCDC_REC656IF_BT656_EN 3 | ||
158 | |||
159 | #define CCDC_FMTCFG_FMTMODE_MASK 3 | ||
160 | #define CCDC_FMTCFG_FMTMODE_SHIFT 1 | ||
161 | #define CCDC_FMTCFG_LNUM_MASK 3 | ||
162 | #define CCDC_FMTCFG_LNUM_SHIFT 4 | ||
163 | #define CCDC_FMTCFG_ADDRINC_MASK 7 | ||
164 | #define CCDC_FMTCFG_ADDRINC_SHIFT 8 | ||
165 | |||
166 | #define CCDC_CCDCFG_FIDMD_SHIFT 6 | ||
167 | #define CCDC_CCDCFG_WENLOG_SHIFT 8 | ||
168 | #define CCDC_CCDCFG_TRGSEL_SHIFT 9 | ||
169 | #define CCDC_CCDCFG_EXTRG_SHIFT 10 | ||
170 | #define CCDC_CCDCFG_MSBINVI_SHIFT 13 | ||
171 | |||
172 | #define CCDC_HSIZE_FLIP_SHIFT 12 | ||
173 | #define CCDC_HSIZE_FLIP_MASK 1 | ||
174 | #define CCDC_HSIZE_VAL_MASK 0xFFF | ||
175 | #define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 | ||
176 | #define CCDC_SDOFST_INTERLACE_INVERSE 0x4B6D | ||
177 | #define CCDC_SDOFST_INTERLACE_NORMAL 0x0B6D | ||
178 | #define CCDC_SDOFST_PROGRESSIVE_INVERSE 0x4000 | ||
179 | #define CCDC_SDOFST_PROGRESSIVE_NORMAL 0 | ||
180 | #define CCDC_START_PX_HOR_MASK 0x7FFF | ||
181 | #define CCDC_NUM_PX_HOR_MASK 0x7FFF | ||
182 | #define CCDC_START_VER_ONE_MASK 0x7FFF | ||
183 | #define CCDC_START_VER_TWO_MASK 0x7FFF | ||
184 | #define CCDC_NUM_LINES_VER 0x7FFF | ||
185 | |||
186 | #define CCDC_BLK_CLAMP_ENABLE (1 << 15) | ||
187 | #define CCDC_BLK_SGAIN_MASK 0x1F | ||
188 | #define CCDC_BLK_ST_PXL_MASK 0x1FFF | ||
189 | #define CCDC_BLK_SAMPLE_LN_MASK 3 | ||
190 | #define CCDC_BLK_SAMPLE_LN_SHIFT 13 | ||
191 | |||
192 | #define CCDC_NUM_LINE_CALC_MASK 3 | ||
193 | #define CCDC_NUM_LINE_CALC_SHIFT 14 | ||
194 | |||
195 | #define CCDC_BLK_DC_SUB_MASK 0x3FFF | ||
196 | #define CCDC_BLK_COMP_MASK 0xFF | ||
197 | #define CCDC_BLK_COMP_GB_COMP_SHIFT 8 | ||
198 | #define CCDC_BLK_COMP_GR_COMP_SHIFT 0 | ||
199 | #define CCDC_BLK_COMP_R_COMP_SHIFT 8 | ||
200 | #define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) | ||
201 | #define CCDC_LATCH_ON_VSYNC_ENABLE (0 << 15) | ||
202 | #define CCDC_FPC_ENABLE (1 << 15) | ||
203 | #define CCDC_FPC_FPC_NUM_MASK 0x7FFF | ||
204 | #define CCDC_DATA_PACK_ENABLE (1 << 11) | ||
205 | #define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF | ||
206 | #define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF | ||
207 | #define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 | ||
208 | #define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF | ||
209 | #define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF | ||
210 | #define CCDC_FMT_VERT_FMTSLV_SHIFT 16 | ||
211 | #define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF | ||
212 | #define CCDC_VP_OUT_VERT_NUM_SHIFT 17 | ||
213 | #define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF | ||
214 | #define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 | ||
215 | #define CCDC_VP_OUT_HORZ_ST_MASK 0xF | ||
216 | |||
217 | #define CCDC_CSC_COEF_INTEG_MASK 7 | ||
218 | #define CCDC_CSC_COEF_DECIMAL_MASK 0x1f | ||
219 | #define CCDC_CSC_COEF_INTEG_SHIFT 5 | ||
220 | #define CCDC_CSCM_MSB_SHIFT 8 | ||
221 | #define CCDC_CSC_ENABLE 1 | ||
222 | #define CCDC_CSC_DEC_MAX 32 | ||
223 | |||
224 | #define CCDC_MFILT1_SHIFT 10 | ||
225 | #define CCDC_MFILT2_SHIFT 8 | ||
226 | #define CCDC_MED_FILT_THRESH 0x3FFF | ||
227 | #define CCDC_LPF_MASK 1 | ||
228 | #define CCDC_LPF_SHIFT 14 | ||
229 | #define CCDC_OFFSET_MASK 0x3FF | ||
230 | #define CCDC_DATASFT_MASK 7 | ||
231 | #define CCDC_DATASFT_SHIFT 8 | ||
232 | |||
233 | #define CCDC_DF_ENABLE 1 | ||
234 | |||
235 | #define CCDC_FMTPLEN_P0_MASK 0xF | ||
236 | #define CCDC_FMTPLEN_P1_MASK 0xF | ||
237 | #define CCDC_FMTPLEN_P2_MASK 7 | ||
238 | #define CCDC_FMTPLEN_P3_MASK 7 | ||
239 | #define CCDC_FMTPLEN_P0_SHIFT 0 | ||
240 | #define CCDC_FMTPLEN_P1_SHIFT 4 | ||
241 | #define CCDC_FMTPLEN_P2_SHIFT 8 | ||
242 | #define CCDC_FMTPLEN_P3_SHIFT 12 | ||
243 | |||
244 | #define CCDC_FMTSPH_MASK 0x1FFF | ||
245 | #define CCDC_FMTLNH_MASK 0x1FFF | ||
246 | #define CCDC_FMTSLV_MASK 0x1FFF | ||
247 | #define CCDC_FMTLNV_MASK 0x7FFF | ||
248 | #define CCDC_FMTRLEN_MASK 0x1FFF | ||
249 | #define CCDC_FMTHCNT_MASK 0x1FFF | ||
250 | |||
251 | #define CCDC_ADP_INIT_MASK 0x1FFF | ||
252 | #define CCDC_ADP_LINE_SHIFT 13 | ||
253 | #define CCDC_ADP_LINE_MASK 3 | ||
254 | #define CCDC_FMTPGN_APTR_MASK 7 | ||
255 | |||
256 | #define CCDC_DFCCTL_GDFCEN_MASK 1 | ||
257 | #define CCDC_DFCCTL_VDFCEN_MASK 1 | ||
258 | #define CCDC_DFCCTL_VDFC_DISABLE (0 << 4) | ||
259 | #define CCDC_DFCCTL_VDFCEN_SHIFT 4 | ||
260 | #define CCDC_DFCCTL_VDFCSL_MASK 3 | ||
261 | #define CCDC_DFCCTL_VDFCSL_SHIFT 5 | ||
262 | #define CCDC_DFCCTL_VDFCUDA_MASK 1 | ||
263 | #define CCDC_DFCCTL_VDFCUDA_SHIFT 7 | ||
264 | #define CCDC_DFCCTL_VDFLSFT_MASK 3 | ||
265 | #define CCDC_DFCCTL_VDFLSFT_SHIFT 8 | ||
266 | #define CCDC_DFCMEMCTL_DFCMARST_MASK 1 | ||
267 | #define CCDC_DFCMEMCTL_DFCMARST_SHIFT 2 | ||
268 | #define CCDC_DFCMEMCTL_DFCMWR_MASK 1 | ||
269 | #define CCDC_DFCMEMCTL_DFCMWR_SHIFT 0 | ||
270 | #define CCDC_DFCMEMCTL_INC_ADDR (0 << 2) | ||
271 | |||
272 | #define CCDC_LSCCFG_GFTSF_MASK 7 | ||
273 | #define CCDC_LSCCFG_GFTSF_SHIFT 1 | ||
274 | #define CCDC_LSCCFG_GFTINV_MASK 0xf | ||
275 | #define CCDC_LSCCFG_GFTINV_SHIFT 4 | ||
276 | #define CCDC_LSC_GFTABLE_SEL_MASK 3 | ||
277 | #define CCDC_LSC_GFTABLE_EPEL_SHIFT 8 | ||
278 | #define CCDC_LSC_GFTABLE_OPEL_SHIFT 10 | ||
279 | #define CCDC_LSC_GFTABLE_EPOL_SHIFT 12 | ||
280 | #define CCDC_LSC_GFTABLE_OPOL_SHIFT 14 | ||
281 | #define CCDC_LSC_GFMODE_MASK 3 | ||
282 | #define CCDC_LSC_GFMODE_SHIFT 4 | ||
283 | #define CCDC_LSC_DISABLE 0 | ||
284 | #define CCDC_LSC_ENABLE 1 | ||
285 | #define CCDC_LSC_TABLE1_SLC 0 | ||
286 | #define CCDC_LSC_TABLE2_SLC 1 | ||
287 | #define CCDC_LSC_TABLE3_SLC 2 | ||
288 | #define CCDC_LSC_MEMADDR_RESET (1 << 2) | ||
289 | #define CCDC_LSC_MEMADDR_INCR (0 << 2) | ||
290 | #define CCDC_LSC_FRAC_MASK_T1 0xFF | ||
291 | #define CCDC_LSC_INT_MASK 3 | ||
292 | #define CCDC_LSC_FRAC_MASK 0x3FFF | ||
293 | #define CCDC_LSC_CENTRE_MASK 0x3FFF | ||
294 | #define CCDC_LSC_COEF_MASK 0xff | ||
295 | #define CCDC_LSC_COEFL_SHIFT 0 | ||
296 | #define CCDC_LSC_COEFU_SHIFT 8 | ||
297 | #define CCDC_GAIN_MASK 0x7FF | ||
298 | #define CCDC_SYNCEN_VDHDEN_MASK (1 << 0) | ||
299 | #define CCDC_SYNCEN_WEN_MASK (1 << 1) | ||
300 | #define CCDC_SYNCEN_WEN_SHIFT 1 | ||
301 | |||
302 | /* Power on Defaults in hardware */ | ||
303 | #define MODESET_DEFAULT 0x200 | ||
304 | #define CULH_DEFAULT 0xFFFF | ||
305 | #define CULV_DEFAULT 0xFF | ||
306 | #define GAIN_DEFAULT 256 | ||
307 | #define OUTCLIP_DEFAULT 0x3FFF | ||
308 | #define LSCCFG2_DEFAULT 0xE | ||
309 | |||
310 | #endif | ||
diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c new file mode 100644 index 00000000000..c8b32c1c738 --- /dev/null +++ b/drivers/media/video/davinci/dm644x_ccdc.c | |||
@@ -0,0 +1,1091 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * CCDC hardware module for DM6446 | ||
19 | * ------------------------------ | ||
20 | * | ||
21 | * This module is for configuring CCD controller of DM6446 VPFE to capture | ||
22 | * Raw yuv or Bayer RGB data from a decoder. CCDC has several modules | ||
23 | * such as Defect Pixel Correction, Color Space Conversion etc to | ||
24 | * pre-process the Raw Bayer RGB data, before writing it to SDRAM. This | ||
25 | * module also allows application to configure individual | ||
26 | * module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL. | ||
27 | * To do so, application includes dm644x_ccdc.h and vpfe_capture.h header | ||
28 | * files. The setparams() API is called by vpfe_capture driver | ||
29 | * to configure module parameters. This file is named DM644x so that other | ||
30 | * variants such DM6443 may be supported using the same module. | ||
31 | * | ||
32 | * TODO: Test Raw bayer parameter settings and bayer capture | ||
33 | * Split module parameter structure to module specific ioctl structs | ||
34 | * investigate if enum used for user space type definition | ||
35 | * to be replaced by #defines or integer | ||
36 | */ | ||
37 | #include <linux/platform_device.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | #include <linux/videodev2.h> | ||
40 | #include <linux/gfp.h> | ||
41 | #include <linux/clk.h> | ||
42 | #include <linux/err.h> | ||
43 | |||
44 | #include <media/davinci/dm644x_ccdc.h> | ||
45 | #include <media/davinci/vpss.h> | ||
46 | |||
47 | #include "dm644x_ccdc_regs.h" | ||
48 | #include "ccdc_hw_device.h" | ||
49 | |||
50 | MODULE_LICENSE("GPL"); | ||
51 | MODULE_DESCRIPTION("CCDC Driver for DM6446"); | ||
52 | MODULE_AUTHOR("Texas Instruments"); | ||
53 | |||
54 | static struct ccdc_oper_config { | ||
55 | struct device *dev; | ||
56 | /* CCDC interface type */ | ||
57 | enum vpfe_hw_if_type if_type; | ||
58 | /* Raw Bayer configuration */ | ||
59 | struct ccdc_params_raw bayer; | ||
60 | /* YCbCr configuration */ | ||
61 | struct ccdc_params_ycbcr ycbcr; | ||
62 | /* Master clock */ | ||
63 | struct clk *mclk; | ||
64 | /* slave clock */ | ||
65 | struct clk *sclk; | ||
66 | /* ccdc base address */ | ||
67 | void __iomem *base_addr; | ||
68 | } ccdc_cfg = { | ||
69 | /* Raw configurations */ | ||
70 | .bayer = { | ||
71 | .pix_fmt = CCDC_PIXFMT_RAW, | ||
72 | .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, | ||
73 | .win = CCDC_WIN_VGA, | ||
74 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
75 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
76 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
77 | .config_params = { | ||
78 | .data_sz = CCDC_DATA_10BITS, | ||
79 | }, | ||
80 | }, | ||
81 | .ycbcr = { | ||
82 | .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, | ||
83 | .frm_fmt = CCDC_FRMFMT_INTERLACED, | ||
84 | .win = CCDC_WIN_PAL, | ||
85 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
86 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
87 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
88 | .bt656_enable = 1, | ||
89 | .pix_order = CCDC_PIXORDER_CBYCRY, | ||
90 | .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED | ||
91 | }, | ||
92 | }; | ||
93 | |||
94 | #define CCDC_MAX_RAW_YUV_FORMATS 2 | ||
95 | |||
96 | /* Raw Bayer formats */ | ||
97 | static u32 ccdc_raw_bayer_pix_formats[] = | ||
98 | {V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; | ||
99 | |||
100 | /* Raw YUV formats */ | ||
101 | static u32 ccdc_raw_yuv_pix_formats[] = | ||
102 | {V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; | ||
103 | |||
104 | /* CCDC Save/Restore context */ | ||
105 | static u32 ccdc_ctx[CCDC_REG_END / sizeof(u32)]; | ||
106 | |||
107 | /* register access routines */ | ||
108 | static inline u32 regr(u32 offset) | ||
109 | { | ||
110 | return __raw_readl(ccdc_cfg.base_addr + offset); | ||
111 | } | ||
112 | |||
113 | static inline void regw(u32 val, u32 offset) | ||
114 | { | ||
115 | __raw_writel(val, ccdc_cfg.base_addr + offset); | ||
116 | } | ||
117 | |||
118 | static void ccdc_enable(int flag) | ||
119 | { | ||
120 | regw(flag, CCDC_PCR); | ||
121 | } | ||
122 | |||
123 | static void ccdc_enable_vport(int flag) | ||
124 | { | ||
125 | if (flag) | ||
126 | /* enable video port */ | ||
127 | regw(CCDC_ENABLE_VIDEO_PORT, CCDC_FMTCFG); | ||
128 | else | ||
129 | regw(CCDC_DISABLE_VIDEO_PORT, CCDC_FMTCFG); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * ccdc_setwin() | ||
134 | * This function will configure the window size | ||
135 | * to be capture in CCDC reg | ||
136 | */ | ||
137 | void ccdc_setwin(struct v4l2_rect *image_win, | ||
138 | enum ccdc_frmfmt frm_fmt, | ||
139 | int ppc) | ||
140 | { | ||
141 | int horz_start, horz_nr_pixels; | ||
142 | int vert_start, vert_nr_lines; | ||
143 | int val = 0, mid_img = 0; | ||
144 | |||
145 | dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin..."); | ||
146 | /* | ||
147 | * ppc - per pixel count. indicates how many pixels per cell | ||
148 | * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. | ||
149 | * raw capture this is 1 | ||
150 | */ | ||
151 | horz_start = image_win->left << (ppc - 1); | ||
152 | horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; | ||
153 | regw((horz_start << CCDC_HORZ_INFO_SPH_SHIFT) | horz_nr_pixels, | ||
154 | CCDC_HORZ_INFO); | ||
155 | |||
156 | vert_start = image_win->top; | ||
157 | |||
158 | if (frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
159 | vert_nr_lines = (image_win->height >> 1) - 1; | ||
160 | vert_start >>= 1; | ||
161 | /* Since first line doesn't have any data */ | ||
162 | vert_start += 1; | ||
163 | /* configure VDINT0 */ | ||
164 | val = (vert_start << CCDC_VDINT_VDINT0_SHIFT); | ||
165 | regw(val, CCDC_VDINT); | ||
166 | |||
167 | } else { | ||
168 | /* Since first line doesn't have any data */ | ||
169 | vert_start += 1; | ||
170 | vert_nr_lines = image_win->height - 1; | ||
171 | /* | ||
172 | * configure VDINT0 and VDINT1. VDINT1 will be at half | ||
173 | * of image height | ||
174 | */ | ||
175 | mid_img = vert_start + (image_win->height / 2); | ||
176 | val = (vert_start << CCDC_VDINT_VDINT0_SHIFT) | | ||
177 | (mid_img & CCDC_VDINT_VDINT1_MASK); | ||
178 | regw(val, CCDC_VDINT); | ||
179 | |||
180 | } | ||
181 | regw((vert_start << CCDC_VERT_START_SLV0_SHIFT) | vert_start, | ||
182 | CCDC_VERT_START); | ||
183 | regw(vert_nr_lines, CCDC_VERT_LINES); | ||
184 | dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin..."); | ||
185 | } | ||
186 | |||
187 | static void ccdc_readregs(void) | ||
188 | { | ||
189 | unsigned int val = 0; | ||
190 | |||
191 | val = regr(CCDC_ALAW); | ||
192 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to ALAW...\n", val); | ||
193 | val = regr(CCDC_CLAMP); | ||
194 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to CLAMP...\n", val); | ||
195 | val = regr(CCDC_DCSUB); | ||
196 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to DCSUB...\n", val); | ||
197 | val = regr(CCDC_BLKCMP); | ||
198 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to BLKCMP...\n", val); | ||
199 | val = regr(CCDC_FPC_ADDR); | ||
200 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC_ADDR...\n", val); | ||
201 | val = regr(CCDC_FPC); | ||
202 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FPC...\n", val); | ||
203 | val = regr(CCDC_FMTCFG); | ||
204 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMTCFG...\n", val); | ||
205 | val = regr(CCDC_COLPTN); | ||
206 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to COLPTN...\n", val); | ||
207 | val = regr(CCDC_FMT_HORZ); | ||
208 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_HORZ...\n", val); | ||
209 | val = regr(CCDC_FMT_VERT); | ||
210 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to FMT_VERT...\n", val); | ||
211 | val = regr(CCDC_HSIZE_OFF); | ||
212 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HSIZE_OFF...\n", val); | ||
213 | val = regr(CCDC_SDOFST); | ||
214 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SDOFST...\n", val); | ||
215 | val = regr(CCDC_VP_OUT); | ||
216 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VP_OUT...\n", val); | ||
217 | val = regr(CCDC_SYN_MODE); | ||
218 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to SYN_MODE...\n", val); | ||
219 | val = regr(CCDC_HORZ_INFO); | ||
220 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to HORZ_INFO...\n", val); | ||
221 | val = regr(CCDC_VERT_START); | ||
222 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_START...\n", val); | ||
223 | val = regr(CCDC_VERT_LINES); | ||
224 | dev_notice(ccdc_cfg.dev, "\nReading 0x%x to VERT_LINES...\n", val); | ||
225 | } | ||
226 | |||
227 | static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) | ||
228 | { | ||
229 | if (ccdcparam->alaw.enable) { | ||
230 | if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || | ||
231 | (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || | ||
232 | (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { | ||
233 | dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); | ||
234 | return -1; | ||
235 | } | ||
236 | } | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) | ||
241 | { | ||
242 | struct ccdc_config_params_raw *config_params = | ||
243 | &ccdc_cfg.bayer.config_params; | ||
244 | unsigned int *fpc_virtaddr = NULL; | ||
245 | unsigned int *fpc_physaddr = NULL; | ||
246 | |||
247 | memcpy(config_params, raw_params, sizeof(*raw_params)); | ||
248 | /* | ||
249 | * allocate memory for fault pixel table and copy the user | ||
250 | * values to the table | ||
251 | */ | ||
252 | if (!config_params->fault_pxl.enable) | ||
253 | return 0; | ||
254 | |||
255 | fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; | ||
256 | fpc_virtaddr = (unsigned int *)phys_to_virt( | ||
257 | (unsigned long)fpc_physaddr); | ||
258 | /* | ||
259 | * Allocate memory for FPC table if current | ||
260 | * FPC table buffer is not big enough to | ||
261 | * accommodate FPC Number requested | ||
262 | */ | ||
263 | if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) { | ||
264 | if (fpc_physaddr != NULL) { | ||
265 | free_pages((unsigned long)fpc_physaddr, | ||
266 | get_order | ||
267 | (config_params->fault_pxl.fp_num * | ||
268 | FP_NUM_BYTES)); | ||
269 | } | ||
270 | |||
271 | /* Allocate memory for FPC table */ | ||
272 | fpc_virtaddr = | ||
273 | (unsigned int *)__get_free_pages(GFP_KERNEL | GFP_DMA, | ||
274 | get_order(raw_params-> | ||
275 | fault_pxl.fp_num * | ||
276 | FP_NUM_BYTES)); | ||
277 | |||
278 | if (fpc_virtaddr == NULL) { | ||
279 | dev_dbg(ccdc_cfg.dev, | ||
280 | "\nUnable to allocate memory for FPC"); | ||
281 | return -EFAULT; | ||
282 | } | ||
283 | fpc_physaddr = | ||
284 | (unsigned int *)virt_to_phys((void *)fpc_virtaddr); | ||
285 | } | ||
286 | |||
287 | /* Copy number of fault pixels and FPC table */ | ||
288 | config_params->fault_pxl.fp_num = raw_params->fault_pxl.fp_num; | ||
289 | if (copy_from_user(fpc_virtaddr, | ||
290 | (void __user *)raw_params->fault_pxl.fpc_table_addr, | ||
291 | config_params->fault_pxl.fp_num * FP_NUM_BYTES)) { | ||
292 | dev_dbg(ccdc_cfg.dev, "\n copy_from_user failed"); | ||
293 | return -EFAULT; | ||
294 | } | ||
295 | config_params->fault_pxl.fpc_table_addr = (unsigned int)fpc_physaddr; | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int ccdc_close(struct device *dev) | ||
300 | { | ||
301 | struct ccdc_config_params_raw *config_params = | ||
302 | &ccdc_cfg.bayer.config_params; | ||
303 | unsigned int *fpc_physaddr = NULL, *fpc_virtaddr = NULL; | ||
304 | |||
305 | fpc_physaddr = (unsigned int *)config_params->fault_pxl.fpc_table_addr; | ||
306 | |||
307 | if (fpc_physaddr != NULL) { | ||
308 | fpc_virtaddr = (unsigned int *) | ||
309 | phys_to_virt((unsigned long)fpc_physaddr); | ||
310 | free_pages((unsigned long)fpc_virtaddr, | ||
311 | get_order(config_params->fault_pxl.fp_num * | ||
312 | FP_NUM_BYTES)); | ||
313 | } | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * ccdc_restore_defaults() | ||
319 | * This function will write defaults to all CCDC registers | ||
320 | */ | ||
321 | static void ccdc_restore_defaults(void) | ||
322 | { | ||
323 | int i; | ||
324 | |||
325 | /* disable CCDC */ | ||
326 | ccdc_enable(0); | ||
327 | /* set all registers to default value */ | ||
328 | for (i = 4; i <= 0x94; i += 4) | ||
329 | regw(0, i); | ||
330 | regw(CCDC_NO_CULLING, CCDC_CULLING); | ||
331 | regw(CCDC_GAMMA_BITS_11_2, CCDC_ALAW); | ||
332 | } | ||
333 | |||
334 | static int ccdc_open(struct device *device) | ||
335 | { | ||
336 | ccdc_restore_defaults(); | ||
337 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
338 | ccdc_enable_vport(1); | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static void ccdc_sbl_reset(void) | ||
343 | { | ||
344 | vpss_clear_wbl_overflow(VPSS_PCR_CCDC_WBL_O); | ||
345 | } | ||
346 | |||
347 | /* Parameter operations */ | ||
348 | static int ccdc_set_params(void __user *params) | ||
349 | { | ||
350 | struct ccdc_config_params_raw ccdc_raw_params; | ||
351 | int x; | ||
352 | |||
353 | if (ccdc_cfg.if_type != VPFE_RAW_BAYER) | ||
354 | return -EINVAL; | ||
355 | |||
356 | x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); | ||
357 | if (x) { | ||
358 | dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying" | ||
359 | "ccdc params, %d\n", x); | ||
360 | return -EFAULT; | ||
361 | } | ||
362 | |||
363 | if (!validate_ccdc_param(&ccdc_raw_params)) { | ||
364 | if (!ccdc_update_raw_params(&ccdc_raw_params)) | ||
365 | return 0; | ||
366 | } | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * ccdc_config_ycbcr() | ||
372 | * This function will configure CCDC for YCbCr video capture | ||
373 | */ | ||
374 | void ccdc_config_ycbcr(void) | ||
375 | { | ||
376 | struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr; | ||
377 | u32 syn_mode; | ||
378 | |||
379 | dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr..."); | ||
380 | /* | ||
381 | * first restore the CCDC registers to default values | ||
382 | * This is important since we assume default values to be set in | ||
383 | * a lot of registers that we didn't touch | ||
384 | */ | ||
385 | ccdc_restore_defaults(); | ||
386 | |||
387 | /* | ||
388 | * configure pixel format, frame format, configure video frame | ||
389 | * format, enable output to SDRAM, enable internal timing generator | ||
390 | * and 8bit pack mode | ||
391 | */ | ||
392 | syn_mode = (((params->pix_fmt & CCDC_SYN_MODE_INPMOD_MASK) << | ||
393 | CCDC_SYN_MODE_INPMOD_SHIFT) | | ||
394 | ((params->frm_fmt & CCDC_SYN_FLDMODE_MASK) << | ||
395 | CCDC_SYN_FLDMODE_SHIFT) | CCDC_VDHDEN_ENABLE | | ||
396 | CCDC_WEN_ENABLE | CCDC_DATA_PACK_ENABLE); | ||
397 | |||
398 | /* setup BT.656 sync mode */ | ||
399 | if (params->bt656_enable) { | ||
400 | regw(CCDC_REC656IF_BT656_EN, CCDC_REC656IF); | ||
401 | |||
402 | /* | ||
403 | * configure the FID, VD, HD pin polarity, | ||
404 | * fld,hd pol positive, vd negative, 8-bit data | ||
405 | */ | ||
406 | syn_mode |= CCDC_SYN_MODE_VD_POL_NEGATIVE; | ||
407 | if (ccdc_cfg.if_type == VPFE_BT656_10BIT) | ||
408 | syn_mode |= CCDC_SYN_MODE_10BITS; | ||
409 | else | ||
410 | syn_mode |= CCDC_SYN_MODE_8BITS; | ||
411 | } else { | ||
412 | /* y/c external sync mode */ | ||
413 | syn_mode |= (((params->fid_pol & CCDC_FID_POL_MASK) << | ||
414 | CCDC_FID_POL_SHIFT) | | ||
415 | ((params->hd_pol & CCDC_HD_POL_MASK) << | ||
416 | CCDC_HD_POL_SHIFT) | | ||
417 | ((params->vd_pol & CCDC_VD_POL_MASK) << | ||
418 | CCDC_VD_POL_SHIFT)); | ||
419 | } | ||
420 | regw(syn_mode, CCDC_SYN_MODE); | ||
421 | |||
422 | /* configure video window */ | ||
423 | ccdc_setwin(¶ms->win, params->frm_fmt, 2); | ||
424 | |||
425 | /* | ||
426 | * configure the order of y cb cr in SDRAM, and disable latch | ||
427 | * internal register on vsync | ||
428 | */ | ||
429 | if (ccdc_cfg.if_type == VPFE_BT656_10BIT) | ||
430 | regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | | ||
431 | CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_BW656_10BIT, | ||
432 | CCDC_CCDCFG); | ||
433 | else | ||
434 | regw((params->pix_order << CCDC_CCDCFG_Y8POS_SHIFT) | | ||
435 | CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); | ||
436 | |||
437 | /* | ||
438 | * configure the horizontal line offset. This should be a | ||
439 | * on 32 byte boundary. So clear LSB 5 bits | ||
440 | */ | ||
441 | regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); | ||
442 | |||
443 | /* configure the memory line offset */ | ||
444 | if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) | ||
445 | /* two fields are interleaved in memory */ | ||
446 | regw(CCDC_SDOFST_FIELD_INTERLEAVED, CCDC_SDOFST); | ||
447 | |||
448 | ccdc_sbl_reset(); | ||
449 | dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n"); | ||
450 | } | ||
451 | |||
452 | static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp) | ||
453 | { | ||
454 | u32 val; | ||
455 | |||
456 | if (!bclamp->enable) { | ||
457 | /* configure DCSub */ | ||
458 | val = (bclamp->dc_sub) & CCDC_BLK_DC_SUB_MASK; | ||
459 | regw(val, CCDC_DCSUB); | ||
460 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to DCSUB...\n", val); | ||
461 | regw(CCDC_CLAMP_DEFAULT_VAL, CCDC_CLAMP); | ||
462 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to CLAMP...\n"); | ||
463 | return; | ||
464 | } | ||
465 | /* | ||
466 | * Configure gain, Start pixel, No of line to be avg, | ||
467 | * No of pixel/line to be avg, & Enable the Black clamping | ||
468 | */ | ||
469 | val = ((bclamp->sgain & CCDC_BLK_SGAIN_MASK) | | ||
470 | ((bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) << | ||
471 | CCDC_BLK_ST_PXL_SHIFT) | | ||
472 | ((bclamp->sample_ln & CCDC_BLK_SAMPLE_LINE_MASK) << | ||
473 | CCDC_BLK_SAMPLE_LINE_SHIFT) | | ||
474 | ((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) << | ||
475 | CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE); | ||
476 | regw(val, CCDC_CLAMP); | ||
477 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to CLAMP...\n", val); | ||
478 | /* If Black clamping is enable then make dcsub 0 */ | ||
479 | regw(CCDC_DCSUB_DEFAULT_VAL, CCDC_DCSUB); | ||
480 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x00000000 to DCSUB...\n"); | ||
481 | } | ||
482 | |||
483 | static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp) | ||
484 | { | ||
485 | u32 val; | ||
486 | |||
487 | val = ((bcomp->b & CCDC_BLK_COMP_MASK) | | ||
488 | ((bcomp->gb & CCDC_BLK_COMP_MASK) << | ||
489 | CCDC_BLK_COMP_GB_COMP_SHIFT) | | ||
490 | ((bcomp->gr & CCDC_BLK_COMP_MASK) << | ||
491 | CCDC_BLK_COMP_GR_COMP_SHIFT) | | ||
492 | ((bcomp->r & CCDC_BLK_COMP_MASK) << | ||
493 | CCDC_BLK_COMP_R_COMP_SHIFT)); | ||
494 | regw(val, CCDC_BLKCMP); | ||
495 | } | ||
496 | |||
497 | static void ccdc_config_fpc(struct ccdc_fault_pixel *fpc) | ||
498 | { | ||
499 | u32 val; | ||
500 | |||
501 | /* Initially disable FPC */ | ||
502 | val = CCDC_FPC_DISABLE; | ||
503 | regw(val, CCDC_FPC); | ||
504 | |||
505 | if (!fpc->enable) | ||
506 | return; | ||
507 | |||
508 | /* Configure Fault pixel if needed */ | ||
509 | regw(fpc->fpc_table_addr, CCDC_FPC_ADDR); | ||
510 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC_ADDR...\n", | ||
511 | (fpc->fpc_table_addr)); | ||
512 | /* Write the FPC params with FPC disable */ | ||
513 | val = fpc->fp_num & CCDC_FPC_FPC_NUM_MASK; | ||
514 | regw(val, CCDC_FPC); | ||
515 | |||
516 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); | ||
517 | /* read the FPC register */ | ||
518 | val = regr(CCDC_FPC) | CCDC_FPC_ENABLE; | ||
519 | regw(val, CCDC_FPC); | ||
520 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FPC...\n", val); | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * ccdc_config_raw() | ||
525 | * This function will configure CCDC for Raw capture mode | ||
526 | */ | ||
527 | void ccdc_config_raw(void) | ||
528 | { | ||
529 | struct ccdc_params_raw *params = &ccdc_cfg.bayer; | ||
530 | struct ccdc_config_params_raw *config_params = | ||
531 | &ccdc_cfg.bayer.config_params; | ||
532 | unsigned int syn_mode = 0; | ||
533 | unsigned int val; | ||
534 | |||
535 | dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw..."); | ||
536 | |||
537 | /* Reset CCDC */ | ||
538 | ccdc_restore_defaults(); | ||
539 | |||
540 | /* Disable latching function registers on VSYNC */ | ||
541 | regw(CCDC_LATCH_ON_VSYNC_DISABLE, CCDC_CCDCFG); | ||
542 | |||
543 | /* | ||
544 | * Configure the vertical sync polarity(SYN_MODE.VDPOL), | ||
545 | * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity | ||
546 | * (SYN_MODE.FLDPOL), frame format(progressive or interlace), | ||
547 | * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output | ||
548 | * SDRAM, enable internal timing generator | ||
549 | */ | ||
550 | syn_mode = | ||
551 | (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) | | ||
552 | ((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) | | ||
553 | ((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) | | ||
554 | ((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) | | ||
555 | ((config_params->data_sz & CCDC_DATA_SZ_MASK) << | ||
556 | CCDC_DATA_SZ_SHIFT) | | ||
557 | ((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT) | | ||
558 | CCDC_WEN_ENABLE | CCDC_VDHDEN_ENABLE); | ||
559 | |||
560 | /* Enable and configure aLaw register if needed */ | ||
561 | if (config_params->alaw.enable) { | ||
562 | val = ((config_params->alaw.gama_wd & | ||
563 | CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); | ||
564 | regw(val, CCDC_ALAW); | ||
565 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); | ||
566 | } | ||
567 | |||
568 | /* Configure video window */ | ||
569 | ccdc_setwin(¶ms->win, params->frm_fmt, CCDC_PPC_RAW); | ||
570 | |||
571 | /* Configure Black Clamp */ | ||
572 | ccdc_config_black_clamp(&config_params->blk_clamp); | ||
573 | |||
574 | /* Configure Black level compensation */ | ||
575 | ccdc_config_black_compense(&config_params->blk_comp); | ||
576 | |||
577 | /* Configure Fault Pixel Correction */ | ||
578 | ccdc_config_fpc(&config_params->fault_pxl); | ||
579 | |||
580 | /* If data size is 8 bit then pack the data */ | ||
581 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
582 | config_params->alaw.enable) | ||
583 | syn_mode |= CCDC_DATA_PACK_ENABLE; | ||
584 | |||
585 | #ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE | ||
586 | /* enable video port */ | ||
587 | val = CCDC_ENABLE_VIDEO_PORT; | ||
588 | #else | ||
589 | /* disable video port */ | ||
590 | val = CCDC_DISABLE_VIDEO_PORT; | ||
591 | #endif | ||
592 | |||
593 | if (config_params->data_sz == CCDC_DATA_8BITS) | ||
594 | val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK) | ||
595 | << CCDC_FMTCFG_VPIN_SHIFT; | ||
596 | else | ||
597 | val |= (config_params->data_sz & CCDC_FMTCFG_VPIN_MASK) | ||
598 | << CCDC_FMTCFG_VPIN_SHIFT; | ||
599 | /* Write value in FMTCFG */ | ||
600 | regw(val, CCDC_FMTCFG); | ||
601 | |||
602 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMTCFG...\n", val); | ||
603 | /* Configure the color pattern according to mt9t001 sensor */ | ||
604 | regw(CCDC_COLPTN_VAL, CCDC_COLPTN); | ||
605 | |||
606 | dev_dbg(ccdc_cfg.dev, "\nWriting 0xBB11BB11 to COLPTN...\n"); | ||
607 | /* | ||
608 | * Configure Data formatter(Video port) pixel selection | ||
609 | * (FMT_HORZ, FMT_VERT) | ||
610 | */ | ||
611 | val = ((params->win.left & CCDC_FMT_HORZ_FMTSPH_MASK) << | ||
612 | CCDC_FMT_HORZ_FMTSPH_SHIFT) | | ||
613 | (params->win.width & CCDC_FMT_HORZ_FMTLNH_MASK); | ||
614 | regw(val, CCDC_FMT_HORZ); | ||
615 | |||
616 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_HORZ...\n", val); | ||
617 | val = (params->win.top & CCDC_FMT_VERT_FMTSLV_MASK) | ||
618 | << CCDC_FMT_VERT_FMTSLV_SHIFT; | ||
619 | if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) | ||
620 | val |= (params->win.height) & CCDC_FMT_VERT_FMTLNV_MASK; | ||
621 | else | ||
622 | val |= (params->win.height >> 1) & CCDC_FMT_VERT_FMTLNV_MASK; | ||
623 | |||
624 | dev_dbg(ccdc_cfg.dev, "\nparams->win.height 0x%x ...\n", | ||
625 | params->win.height); | ||
626 | regw(val, CCDC_FMT_VERT); | ||
627 | |||
628 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to FMT_VERT...\n", val); | ||
629 | |||
630 | dev_dbg(ccdc_cfg.dev, "\nbelow regw(val, FMT_VERT)..."); | ||
631 | |||
632 | /* | ||
633 | * Configure Horizontal offset register. If pack 8 is enabled then | ||
634 | * 1 pixel will take 1 byte | ||
635 | */ | ||
636 | if ((config_params->data_sz == CCDC_DATA_8BITS) || | ||
637 | config_params->alaw.enable) | ||
638 | regw((params->win.width + CCDC_32BYTE_ALIGN_VAL) & | ||
639 | CCDC_HSIZE_OFF_MASK, CCDC_HSIZE_OFF); | ||
640 | else | ||
641 | /* else one pixel will take 2 byte */ | ||
642 | regw(((params->win.width * CCDC_TWO_BYTES_PER_PIXEL) + | ||
643 | CCDC_32BYTE_ALIGN_VAL) & CCDC_HSIZE_OFF_MASK, | ||
644 | CCDC_HSIZE_OFF); | ||
645 | |||
646 | /* Set value for SDOFST */ | ||
647 | if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
648 | if (params->image_invert_enable) { | ||
649 | /* For intelace inverse mode */ | ||
650 | regw(CCDC_INTERLACED_IMAGE_INVERT, CCDC_SDOFST); | ||
651 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x4B6D to SDOFST..\n"); | ||
652 | } | ||
653 | |||
654 | else { | ||
655 | /* For intelace non inverse mode */ | ||
656 | regw(CCDC_INTERLACED_NO_IMAGE_INVERT, CCDC_SDOFST); | ||
657 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x0249 to SDOFST..\n"); | ||
658 | } | ||
659 | } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { | ||
660 | regw(CCDC_PROGRESSIVE_NO_IMAGE_INVERT, CCDC_SDOFST); | ||
661 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x0000 to SDOFST...\n"); | ||
662 | } | ||
663 | |||
664 | /* | ||
665 | * Configure video port pixel selection (VPOUT) | ||
666 | * Here -1 is to make the height value less than FMT_VERT.FMTLNV | ||
667 | */ | ||
668 | if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) | ||
669 | val = (((params->win.height - 1) & CCDC_VP_OUT_VERT_NUM_MASK)) | ||
670 | << CCDC_VP_OUT_VERT_NUM_SHIFT; | ||
671 | else | ||
672 | val = | ||
673 | ((((params->win.height >> CCDC_INTERLACED_HEIGHT_SHIFT) - | ||
674 | 1) & CCDC_VP_OUT_VERT_NUM_MASK)) << | ||
675 | CCDC_VP_OUT_VERT_NUM_SHIFT; | ||
676 | |||
677 | val |= ((((params->win.width))) & CCDC_VP_OUT_HORZ_NUM_MASK) | ||
678 | << CCDC_VP_OUT_HORZ_NUM_SHIFT; | ||
679 | val |= (params->win.left) & CCDC_VP_OUT_HORZ_ST_MASK; | ||
680 | regw(val, CCDC_VP_OUT); | ||
681 | |||
682 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to VP_OUT...\n", val); | ||
683 | regw(syn_mode, CCDC_SYN_MODE); | ||
684 | dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to SYN_MODE...\n", syn_mode); | ||
685 | |||
686 | ccdc_sbl_reset(); | ||
687 | dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw..."); | ||
688 | ccdc_readregs(); | ||
689 | } | ||
690 | |||
691 | static int ccdc_configure(void) | ||
692 | { | ||
693 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
694 | ccdc_config_raw(); | ||
695 | else | ||
696 | ccdc_config_ycbcr(); | ||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | static int ccdc_set_buftype(enum ccdc_buftype buf_type) | ||
701 | { | ||
702 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
703 | ccdc_cfg.bayer.buf_type = buf_type; | ||
704 | else | ||
705 | ccdc_cfg.ycbcr.buf_type = buf_type; | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static enum ccdc_buftype ccdc_get_buftype(void) | ||
710 | { | ||
711 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
712 | return ccdc_cfg.bayer.buf_type; | ||
713 | return ccdc_cfg.ycbcr.buf_type; | ||
714 | } | ||
715 | |||
716 | static int ccdc_enum_pix(u32 *pix, int i) | ||
717 | { | ||
718 | int ret = -EINVAL; | ||
719 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { | ||
720 | if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) { | ||
721 | *pix = ccdc_raw_bayer_pix_formats[i]; | ||
722 | ret = 0; | ||
723 | } | ||
724 | } else { | ||
725 | if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) { | ||
726 | *pix = ccdc_raw_yuv_pix_formats[i]; | ||
727 | ret = 0; | ||
728 | } | ||
729 | } | ||
730 | return ret; | ||
731 | } | ||
732 | |||
733 | static int ccdc_set_pixel_format(u32 pixfmt) | ||
734 | { | ||
735 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { | ||
736 | ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; | ||
737 | if (pixfmt == V4L2_PIX_FMT_SBGGR8) | ||
738 | ccdc_cfg.bayer.config_params.alaw.enable = 1; | ||
739 | else if (pixfmt != V4L2_PIX_FMT_SBGGR16) | ||
740 | return -EINVAL; | ||
741 | } else { | ||
742 | if (pixfmt == V4L2_PIX_FMT_YUYV) | ||
743 | ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; | ||
744 | else if (pixfmt == V4L2_PIX_FMT_UYVY) | ||
745 | ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; | ||
746 | else | ||
747 | return -EINVAL; | ||
748 | } | ||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static u32 ccdc_get_pixel_format(void) | ||
753 | { | ||
754 | struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw; | ||
755 | u32 pixfmt; | ||
756 | |||
757 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
758 | if (alaw->enable) | ||
759 | pixfmt = V4L2_PIX_FMT_SBGGR8; | ||
760 | else | ||
761 | pixfmt = V4L2_PIX_FMT_SBGGR16; | ||
762 | else { | ||
763 | if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) | ||
764 | pixfmt = V4L2_PIX_FMT_YUYV; | ||
765 | else | ||
766 | pixfmt = V4L2_PIX_FMT_UYVY; | ||
767 | } | ||
768 | return pixfmt; | ||
769 | } | ||
770 | |||
771 | static int ccdc_set_image_window(struct v4l2_rect *win) | ||
772 | { | ||
773 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
774 | ccdc_cfg.bayer.win = *win; | ||
775 | else | ||
776 | ccdc_cfg.ycbcr.win = *win; | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | static void ccdc_get_image_window(struct v4l2_rect *win) | ||
781 | { | ||
782 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
783 | *win = ccdc_cfg.bayer.win; | ||
784 | else | ||
785 | *win = ccdc_cfg.ycbcr.win; | ||
786 | } | ||
787 | |||
788 | static unsigned int ccdc_get_line_length(void) | ||
789 | { | ||
790 | struct ccdc_config_params_raw *config_params = | ||
791 | &ccdc_cfg.bayer.config_params; | ||
792 | unsigned int len; | ||
793 | |||
794 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) { | ||
795 | if ((config_params->alaw.enable) || | ||
796 | (config_params->data_sz == CCDC_DATA_8BITS)) | ||
797 | len = ccdc_cfg.bayer.win.width; | ||
798 | else | ||
799 | len = ccdc_cfg.bayer.win.width * 2; | ||
800 | } else | ||
801 | len = ccdc_cfg.ycbcr.win.width * 2; | ||
802 | return ALIGN(len, 32); | ||
803 | } | ||
804 | |||
805 | static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt) | ||
806 | { | ||
807 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
808 | ccdc_cfg.bayer.frm_fmt = frm_fmt; | ||
809 | else | ||
810 | ccdc_cfg.ycbcr.frm_fmt = frm_fmt; | ||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static enum ccdc_frmfmt ccdc_get_frame_format(void) | ||
815 | { | ||
816 | if (ccdc_cfg.if_type == VPFE_RAW_BAYER) | ||
817 | return ccdc_cfg.bayer.frm_fmt; | ||
818 | else | ||
819 | return ccdc_cfg.ycbcr.frm_fmt; | ||
820 | } | ||
821 | |||
822 | static int ccdc_getfid(void) | ||
823 | { | ||
824 | return (regr(CCDC_SYN_MODE) >> 15) & 1; | ||
825 | } | ||
826 | |||
827 | /* misc operations */ | ||
828 | static inline void ccdc_setfbaddr(unsigned long addr) | ||
829 | { | ||
830 | regw(addr & 0xffffffe0, CCDC_SDR_ADDR); | ||
831 | } | ||
832 | |||
833 | static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) | ||
834 | { | ||
835 | ccdc_cfg.if_type = params->if_type; | ||
836 | |||
837 | switch (params->if_type) { | ||
838 | case VPFE_BT656: | ||
839 | case VPFE_YCBCR_SYNC_16: | ||
840 | case VPFE_YCBCR_SYNC_8: | ||
841 | case VPFE_BT656_10BIT: | ||
842 | ccdc_cfg.ycbcr.vd_pol = params->vdpol; | ||
843 | ccdc_cfg.ycbcr.hd_pol = params->hdpol; | ||
844 | break; | ||
845 | default: | ||
846 | /* TODO add support for raw bayer here */ | ||
847 | return -EINVAL; | ||
848 | } | ||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | static void ccdc_save_context(void) | ||
853 | { | ||
854 | ccdc_ctx[CCDC_PCR >> 2] = regr(CCDC_PCR); | ||
855 | ccdc_ctx[CCDC_SYN_MODE >> 2] = regr(CCDC_SYN_MODE); | ||
856 | ccdc_ctx[CCDC_HD_VD_WID >> 2] = regr(CCDC_HD_VD_WID); | ||
857 | ccdc_ctx[CCDC_PIX_LINES >> 2] = regr(CCDC_PIX_LINES); | ||
858 | ccdc_ctx[CCDC_HORZ_INFO >> 2] = regr(CCDC_HORZ_INFO); | ||
859 | ccdc_ctx[CCDC_VERT_START >> 2] = regr(CCDC_VERT_START); | ||
860 | ccdc_ctx[CCDC_VERT_LINES >> 2] = regr(CCDC_VERT_LINES); | ||
861 | ccdc_ctx[CCDC_CULLING >> 2] = regr(CCDC_CULLING); | ||
862 | ccdc_ctx[CCDC_HSIZE_OFF >> 2] = regr(CCDC_HSIZE_OFF); | ||
863 | ccdc_ctx[CCDC_SDOFST >> 2] = regr(CCDC_SDOFST); | ||
864 | ccdc_ctx[CCDC_SDR_ADDR >> 2] = regr(CCDC_SDR_ADDR); | ||
865 | ccdc_ctx[CCDC_CLAMP >> 2] = regr(CCDC_CLAMP); | ||
866 | ccdc_ctx[CCDC_DCSUB >> 2] = regr(CCDC_DCSUB); | ||
867 | ccdc_ctx[CCDC_COLPTN >> 2] = regr(CCDC_COLPTN); | ||
868 | ccdc_ctx[CCDC_BLKCMP >> 2] = regr(CCDC_BLKCMP); | ||
869 | ccdc_ctx[CCDC_FPC >> 2] = regr(CCDC_FPC); | ||
870 | ccdc_ctx[CCDC_FPC_ADDR >> 2] = regr(CCDC_FPC_ADDR); | ||
871 | ccdc_ctx[CCDC_VDINT >> 2] = regr(CCDC_VDINT); | ||
872 | ccdc_ctx[CCDC_ALAW >> 2] = regr(CCDC_ALAW); | ||
873 | ccdc_ctx[CCDC_REC656IF >> 2] = regr(CCDC_REC656IF); | ||
874 | ccdc_ctx[CCDC_CCDCFG >> 2] = regr(CCDC_CCDCFG); | ||
875 | ccdc_ctx[CCDC_FMTCFG >> 2] = regr(CCDC_FMTCFG); | ||
876 | ccdc_ctx[CCDC_FMT_HORZ >> 2] = regr(CCDC_FMT_HORZ); | ||
877 | ccdc_ctx[CCDC_FMT_VERT >> 2] = regr(CCDC_FMT_VERT); | ||
878 | ccdc_ctx[CCDC_FMT_ADDR0 >> 2] = regr(CCDC_FMT_ADDR0); | ||
879 | ccdc_ctx[CCDC_FMT_ADDR1 >> 2] = regr(CCDC_FMT_ADDR1); | ||
880 | ccdc_ctx[CCDC_FMT_ADDR2 >> 2] = regr(CCDC_FMT_ADDR2); | ||
881 | ccdc_ctx[CCDC_FMT_ADDR3 >> 2] = regr(CCDC_FMT_ADDR3); | ||
882 | ccdc_ctx[CCDC_FMT_ADDR4 >> 2] = regr(CCDC_FMT_ADDR4); | ||
883 | ccdc_ctx[CCDC_FMT_ADDR5 >> 2] = regr(CCDC_FMT_ADDR5); | ||
884 | ccdc_ctx[CCDC_FMT_ADDR6 >> 2] = regr(CCDC_FMT_ADDR6); | ||
885 | ccdc_ctx[CCDC_FMT_ADDR7 >> 2] = regr(CCDC_FMT_ADDR7); | ||
886 | ccdc_ctx[CCDC_PRGEVEN_0 >> 2] = regr(CCDC_PRGEVEN_0); | ||
887 | ccdc_ctx[CCDC_PRGEVEN_1 >> 2] = regr(CCDC_PRGEVEN_1); | ||
888 | ccdc_ctx[CCDC_PRGODD_0 >> 2] = regr(CCDC_PRGODD_0); | ||
889 | ccdc_ctx[CCDC_PRGODD_1 >> 2] = regr(CCDC_PRGODD_1); | ||
890 | ccdc_ctx[CCDC_VP_OUT >> 2] = regr(CCDC_VP_OUT); | ||
891 | } | ||
892 | |||
893 | static void ccdc_restore_context(void) | ||
894 | { | ||
895 | regw(ccdc_ctx[CCDC_SYN_MODE >> 2], CCDC_SYN_MODE); | ||
896 | regw(ccdc_ctx[CCDC_HD_VD_WID >> 2], CCDC_HD_VD_WID); | ||
897 | regw(ccdc_ctx[CCDC_PIX_LINES >> 2], CCDC_PIX_LINES); | ||
898 | regw(ccdc_ctx[CCDC_HORZ_INFO >> 2], CCDC_HORZ_INFO); | ||
899 | regw(ccdc_ctx[CCDC_VERT_START >> 2], CCDC_VERT_START); | ||
900 | regw(ccdc_ctx[CCDC_VERT_LINES >> 2], CCDC_VERT_LINES); | ||
901 | regw(ccdc_ctx[CCDC_CULLING >> 2], CCDC_CULLING); | ||
902 | regw(ccdc_ctx[CCDC_HSIZE_OFF >> 2], CCDC_HSIZE_OFF); | ||
903 | regw(ccdc_ctx[CCDC_SDOFST >> 2], CCDC_SDOFST); | ||
904 | regw(ccdc_ctx[CCDC_SDR_ADDR >> 2], CCDC_SDR_ADDR); | ||
905 | regw(ccdc_ctx[CCDC_CLAMP >> 2], CCDC_CLAMP); | ||
906 | regw(ccdc_ctx[CCDC_DCSUB >> 2], CCDC_DCSUB); | ||
907 | regw(ccdc_ctx[CCDC_COLPTN >> 2], CCDC_COLPTN); | ||
908 | regw(ccdc_ctx[CCDC_BLKCMP >> 2], CCDC_BLKCMP); | ||
909 | regw(ccdc_ctx[CCDC_FPC >> 2], CCDC_FPC); | ||
910 | regw(ccdc_ctx[CCDC_FPC_ADDR >> 2], CCDC_FPC_ADDR); | ||
911 | regw(ccdc_ctx[CCDC_VDINT >> 2], CCDC_VDINT); | ||
912 | regw(ccdc_ctx[CCDC_ALAW >> 2], CCDC_ALAW); | ||
913 | regw(ccdc_ctx[CCDC_REC656IF >> 2], CCDC_REC656IF); | ||
914 | regw(ccdc_ctx[CCDC_CCDCFG >> 2], CCDC_CCDCFG); | ||
915 | regw(ccdc_ctx[CCDC_FMTCFG >> 2], CCDC_FMTCFG); | ||
916 | regw(ccdc_ctx[CCDC_FMT_HORZ >> 2], CCDC_FMT_HORZ); | ||
917 | regw(ccdc_ctx[CCDC_FMT_VERT >> 2], CCDC_FMT_VERT); | ||
918 | regw(ccdc_ctx[CCDC_FMT_ADDR0 >> 2], CCDC_FMT_ADDR0); | ||
919 | regw(ccdc_ctx[CCDC_FMT_ADDR1 >> 2], CCDC_FMT_ADDR1); | ||
920 | regw(ccdc_ctx[CCDC_FMT_ADDR2 >> 2], CCDC_FMT_ADDR2); | ||
921 | regw(ccdc_ctx[CCDC_FMT_ADDR3 >> 2], CCDC_FMT_ADDR3); | ||
922 | regw(ccdc_ctx[CCDC_FMT_ADDR4 >> 2], CCDC_FMT_ADDR4); | ||
923 | regw(ccdc_ctx[CCDC_FMT_ADDR5 >> 2], CCDC_FMT_ADDR5); | ||
924 | regw(ccdc_ctx[CCDC_FMT_ADDR6 >> 2], CCDC_FMT_ADDR6); | ||
925 | regw(ccdc_ctx[CCDC_FMT_ADDR7 >> 2], CCDC_FMT_ADDR7); | ||
926 | regw(ccdc_ctx[CCDC_PRGEVEN_0 >> 2], CCDC_PRGEVEN_0); | ||
927 | regw(ccdc_ctx[CCDC_PRGEVEN_1 >> 2], CCDC_PRGEVEN_1); | ||
928 | regw(ccdc_ctx[CCDC_PRGODD_0 >> 2], CCDC_PRGODD_0); | ||
929 | regw(ccdc_ctx[CCDC_PRGODD_1 >> 2], CCDC_PRGODD_1); | ||
930 | regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); | ||
931 | regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); | ||
932 | } | ||
933 | static struct ccdc_hw_device ccdc_hw_dev = { | ||
934 | .name = "DM6446 CCDC", | ||
935 | .owner = THIS_MODULE, | ||
936 | .hw_ops = { | ||
937 | .open = ccdc_open, | ||
938 | .close = ccdc_close, | ||
939 | .reset = ccdc_sbl_reset, | ||
940 | .enable = ccdc_enable, | ||
941 | .set_hw_if_params = ccdc_set_hw_if_params, | ||
942 | .set_params = ccdc_set_params, | ||
943 | .configure = ccdc_configure, | ||
944 | .set_buftype = ccdc_set_buftype, | ||
945 | .get_buftype = ccdc_get_buftype, | ||
946 | .enum_pix = ccdc_enum_pix, | ||
947 | .set_pixel_format = ccdc_set_pixel_format, | ||
948 | .get_pixel_format = ccdc_get_pixel_format, | ||
949 | .set_frame_format = ccdc_set_frame_format, | ||
950 | .get_frame_format = ccdc_get_frame_format, | ||
951 | .set_image_window = ccdc_set_image_window, | ||
952 | .get_image_window = ccdc_get_image_window, | ||
953 | .get_line_length = ccdc_get_line_length, | ||
954 | .setfbaddr = ccdc_setfbaddr, | ||
955 | .getfid = ccdc_getfid, | ||
956 | }, | ||
957 | }; | ||
958 | |||
959 | static int __init dm644x_ccdc_probe(struct platform_device *pdev) | ||
960 | { | ||
961 | struct resource *res; | ||
962 | int status = 0; | ||
963 | |||
964 | /* | ||
965 | * first try to register with vpfe. If not correct platform, then we | ||
966 | * don't have to iomap | ||
967 | */ | ||
968 | status = vpfe_register_ccdc_device(&ccdc_hw_dev); | ||
969 | if (status < 0) | ||
970 | return status; | ||
971 | |||
972 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
973 | if (!res) { | ||
974 | status = -ENODEV; | ||
975 | goto fail_nores; | ||
976 | } | ||
977 | |||
978 | res = request_mem_region(res->start, resource_size(res), res->name); | ||
979 | if (!res) { | ||
980 | status = -EBUSY; | ||
981 | goto fail_nores; | ||
982 | } | ||
983 | |||
984 | ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res)); | ||
985 | if (!ccdc_cfg.base_addr) { | ||
986 | status = -ENOMEM; | ||
987 | goto fail_nomem; | ||
988 | } | ||
989 | |||
990 | /* Get and enable Master clock */ | ||
991 | ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); | ||
992 | if (IS_ERR(ccdc_cfg.mclk)) { | ||
993 | status = PTR_ERR(ccdc_cfg.mclk); | ||
994 | goto fail_nomap; | ||
995 | } | ||
996 | if (clk_enable(ccdc_cfg.mclk)) { | ||
997 | status = -ENODEV; | ||
998 | goto fail_mclk; | ||
999 | } | ||
1000 | |||
1001 | /* Get and enable Slave clock */ | ||
1002 | ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); | ||
1003 | if (IS_ERR(ccdc_cfg.sclk)) { | ||
1004 | status = PTR_ERR(ccdc_cfg.sclk); | ||
1005 | goto fail_mclk; | ||
1006 | } | ||
1007 | if (clk_enable(ccdc_cfg.sclk)) { | ||
1008 | status = -ENODEV; | ||
1009 | goto fail_sclk; | ||
1010 | } | ||
1011 | ccdc_cfg.dev = &pdev->dev; | ||
1012 | printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); | ||
1013 | return 0; | ||
1014 | fail_sclk: | ||
1015 | clk_put(ccdc_cfg.sclk); | ||
1016 | fail_mclk: | ||
1017 | clk_put(ccdc_cfg.mclk); | ||
1018 | fail_nomap: | ||
1019 | iounmap(ccdc_cfg.base_addr); | ||
1020 | fail_nomem: | ||
1021 | release_mem_region(res->start, resource_size(res)); | ||
1022 | fail_nores: | ||
1023 | vpfe_unregister_ccdc_device(&ccdc_hw_dev); | ||
1024 | return status; | ||
1025 | } | ||
1026 | |||
1027 | static int dm644x_ccdc_remove(struct platform_device *pdev) | ||
1028 | { | ||
1029 | struct resource *res; | ||
1030 | |||
1031 | clk_put(ccdc_cfg.mclk); | ||
1032 | clk_put(ccdc_cfg.sclk); | ||
1033 | iounmap(ccdc_cfg.base_addr); | ||
1034 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1035 | if (res) | ||
1036 | release_mem_region(res->start, resource_size(res)); | ||
1037 | vpfe_unregister_ccdc_device(&ccdc_hw_dev); | ||
1038 | return 0; | ||
1039 | } | ||
1040 | |||
1041 | static int dm644x_ccdc_suspend(struct device *dev) | ||
1042 | { | ||
1043 | /* Save CCDC context */ | ||
1044 | ccdc_save_context(); | ||
1045 | /* Disable CCDC */ | ||
1046 | ccdc_enable(0); | ||
1047 | /* Disable both master and slave clock */ | ||
1048 | clk_disable(ccdc_cfg.mclk); | ||
1049 | clk_disable(ccdc_cfg.sclk); | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static int dm644x_ccdc_resume(struct device *dev) | ||
1055 | { | ||
1056 | /* Enable both master and slave clock */ | ||
1057 | clk_enable(ccdc_cfg.mclk); | ||
1058 | clk_enable(ccdc_cfg.sclk); | ||
1059 | /* Restore CCDC context */ | ||
1060 | ccdc_restore_context(); | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static const struct dev_pm_ops dm644x_ccdc_pm_ops = { | ||
1066 | .suspend = dm644x_ccdc_suspend, | ||
1067 | .resume = dm644x_ccdc_resume, | ||
1068 | }; | ||
1069 | |||
1070 | static struct platform_driver dm644x_ccdc_driver = { | ||
1071 | .driver = { | ||
1072 | .name = "dm644x_ccdc", | ||
1073 | .owner = THIS_MODULE, | ||
1074 | .pm = &dm644x_ccdc_pm_ops, | ||
1075 | }, | ||
1076 | .remove = __devexit_p(dm644x_ccdc_remove), | ||
1077 | .probe = dm644x_ccdc_probe, | ||
1078 | }; | ||
1079 | |||
1080 | static int __init dm644x_ccdc_init(void) | ||
1081 | { | ||
1082 | return platform_driver_register(&dm644x_ccdc_driver); | ||
1083 | } | ||
1084 | |||
1085 | static void __exit dm644x_ccdc_exit(void) | ||
1086 | { | ||
1087 | platform_driver_unregister(&dm644x_ccdc_driver); | ||
1088 | } | ||
1089 | |||
1090 | module_init(dm644x_ccdc_init); | ||
1091 | 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 new file mode 100644 index 00000000000..90370e414e2 --- /dev/null +++ b/drivers/media/video/davinci/dm644x_ccdc_regs.h | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _DM644X_CCDC_REGS_H | ||
19 | #define _DM644X_CCDC_REGS_H | ||
20 | |||
21 | /**************************************************************************\ | ||
22 | * Register OFFSET Definitions | ||
23 | \**************************************************************************/ | ||
24 | #define CCDC_PID 0x0 | ||
25 | #define CCDC_PCR 0x4 | ||
26 | #define CCDC_SYN_MODE 0x8 | ||
27 | #define CCDC_HD_VD_WID 0xc | ||
28 | #define CCDC_PIX_LINES 0x10 | ||
29 | #define CCDC_HORZ_INFO 0x14 | ||
30 | #define CCDC_VERT_START 0x18 | ||
31 | #define CCDC_VERT_LINES 0x1c | ||
32 | #define CCDC_CULLING 0x20 | ||
33 | #define CCDC_HSIZE_OFF 0x24 | ||
34 | #define CCDC_SDOFST 0x28 | ||
35 | #define CCDC_SDR_ADDR 0x2c | ||
36 | #define CCDC_CLAMP 0x30 | ||
37 | #define CCDC_DCSUB 0x34 | ||
38 | #define CCDC_COLPTN 0x38 | ||
39 | #define CCDC_BLKCMP 0x3c | ||
40 | #define CCDC_FPC 0x40 | ||
41 | #define CCDC_FPC_ADDR 0x44 | ||
42 | #define CCDC_VDINT 0x48 | ||
43 | #define CCDC_ALAW 0x4c | ||
44 | #define CCDC_REC656IF 0x50 | ||
45 | #define CCDC_CCDCFG 0x54 | ||
46 | #define CCDC_FMTCFG 0x58 | ||
47 | #define CCDC_FMT_HORZ 0x5c | ||
48 | #define CCDC_FMT_VERT 0x60 | ||
49 | #define CCDC_FMT_ADDR0 0x64 | ||
50 | #define CCDC_FMT_ADDR1 0x68 | ||
51 | #define CCDC_FMT_ADDR2 0x6c | ||
52 | #define CCDC_FMT_ADDR3 0x70 | ||
53 | #define CCDC_FMT_ADDR4 0x74 | ||
54 | #define CCDC_FMT_ADDR5 0x78 | ||
55 | #define CCDC_FMT_ADDR6 0x7c | ||
56 | #define CCDC_FMT_ADDR7 0x80 | ||
57 | #define CCDC_PRGEVEN_0 0x84 | ||
58 | #define CCDC_PRGEVEN_1 0x88 | ||
59 | #define CCDC_PRGODD_0 0x8c | ||
60 | #define CCDC_PRGODD_1 0x90 | ||
61 | #define CCDC_VP_OUT 0x94 | ||
62 | #define CCDC_REG_END 0x98 | ||
63 | |||
64 | /*************************************************************** | ||
65 | * Define for various register bit mask and shifts for CCDC | ||
66 | ****************************************************************/ | ||
67 | #define CCDC_FID_POL_MASK 1 | ||
68 | #define CCDC_FID_POL_SHIFT 4 | ||
69 | #define CCDC_HD_POL_MASK 1 | ||
70 | #define CCDC_HD_POL_SHIFT 3 | ||
71 | #define CCDC_VD_POL_MASK 1 | ||
72 | #define CCDC_VD_POL_SHIFT 2 | ||
73 | #define CCDC_HSIZE_OFF_MASK 0xffffffe0 | ||
74 | #define CCDC_32BYTE_ALIGN_VAL 31 | ||
75 | #define CCDC_FRM_FMT_MASK 0x1 | ||
76 | #define CCDC_FRM_FMT_SHIFT 7 | ||
77 | #define CCDC_DATA_SZ_MASK 7 | ||
78 | #define CCDC_DATA_SZ_SHIFT 8 | ||
79 | #define CCDC_PIX_FMT_MASK 3 | ||
80 | #define CCDC_PIX_FMT_SHIFT 12 | ||
81 | #define CCDC_VP2SDR_DISABLE 0xFFFBFFFF | ||
82 | #define CCDC_WEN_ENABLE (1 << 17) | ||
83 | #define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF | ||
84 | #define CCDC_VDHDEN_ENABLE (1 << 16) | ||
85 | #define CCDC_LPF_ENABLE (1 << 14) | ||
86 | #define CCDC_ALAW_ENABLE (1 << 3) | ||
87 | #define CCDC_ALAW_GAMA_WD_MASK 7 | ||
88 | #define CCDC_BLK_CLAMP_ENABLE (1 << 31) | ||
89 | #define CCDC_BLK_SGAIN_MASK 0x1F | ||
90 | #define CCDC_BLK_ST_PXL_MASK 0x7FFF | ||
91 | #define CCDC_BLK_ST_PXL_SHIFT 10 | ||
92 | #define CCDC_BLK_SAMPLE_LN_MASK 7 | ||
93 | #define CCDC_BLK_SAMPLE_LN_SHIFT 28 | ||
94 | #define CCDC_BLK_SAMPLE_LINE_MASK 7 | ||
95 | #define CCDC_BLK_SAMPLE_LINE_SHIFT 25 | ||
96 | #define CCDC_BLK_DC_SUB_MASK 0x03FFF | ||
97 | #define CCDC_BLK_COMP_MASK 0xFF | ||
98 | #define CCDC_BLK_COMP_GB_COMP_SHIFT 8 | ||
99 | #define CCDC_BLK_COMP_GR_COMP_SHIFT 16 | ||
100 | #define CCDC_BLK_COMP_R_COMP_SHIFT 24 | ||
101 | #define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15) | ||
102 | #define CCDC_FPC_ENABLE (1 << 15) | ||
103 | #define CCDC_FPC_DISABLE 0 | ||
104 | #define CCDC_FPC_FPC_NUM_MASK 0x7FFF | ||
105 | #define CCDC_DATA_PACK_ENABLE (1 << 11) | ||
106 | #define CCDC_FMTCFG_VPIN_MASK 7 | ||
107 | #define CCDC_FMTCFG_VPIN_SHIFT 12 | ||
108 | #define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF | ||
109 | #define CCDC_FMT_HORZ_FMTSPH_MASK 0x1FFF | ||
110 | #define CCDC_FMT_HORZ_FMTSPH_SHIFT 16 | ||
111 | #define CCDC_FMT_VERT_FMTLNV_MASK 0x1FFF | ||
112 | #define CCDC_FMT_VERT_FMTSLV_MASK 0x1FFF | ||
113 | #define CCDC_FMT_VERT_FMTSLV_SHIFT 16 | ||
114 | #define CCDC_VP_OUT_VERT_NUM_MASK 0x3FFF | ||
115 | #define CCDC_VP_OUT_VERT_NUM_SHIFT 17 | ||
116 | #define CCDC_VP_OUT_HORZ_NUM_MASK 0x1FFF | ||
117 | #define CCDC_VP_OUT_HORZ_NUM_SHIFT 4 | ||
118 | #define CCDC_VP_OUT_HORZ_ST_MASK 0xF | ||
119 | #define CCDC_HORZ_INFO_SPH_SHIFT 16 | ||
120 | #define CCDC_VERT_START_SLV0_SHIFT 16 | ||
121 | #define CCDC_VDINT_VDINT0_SHIFT 16 | ||
122 | #define CCDC_VDINT_VDINT1_MASK 0xFFFF | ||
123 | #define CCDC_PPC_RAW 1 | ||
124 | #define CCDC_DCSUB_DEFAULT_VAL 0 | ||
125 | #define CCDC_CLAMP_DEFAULT_VAL 0 | ||
126 | #define CCDC_ENABLE_VIDEO_PORT 0x8000 | ||
127 | #define CCDC_DISABLE_VIDEO_PORT 0 | ||
128 | #define CCDC_COLPTN_VAL 0xBB11BB11 | ||
129 | #define CCDC_TWO_BYTES_PER_PIXEL 2 | ||
130 | #define CCDC_INTERLACED_IMAGE_INVERT 0x4B6D | ||
131 | #define CCDC_INTERLACED_NO_IMAGE_INVERT 0x0249 | ||
132 | #define CCDC_PROGRESSIVE_IMAGE_INVERT 0x4000 | ||
133 | #define CCDC_PROGRESSIVE_NO_IMAGE_INVERT 0 | ||
134 | #define CCDC_INTERLACED_HEIGHT_SHIFT 1 | ||
135 | #define CCDC_SYN_MODE_INPMOD_SHIFT 12 | ||
136 | #define CCDC_SYN_MODE_INPMOD_MASK 3 | ||
137 | #define CCDC_SYN_MODE_8BITS (7 << 8) | ||
138 | #define CCDC_SYN_MODE_10BITS (6 << 8) | ||
139 | #define CCDC_SYN_MODE_11BITS (5 << 8) | ||
140 | #define CCDC_SYN_MODE_12BITS (4 << 8) | ||
141 | #define CCDC_SYN_MODE_13BITS (3 << 8) | ||
142 | #define CCDC_SYN_MODE_14BITS (2 << 8) | ||
143 | #define CCDC_SYN_MODE_15BITS (1 << 8) | ||
144 | #define CCDC_SYN_MODE_16BITS (0 << 8) | ||
145 | #define CCDC_SYN_FLDMODE_MASK 1 | ||
146 | #define CCDC_SYN_FLDMODE_SHIFT 7 | ||
147 | #define CCDC_REC656IF_BT656_EN 3 | ||
148 | #define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2) | ||
149 | #define CCDC_CCDCFG_Y8POS_SHIFT 11 | ||
150 | #define CCDC_CCDCFG_BW656_10BIT (1 << 5) | ||
151 | #define CCDC_SDOFST_FIELD_INTERLEAVED 0x249 | ||
152 | #define CCDC_NO_CULLING 0xffff00ff | ||
153 | #endif | ||
diff --git a/drivers/media/video/davinci/isif.c b/drivers/media/video/davinci/isif.c new file mode 100644 index 00000000000..29c29c66859 --- /dev/null +++ b/drivers/media/video/davinci/isif.c | |||
@@ -0,0 +1,1172 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * Image Sensor Interface (ISIF) driver | ||
19 | * | ||
20 | * This driver is for configuring the ISIF IP available on DM365 or any other | ||
21 | * TI SoCs. This is used for capturing yuv or bayer video or image data | ||
22 | * from a decoder or sensor. This IP is similar to the CCDC IP on DM355 | ||
23 | * and DM6446, but with enhanced or additional ip blocks. The driver | ||
24 | * configures the ISIF upon commands from the vpfe bridge driver through | ||
25 | * ccdc_hw_device interface. | ||
26 | * | ||
27 | * TODO: 1) Raw bayer parameter settings and bayer capture | ||
28 | * 2) Add support for control ioctl | ||
29 | */ | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <linux/uaccess.h> | ||
33 | #include <linux/io.h> | ||
34 | #include <linux/videodev2.h> | ||
35 | #include <linux/clk.h> | ||
36 | #include <linux/err.h> | ||
37 | |||
38 | #include <mach/mux.h> | ||
39 | |||
40 | #include <media/davinci/isif.h> | ||
41 | #include <media/davinci/vpss.h> | ||
42 | |||
43 | #include "isif_regs.h" | ||
44 | #include "ccdc_hw_device.h" | ||
45 | |||
46 | /* Defaults for module configuration parameters */ | ||
47 | static struct isif_config_params_raw isif_config_defaults = { | ||
48 | .linearize = { | ||
49 | .en = 0, | ||
50 | .corr_shft = ISIF_NO_SHIFT, | ||
51 | .scale_fact = {1, 0}, | ||
52 | }, | ||
53 | .df_csc = { | ||
54 | .df_or_csc = 0, | ||
55 | .csc = { | ||
56 | .en = 0, | ||
57 | }, | ||
58 | }, | ||
59 | .dfc = { | ||
60 | .en = 0, | ||
61 | }, | ||
62 | .bclamp = { | ||
63 | .en = 0, | ||
64 | }, | ||
65 | .gain_offset = { | ||
66 | .gain = { | ||
67 | .r_ye = {1, 0}, | ||
68 | .gr_cy = {1, 0}, | ||
69 | .gb_g = {1, 0}, | ||
70 | .b_mg = {1, 0}, | ||
71 | }, | ||
72 | }, | ||
73 | .culling = { | ||
74 | .hcpat_odd = 0xff, | ||
75 | .hcpat_even = 0xff, | ||
76 | .vcpat = 0xff, | ||
77 | }, | ||
78 | .compress = { | ||
79 | .alg = ISIF_ALAW, | ||
80 | }, | ||
81 | }; | ||
82 | |||
83 | /* ISIF operation configuration */ | ||
84 | static struct isif_oper_config { | ||
85 | struct device *dev; | ||
86 | enum vpfe_hw_if_type if_type; | ||
87 | struct isif_ycbcr_config ycbcr; | ||
88 | struct isif_params_raw bayer; | ||
89 | enum isif_data_pack data_pack; | ||
90 | /* Master clock */ | ||
91 | struct clk *mclk; | ||
92 | /* ISIF base address */ | ||
93 | void __iomem *base_addr; | ||
94 | /* ISIF Linear Table 0 */ | ||
95 | void __iomem *linear_tbl0_addr; | ||
96 | /* ISIF Linear Table 1 */ | ||
97 | void __iomem *linear_tbl1_addr; | ||
98 | } isif_cfg = { | ||
99 | .ycbcr = { | ||
100 | .pix_fmt = CCDC_PIXFMT_YCBCR_8BIT, | ||
101 | .frm_fmt = CCDC_FRMFMT_INTERLACED, | ||
102 | .win = ISIF_WIN_NTSC, | ||
103 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
104 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
105 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
106 | .pix_order = CCDC_PIXORDER_CBYCRY, | ||
107 | .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED, | ||
108 | }, | ||
109 | .bayer = { | ||
110 | .pix_fmt = CCDC_PIXFMT_RAW, | ||
111 | .frm_fmt = CCDC_FRMFMT_PROGRESSIVE, | ||
112 | .win = ISIF_WIN_VGA, | ||
113 | .fid_pol = VPFE_PINPOL_POSITIVE, | ||
114 | .vd_pol = VPFE_PINPOL_POSITIVE, | ||
115 | .hd_pol = VPFE_PINPOL_POSITIVE, | ||
116 | .gain = { | ||
117 | .r_ye = {1, 0}, | ||
118 | .gr_cy = {1, 0}, | ||
119 | .gb_g = {1, 0}, | ||
120 | .b_mg = {1, 0}, | ||
121 | }, | ||
122 | .cfa_pat = ISIF_CFA_PAT_MOSAIC, | ||
123 | .data_msb = ISIF_BIT_MSB_11, | ||
124 | .config_params = { | ||
125 | .data_shift = ISIF_NO_SHIFT, | ||
126 | .col_pat_field0 = { | ||
127 | .olop = ISIF_GREEN_BLUE, | ||
128 | .olep = ISIF_BLUE, | ||
129 | .elop = ISIF_RED, | ||
130 | .elep = ISIF_GREEN_RED, | ||
131 | }, | ||
132 | .col_pat_field1 = { | ||
133 | .olop = ISIF_GREEN_BLUE, | ||
134 | .olep = ISIF_BLUE, | ||
135 | .elop = ISIF_RED, | ||
136 | .elep = ISIF_GREEN_RED, | ||
137 | }, | ||
138 | .test_pat_gen = 0, | ||
139 | }, | ||
140 | }, | ||
141 | .data_pack = ISIF_DATA_PACK8, | ||
142 | }; | ||
143 | |||
144 | /* Raw Bayer formats */ | ||
145 | static const u32 isif_raw_bayer_pix_formats[] = { | ||
146 | V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16}; | ||
147 | |||
148 | /* Raw YUV formats */ | ||
149 | static const u32 isif_raw_yuv_pix_formats[] = { | ||
150 | V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV}; | ||
151 | |||
152 | /* register access routines */ | ||
153 | static inline u32 regr(u32 offset) | ||
154 | { | ||
155 | return __raw_readl(isif_cfg.base_addr + offset); | ||
156 | } | ||
157 | |||
158 | static inline void regw(u32 val, u32 offset) | ||
159 | { | ||
160 | __raw_writel(val, isif_cfg.base_addr + offset); | ||
161 | } | ||
162 | |||
163 | /* reg_modify() - read, modify and write register */ | ||
164 | static inline u32 reg_modify(u32 mask, u32 val, u32 offset) | ||
165 | { | ||
166 | u32 new_val = (regr(offset) & ~mask) | (val & mask); | ||
167 | |||
168 | regw(new_val, offset); | ||
169 | return new_val; | ||
170 | } | ||
171 | |||
172 | static inline void regw_lin_tbl(u32 val, u32 offset, int i) | ||
173 | { | ||
174 | if (!i) | ||
175 | __raw_writel(val, isif_cfg.linear_tbl0_addr + offset); | ||
176 | else | ||
177 | __raw_writel(val, isif_cfg.linear_tbl1_addr + offset); | ||
178 | } | ||
179 | |||
180 | static void isif_disable_all_modules(void) | ||
181 | { | ||
182 | /* disable BC */ | ||
183 | regw(0, CLAMPCFG); | ||
184 | /* disable vdfc */ | ||
185 | regw(0, DFCCTL); | ||
186 | /* disable CSC */ | ||
187 | regw(0, CSCCTL); | ||
188 | /* disable linearization */ | ||
189 | regw(0, LINCFG0); | ||
190 | /* disable other modules here as they are supported */ | ||
191 | } | ||
192 | |||
193 | static void isif_enable(int en) | ||
194 | { | ||
195 | if (!en) { | ||
196 | /* Before disable isif, disable all ISIF modules */ | ||
197 | isif_disable_all_modules(); | ||
198 | /* | ||
199 | * wait for next VD. Assume lowest scan rate is 12 Hz. So | ||
200 | * 100 msec delay is good enough | ||
201 | */ | ||
202 | msleep(100); | ||
203 | } | ||
204 | reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN); | ||
205 | } | ||
206 | |||
207 | static void isif_enable_output_to_sdram(int en) | ||
208 | { | ||
209 | reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); | ||
210 | } | ||
211 | |||
212 | static void isif_config_culling(struct isif_cul *cul) | ||
213 | { | ||
214 | u32 val; | ||
215 | |||
216 | /* Horizontal pattern */ | ||
217 | val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd; | ||
218 | regw(val, CULH); | ||
219 | |||
220 | /* vertical pattern */ | ||
221 | regw(cul->vcpat, CULV); | ||
222 | |||
223 | /* LPF */ | ||
224 | reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT, | ||
225 | cul->en_lpf << ISIF_LPF_SHIFT, MODESET); | ||
226 | } | ||
227 | |||
228 | static void isif_config_gain_offset(void) | ||
229 | { | ||
230 | struct isif_gain_offsets_adj *gain_off_p = | ||
231 | &isif_cfg.bayer.config_params.gain_offset; | ||
232 | u32 val; | ||
233 | |||
234 | val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) | | ||
235 | (!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) | | ||
236 | (!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) | | ||
237 | (!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) | | ||
238 | (!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) | | ||
239 | (!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT); | ||
240 | |||
241 | reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD); | ||
242 | |||
243 | val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) | | ||
244 | gain_off_p->gain.r_ye.decimal; | ||
245 | regw(val, CRGAIN); | ||
246 | |||
247 | val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) | | ||
248 | gain_off_p->gain.gr_cy.decimal; | ||
249 | regw(val, CGRGAIN); | ||
250 | |||
251 | val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) | | ||
252 | gain_off_p->gain.gb_g.decimal; | ||
253 | regw(val, CGBGAIN); | ||
254 | |||
255 | val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) | | ||
256 | gain_off_p->gain.b_mg.decimal; | ||
257 | regw(val, CBGAIN); | ||
258 | |||
259 | regw(gain_off_p->offset, COFSTA); | ||
260 | } | ||
261 | |||
262 | static void isif_restore_defaults(void) | ||
263 | { | ||
264 | enum vpss_ccdc_source_sel source = VPSS_CCDCIN; | ||
265 | |||
266 | dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults..."); | ||
267 | isif_cfg.bayer.config_params = isif_config_defaults; | ||
268 | /* Enable clock to ISIF, IPIPEIF and BL */ | ||
269 | vpss_enable_clock(VPSS_CCDC_CLOCK, 1); | ||
270 | vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); | ||
271 | vpss_enable_clock(VPSS_BL_CLOCK, 1); | ||
272 | /* Set default offset and gain */ | ||
273 | isif_config_gain_offset(); | ||
274 | vpss_select_ccdc_source(source); | ||
275 | dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults..."); | ||
276 | } | ||
277 | |||
278 | static int isif_open(struct device *device) | ||
279 | { | ||
280 | isif_restore_defaults(); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* This function will configure the window size to be capture in ISIF reg */ | ||
285 | static void isif_setwin(struct v4l2_rect *image_win, | ||
286 | enum ccdc_frmfmt frm_fmt, int ppc) | ||
287 | { | ||
288 | int horz_start, horz_nr_pixels; | ||
289 | int vert_start, vert_nr_lines; | ||
290 | int mid_img = 0; | ||
291 | |||
292 | dev_dbg(isif_cfg.dev, "\nStarting isif_setwin..."); | ||
293 | /* | ||
294 | * ppc - per pixel count. indicates how many pixels per cell | ||
295 | * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. | ||
296 | * raw capture this is 1 | ||
297 | */ | ||
298 | horz_start = image_win->left << (ppc - 1); | ||
299 | horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1; | ||
300 | |||
301 | /* Writing the horizontal info into the registers */ | ||
302 | regw(horz_start & START_PX_HOR_MASK, SPH); | ||
303 | regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH); | ||
304 | vert_start = image_win->top; | ||
305 | |||
306 | if (frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
307 | vert_nr_lines = (image_win->height >> 1) - 1; | ||
308 | vert_start >>= 1; | ||
309 | /* To account for VD since line 0 doesn't have any data */ | ||
310 | vert_start += 1; | ||
311 | } else { | ||
312 | /* To account for VD since line 0 doesn't have any data */ | ||
313 | vert_start += 1; | ||
314 | vert_nr_lines = image_win->height - 1; | ||
315 | /* configure VDINT0 and VDINT1 */ | ||
316 | mid_img = vert_start + (image_win->height / 2); | ||
317 | regw(mid_img, VDINT1); | ||
318 | } | ||
319 | |||
320 | regw(0, VDINT0); | ||
321 | regw(vert_start & START_VER_ONE_MASK, SLV0); | ||
322 | regw(vert_start & START_VER_TWO_MASK, SLV1); | ||
323 | regw(vert_nr_lines & NUM_LINES_VER, LNV); | ||
324 | } | ||
325 | |||
326 | static void isif_config_bclamp(struct isif_black_clamp *bc) | ||
327 | { | ||
328 | u32 val; | ||
329 | |||
330 | /* | ||
331 | * DC Offset is always added to image data irrespective of bc enable | ||
332 | * status | ||
333 | */ | ||
334 | regw(bc->dc_offset, CLDCOFST); | ||
335 | |||
336 | if (bc->en) { | ||
337 | val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT; | ||
338 | |||
339 | /* Enable BC and horizontal clamp caculation paramaters */ | ||
340 | val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT); | ||
341 | |||
342 | regw(val, CLAMPCFG); | ||
343 | |||
344 | if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) { | ||
345 | /* | ||
346 | * Window count for calculation | ||
347 | * Base window selection | ||
348 | * pixel limit | ||
349 | * Horizontal size of window | ||
350 | * vertical size of the window | ||
351 | * Horizontal start position of the window | ||
352 | * Vertical start position of the window | ||
353 | */ | ||
354 | val = bc->horz.win_count_calc | | ||
355 | ((!!bc->horz.base_win_sel_calc) << | ||
356 | ISIF_HORZ_BC_WIN_SEL_SHIFT) | | ||
357 | ((!!bc->horz.clamp_pix_limit) << | ||
358 | ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | | ||
359 | (bc->horz.win_h_sz_calc << | ||
360 | ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | | ||
361 | (bc->horz.win_v_sz_calc << | ||
362 | ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); | ||
363 | regw(val, CLHWIN0); | ||
364 | |||
365 | regw(bc->horz.win_start_h_calc, CLHWIN1); | ||
366 | regw(bc->horz.win_start_v_calc, CLHWIN2); | ||
367 | } | ||
368 | |||
369 | /* vertical clamp caculation paramaters */ | ||
370 | |||
371 | /* Reset clamp value sel for previous line */ | ||
372 | val |= | ||
373 | (bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) | | ||
374 | (bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT); | ||
375 | regw(val, CLVWIN0); | ||
376 | |||
377 | /* Optical Black horizontal start position */ | ||
378 | regw(bc->vert.ob_start_h, CLVWIN1); | ||
379 | /* Optical Black vertical start position */ | ||
380 | regw(bc->vert.ob_start_v, CLVWIN2); | ||
381 | /* Optical Black vertical size for calculation */ | ||
382 | regw(bc->vert.ob_v_sz_calc, CLVWIN3); | ||
383 | /* Vertical start position for BC subtraction */ | ||
384 | regw(bc->vert_start_sub, CLSV); | ||
385 | } | ||
386 | } | ||
387 | |||
388 | static void isif_config_linearization(struct isif_linearize *linearize) | ||
389 | { | ||
390 | u32 val, i; | ||
391 | |||
392 | if (!linearize->en) { | ||
393 | regw(0, LINCFG0); | ||
394 | return; | ||
395 | } | ||
396 | |||
397 | /* shift value for correction & enable linearization (set lsb) */ | ||
398 | val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1; | ||
399 | regw(val, LINCFG0); | ||
400 | |||
401 | /* Scale factor */ | ||
402 | val = ((!!linearize->scale_fact.integer) << | ||
403 | ISIF_LIN_SCALE_FACT_INTEG_SHIFT) | | ||
404 | linearize->scale_fact.decimal; | ||
405 | regw(val, LINCFG1); | ||
406 | |||
407 | for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) { | ||
408 | if (i % 2) | ||
409 | regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1); | ||
410 | else | ||
411 | regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | static int isif_config_dfc(struct isif_dfc *vdfc) | ||
416 | { | ||
417 | /* initialize retries to loop for max ~ 250 usec */ | ||
418 | u32 val, count, retries = loops_per_jiffy / (4000/HZ); | ||
419 | int i; | ||
420 | |||
421 | if (!vdfc->en) | ||
422 | return 0; | ||
423 | |||
424 | /* Correction mode */ | ||
425 | val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT); | ||
426 | |||
427 | /* Correct whole line or partial */ | ||
428 | if (vdfc->corr_whole_line) | ||
429 | val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; | ||
430 | |||
431 | /* level shift value */ | ||
432 | val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT; | ||
433 | |||
434 | regw(val, DFCCTL); | ||
435 | |||
436 | /* Defect saturation level */ | ||
437 | regw(vdfc->def_sat_level, VDFSATLV); | ||
438 | |||
439 | regw(vdfc->table[0].pos_vert, DFCMEM0); | ||
440 | regw(vdfc->table[0].pos_horz, DFCMEM1); | ||
441 | if (vdfc->corr_mode == ISIF_VDFC_NORMAL || | ||
442 | vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { | ||
443 | regw(vdfc->table[0].level_at_pos, DFCMEM2); | ||
444 | regw(vdfc->table[0].level_up_pixels, DFCMEM3); | ||
445 | regw(vdfc->table[0].level_low_pixels, DFCMEM4); | ||
446 | } | ||
447 | |||
448 | /* set DFCMARST and set DFCMWR */ | ||
449 | val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1; | ||
450 | regw(val, DFCMEMCTL); | ||
451 | |||
452 | count = retries; | ||
453 | while (count && (regr(DFCMEMCTL) & 0x1)) | ||
454 | count--; | ||
455 | |||
456 | if (!count) { | ||
457 | dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n"); | ||
458 | return -1; | ||
459 | } | ||
460 | |||
461 | for (i = 1; i < vdfc->num_vdefects; i++) { | ||
462 | regw(vdfc->table[i].pos_vert, DFCMEM0); | ||
463 | regw(vdfc->table[i].pos_horz, DFCMEM1); | ||
464 | if (vdfc->corr_mode == ISIF_VDFC_NORMAL || | ||
465 | vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { | ||
466 | regw(vdfc->table[i].level_at_pos, DFCMEM2); | ||
467 | regw(vdfc->table[i].level_up_pixels, DFCMEM3); | ||
468 | regw(vdfc->table[i].level_low_pixels, DFCMEM4); | ||
469 | } | ||
470 | val = regr(DFCMEMCTL); | ||
471 | /* clear DFCMARST and set DFCMWR */ | ||
472 | val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); | ||
473 | val |= 1; | ||
474 | regw(val, DFCMEMCTL); | ||
475 | |||
476 | count = retries; | ||
477 | while (count && (regr(DFCMEMCTL) & 0x1)) | ||
478 | count--; | ||
479 | |||
480 | if (!count) { | ||
481 | dev_err(isif_cfg.dev, | ||
482 | "defect table write timeout !!!\n"); | ||
483 | return -1; | ||
484 | } | ||
485 | } | ||
486 | if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) { | ||
487 | /* Extra cycle needed */ | ||
488 | regw(0, DFCMEM0); | ||
489 | regw(0x1FFF, DFCMEM1); | ||
490 | regw(1, DFCMEMCTL); | ||
491 | } | ||
492 | |||
493 | /* enable VDFC */ | ||
494 | reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT), | ||
495 | DFCCTL); | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static void isif_config_csc(struct isif_df_csc *df_csc) | ||
500 | { | ||
501 | u32 val1 = 0, val2 = 0, i; | ||
502 | |||
503 | if (!df_csc->csc.en) { | ||
504 | regw(0, CSCCTL); | ||
505 | return; | ||
506 | } | ||
507 | for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) { | ||
508 | if ((i % 2) == 0) { | ||
509 | /* CSCM - LSB */ | ||
510 | val1 = (df_csc->csc.coeff[i].integer << | ||
511 | ISIF_CSC_COEF_INTEG_SHIFT) | | ||
512 | df_csc->csc.coeff[i].decimal; | ||
513 | } else { | ||
514 | |||
515 | /* CSCM - MSB */ | ||
516 | val2 = (df_csc->csc.coeff[i].integer << | ||
517 | ISIF_CSC_COEF_INTEG_SHIFT) | | ||
518 | df_csc->csc.coeff[i].decimal; | ||
519 | val2 <<= ISIF_CSCM_MSB_SHIFT; | ||
520 | val2 |= val1; | ||
521 | regw(val2, (CSCM0 + ((i - 1) << 1))); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | /* program the active area */ | ||
526 | regw(df_csc->start_pix, FMTSPH); | ||
527 | /* | ||
528 | * one extra pixel as required for CSC. Actually number of | ||
529 | * pixel - 1 should be configured in this register. So we | ||
530 | * need to subtract 1 before writing to FMTSPH, but we will | ||
531 | * not do this since csc requires one extra pixel | ||
532 | */ | ||
533 | regw(df_csc->num_pixels, FMTLNH); | ||
534 | regw(df_csc->start_line, FMTSLV); | ||
535 | /* | ||
536 | * one extra line as required for CSC. See reason documented for | ||
537 | * num_pixels | ||
538 | */ | ||
539 | regw(df_csc->num_lines, FMTLNV); | ||
540 | |||
541 | /* Enable CSC */ | ||
542 | regw(1, CSCCTL); | ||
543 | } | ||
544 | |||
545 | static int isif_config_raw(void) | ||
546 | { | ||
547 | struct isif_params_raw *params = &isif_cfg.bayer; | ||
548 | struct isif_config_params_raw *module_params = | ||
549 | &isif_cfg.bayer.config_params; | ||
550 | struct vpss_pg_frame_size frame_size; | ||
551 | struct vpss_sync_pol sync; | ||
552 | u32 val; | ||
553 | |||
554 | dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n"); | ||
555 | |||
556 | /* | ||
557 | * Configure CCDCFG register:- | ||
558 | * Set CCD Not to swap input since input is RAW data | ||
559 | * Set FID detection function to Latch at V-Sync | ||
560 | * Set WENLOG - isif valid area | ||
561 | * Set TRGSEL | ||
562 | * Set EXTRG | ||
563 | * Packed to 8 or 16 bits | ||
564 | */ | ||
565 | |||
566 | val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | | ||
567 | ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | | ||
568 | ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack; | ||
569 | |||
570 | dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val); | ||
571 | regw(val, CCDCFG); | ||
572 | |||
573 | /* | ||
574 | * Configure the vertical sync polarity(MODESET.VDPOL) | ||
575 | * Configure the horizontal sync polarity (MODESET.HDPOL) | ||
576 | * Configure frame id polarity (MODESET.FLDPOL) | ||
577 | * Configure data polarity | ||
578 | * Configure External WEN Selection | ||
579 | * Configure frame format(progressive or interlace) | ||
580 | * Configure pixel format (Input mode) | ||
581 | * Configure the data shift | ||
582 | */ | ||
583 | |||
584 | val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) | | ||
585 | (params->hd_pol << ISIF_HD_POL_SHIFT) | | ||
586 | (params->fid_pol << ISIF_FID_POL_SHIFT) | | ||
587 | (ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) | | ||
588 | (ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) | | ||
589 | (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | | ||
590 | (params->pix_fmt << ISIF_INPUT_SHIFT) | | ||
591 | (params->config_params.data_shift << ISIF_DATASFT_SHIFT); | ||
592 | |||
593 | regw(val, MODESET); | ||
594 | dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val); | ||
595 | |||
596 | /* | ||
597 | * Configure GAMMAWD register | ||
598 | * CFA pattern setting | ||
599 | */ | ||
600 | val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT; | ||
601 | |||
602 | /* Gamma msb */ | ||
603 | if (module_params->compress.alg == ISIF_ALAW) | ||
604 | val |= ISIF_ALAW_ENABLE; | ||
605 | |||
606 | val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); | ||
607 | regw(val, CGAMMAWD); | ||
608 | |||
609 | /* Configure DPCM compression settings */ | ||
610 | if (module_params->compress.alg == ISIF_DPCM) { | ||
611 | val = BIT(ISIF_DPCM_EN_SHIFT) | | ||
612 | (module_params->compress.pred << | ||
613 | ISIF_DPCM_PREDICTOR_SHIFT); | ||
614 | } | ||
615 | |||
616 | regw(val, MISC); | ||
617 | |||
618 | /* Configure Gain & Offset */ | ||
619 | isif_config_gain_offset(); | ||
620 | |||
621 | /* Configure Color pattern */ | ||
622 | val = (params->config_params.col_pat_field0.olop) | | ||
623 | (params->config_params.col_pat_field0.olep << 2) | | ||
624 | (params->config_params.col_pat_field0.elop << 4) | | ||
625 | (params->config_params.col_pat_field0.elep << 6) | | ||
626 | (params->config_params.col_pat_field1.olop << 8) | | ||
627 | (params->config_params.col_pat_field1.olep << 10) | | ||
628 | (params->config_params.col_pat_field1.elop << 12) | | ||
629 | (params->config_params.col_pat_field1.elep << 14); | ||
630 | regw(val, CCOLP); | ||
631 | dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val); | ||
632 | |||
633 | /* Configure HSIZE register */ | ||
634 | val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT; | ||
635 | |||
636 | /* calculate line offset in 32 bytes based on pack value */ | ||
637 | if (isif_cfg.data_pack == ISIF_PACK_8BIT) | ||
638 | val |= ((params->win.width + 31) >> 5); | ||
639 | else if (isif_cfg.data_pack == ISIF_PACK_12BIT) | ||
640 | val |= (((params->win.width + | ||
641 | (params->win.width >> 2)) + 31) >> 5); | ||
642 | else | ||
643 | val |= (((params->win.width * 2) + 31) >> 5); | ||
644 | regw(val, HSIZE); | ||
645 | |||
646 | /* Configure SDOFST register */ | ||
647 | if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
648 | if (params->image_invert_en) { | ||
649 | /* For interlace inverse mode */ | ||
650 | regw(0x4B6D, SDOFST); | ||
651 | dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n"); | ||
652 | } else { | ||
653 | /* For interlace non inverse mode */ | ||
654 | regw(0x0B6D, SDOFST); | ||
655 | dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n"); | ||
656 | } | ||
657 | } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) { | ||
658 | if (params->image_invert_en) { | ||
659 | /* For progressive inverse mode */ | ||
660 | regw(0x4000, SDOFST); | ||
661 | dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n"); | ||
662 | } else { | ||
663 | /* For progressive non inverse mode */ | ||
664 | regw(0x0000, SDOFST); | ||
665 | dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n"); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | /* Configure video window */ | ||
670 | isif_setwin(¶ms->win, params->frm_fmt, 1); | ||
671 | |||
672 | /* Configure Black Clamp */ | ||
673 | isif_config_bclamp(&module_params->bclamp); | ||
674 | |||
675 | /* Configure Vertical Defection Pixel Correction */ | ||
676 | if (isif_config_dfc(&module_params->dfc) < 0) | ||
677 | return -EFAULT; | ||
678 | |||
679 | if (!module_params->df_csc.df_or_csc) | ||
680 | /* Configure Color Space Conversion */ | ||
681 | isif_config_csc(&module_params->df_csc); | ||
682 | |||
683 | isif_config_linearization(&module_params->linearize); | ||
684 | |||
685 | /* Configure Culling */ | ||
686 | isif_config_culling(&module_params->culling); | ||
687 | |||
688 | /* Configure horizontal and vertical offsets(DFC,LSC,Gain) */ | ||
689 | regw(module_params->horz_offset, DATAHOFST); | ||
690 | regw(module_params->vert_offset, DATAVOFST); | ||
691 | |||
692 | /* Setup test pattern if enabled */ | ||
693 | if (params->config_params.test_pat_gen) { | ||
694 | /* Use the HD/VD pol settings from user */ | ||
695 | sync.ccdpg_hdpol = params->hd_pol; | ||
696 | sync.ccdpg_vdpol = params->vd_pol; | ||
697 | dm365_vpss_set_sync_pol(sync); | ||
698 | frame_size.hlpfr = isif_cfg.bayer.win.width; | ||
699 | frame_size.pplen = isif_cfg.bayer.win.height; | ||
700 | dm365_vpss_set_pg_frame_size(frame_size); | ||
701 | vpss_select_ccdc_source(VPSS_PGLPBK); | ||
702 | } | ||
703 | |||
704 | dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n"); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static int isif_set_buftype(enum ccdc_buftype buf_type) | ||
709 | { | ||
710 | if (isif_cfg.if_type == VPFE_RAW_BAYER) | ||
711 | isif_cfg.bayer.buf_type = buf_type; | ||
712 | else | ||
713 | isif_cfg.ycbcr.buf_type = buf_type; | ||
714 | |||
715 | return 0; | ||
716 | |||
717 | } | ||
718 | static enum ccdc_buftype isif_get_buftype(void) | ||
719 | { | ||
720 | if (isif_cfg.if_type == VPFE_RAW_BAYER) | ||
721 | return isif_cfg.bayer.buf_type; | ||
722 | |||
723 | return isif_cfg.ycbcr.buf_type; | ||
724 | } | ||
725 | |||
726 | static int isif_enum_pix(u32 *pix, int i) | ||
727 | { | ||
728 | int ret = -EINVAL; | ||
729 | |||
730 | if (isif_cfg.if_type == VPFE_RAW_BAYER) { | ||
731 | if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) { | ||
732 | *pix = isif_raw_bayer_pix_formats[i]; | ||
733 | ret = 0; | ||
734 | } | ||
735 | } else { | ||
736 | if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) { | ||
737 | *pix = isif_raw_yuv_pix_formats[i]; | ||
738 | ret = 0; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | return ret; | ||
743 | } | ||
744 | |||
745 | static int isif_set_pixel_format(unsigned int pixfmt) | ||
746 | { | ||
747 | if (isif_cfg.if_type == VPFE_RAW_BAYER) { | ||
748 | if (pixfmt == V4L2_PIX_FMT_SBGGR8) { | ||
749 | if ((isif_cfg.bayer.config_params.compress.alg != | ||
750 | ISIF_ALAW) && | ||
751 | (isif_cfg.bayer.config_params.compress.alg != | ||
752 | ISIF_DPCM)) { | ||
753 | dev_dbg(isif_cfg.dev, | ||
754 | "Either configure A-Law or DPCM\n"); | ||
755 | return -EINVAL; | ||
756 | } | ||
757 | isif_cfg.data_pack = ISIF_PACK_8BIT; | ||
758 | } else if (pixfmt == V4L2_PIX_FMT_SBGGR16) { | ||
759 | isif_cfg.bayer.config_params.compress.alg = | ||
760 | ISIF_NO_COMPRESSION; | ||
761 | isif_cfg.data_pack = ISIF_PACK_16BIT; | ||
762 | } else | ||
763 | return -EINVAL; | ||
764 | isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; | ||
765 | } else { | ||
766 | if (pixfmt == V4L2_PIX_FMT_YUYV) | ||
767 | isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR; | ||
768 | else if (pixfmt == V4L2_PIX_FMT_UYVY) | ||
769 | isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; | ||
770 | else | ||
771 | return -EINVAL; | ||
772 | isif_cfg.data_pack = ISIF_PACK_8BIT; | ||
773 | } | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | static u32 isif_get_pixel_format(void) | ||
778 | { | ||
779 | u32 pixfmt; | ||
780 | |||
781 | if (isif_cfg.if_type == VPFE_RAW_BAYER) | ||
782 | if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW || | ||
783 | isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM) | ||
784 | pixfmt = V4L2_PIX_FMT_SBGGR8; | ||
785 | else | ||
786 | pixfmt = V4L2_PIX_FMT_SBGGR16; | ||
787 | else { | ||
788 | if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR) | ||
789 | pixfmt = V4L2_PIX_FMT_YUYV; | ||
790 | else | ||
791 | pixfmt = V4L2_PIX_FMT_UYVY; | ||
792 | } | ||
793 | return pixfmt; | ||
794 | } | ||
795 | |||
796 | static int isif_set_image_window(struct v4l2_rect *win) | ||
797 | { | ||
798 | if (isif_cfg.if_type == VPFE_RAW_BAYER) { | ||
799 | isif_cfg.bayer.win.top = win->top; | ||
800 | isif_cfg.bayer.win.left = win->left; | ||
801 | isif_cfg.bayer.win.width = win->width; | ||
802 | isif_cfg.bayer.win.height = win->height; | ||
803 | } else { | ||
804 | isif_cfg.ycbcr.win.top = win->top; | ||
805 | isif_cfg.ycbcr.win.left = win->left; | ||
806 | isif_cfg.ycbcr.win.width = win->width; | ||
807 | isif_cfg.ycbcr.win.height = win->height; | ||
808 | } | ||
809 | return 0; | ||
810 | } | ||
811 | |||
812 | static void isif_get_image_window(struct v4l2_rect *win) | ||
813 | { | ||
814 | if (isif_cfg.if_type == VPFE_RAW_BAYER) | ||
815 | *win = isif_cfg.bayer.win; | ||
816 | else | ||
817 | *win = isif_cfg.ycbcr.win; | ||
818 | } | ||
819 | |||
820 | static unsigned int isif_get_line_length(void) | ||
821 | { | ||
822 | unsigned int len; | ||
823 | |||
824 | if (isif_cfg.if_type == VPFE_RAW_BAYER) { | ||
825 | if (isif_cfg.data_pack == ISIF_PACK_8BIT) | ||
826 | len = ((isif_cfg.bayer.win.width)); | ||
827 | else if (isif_cfg.data_pack == ISIF_PACK_12BIT) | ||
828 | len = (((isif_cfg.bayer.win.width * 2) + | ||
829 | (isif_cfg.bayer.win.width >> 2))); | ||
830 | else | ||
831 | len = (((isif_cfg.bayer.win.width * 2))); | ||
832 | } else | ||
833 | len = (((isif_cfg.ycbcr.win.width * 2))); | ||
834 | return ALIGN(len, 32); | ||
835 | } | ||
836 | |||
837 | static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt) | ||
838 | { | ||
839 | if (isif_cfg.if_type == VPFE_RAW_BAYER) | ||
840 | isif_cfg.bayer.frm_fmt = frm_fmt; | ||
841 | else | ||
842 | isif_cfg.ycbcr.frm_fmt = frm_fmt; | ||
843 | return 0; | ||
844 | } | ||
845 | static enum ccdc_frmfmt isif_get_frame_format(void) | ||
846 | { | ||
847 | if (isif_cfg.if_type == VPFE_RAW_BAYER) | ||
848 | return isif_cfg.bayer.frm_fmt; | ||
849 | return isif_cfg.ycbcr.frm_fmt; | ||
850 | } | ||
851 | |||
852 | static int isif_getfid(void) | ||
853 | { | ||
854 | return (regr(MODESET) >> 15) & 0x1; | ||
855 | } | ||
856 | |||
857 | /* misc operations */ | ||
858 | static void isif_setfbaddr(unsigned long addr) | ||
859 | { | ||
860 | regw((addr >> 21) & 0x07ff, CADU); | ||
861 | regw((addr >> 5) & 0x0ffff, CADL); | ||
862 | } | ||
863 | |||
864 | static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) | ||
865 | { | ||
866 | isif_cfg.if_type = params->if_type; | ||
867 | |||
868 | switch (params->if_type) { | ||
869 | case VPFE_BT656: | ||
870 | case VPFE_BT656_10BIT: | ||
871 | case VPFE_YCBCR_SYNC_8: | ||
872 | isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT; | ||
873 | isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; | ||
874 | break; | ||
875 | case VPFE_BT1120: | ||
876 | case VPFE_YCBCR_SYNC_16: | ||
877 | isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT; | ||
878 | isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY; | ||
879 | break; | ||
880 | case VPFE_RAW_BAYER: | ||
881 | isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; | ||
882 | break; | ||
883 | default: | ||
884 | dev_dbg(isif_cfg.dev, "Invalid interface type\n"); | ||
885 | return -EINVAL; | ||
886 | } | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | /* This function will configure ISIF for YCbCr parameters. */ | ||
892 | static int isif_config_ycbcr(void) | ||
893 | { | ||
894 | struct isif_ycbcr_config *params = &isif_cfg.ycbcr; | ||
895 | struct vpss_pg_frame_size frame_size; | ||
896 | u32 modeset = 0, ccdcfg = 0; | ||
897 | struct vpss_sync_pol sync; | ||
898 | |||
899 | dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); | ||
900 | |||
901 | /* configure pixel format or input mode */ | ||
902 | modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) | | ||
903 | (params->frm_fmt << ISIF_FRM_FMT_SHIFT) | | ||
904 | (params->fid_pol << ISIF_FID_POL_SHIFT) | | ||
905 | (params->hd_pol << ISIF_HD_POL_SHIFT) | | ||
906 | (params->vd_pol << ISIF_VD_POL_SHIFT); | ||
907 | |||
908 | /* pack the data to 8-bit ISIFCFG */ | ||
909 | switch (isif_cfg.if_type) { | ||
910 | case VPFE_BT656: | ||
911 | if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { | ||
912 | dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); | ||
913 | return -EINVAL; | ||
914 | } | ||
915 | modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT); | ||
916 | regw(3, REC656IF); | ||
917 | ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR; | ||
918 | break; | ||
919 | case VPFE_BT656_10BIT: | ||
920 | if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { | ||
921 | dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); | ||
922 | return -EINVAL; | ||
923 | } | ||
924 | /* setup BT.656, embedded sync */ | ||
925 | regw(3, REC656IF); | ||
926 | /* enable 10 bit mode in ccdcfg */ | ||
927 | ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR | | ||
928 | ISIF_BW656_ENABLE; | ||
929 | break; | ||
930 | case VPFE_BT1120: | ||
931 | if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { | ||
932 | dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); | ||
933 | return -EINVAL; | ||
934 | } | ||
935 | regw(3, REC656IF); | ||
936 | break; | ||
937 | |||
938 | case VPFE_YCBCR_SYNC_8: | ||
939 | ccdcfg |= ISIF_DATA_PACK8; | ||
940 | ccdcfg |= ISIF_YCINSWP_YCBCR; | ||
941 | if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) { | ||
942 | dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); | ||
943 | return -EINVAL; | ||
944 | } | ||
945 | break; | ||
946 | case VPFE_YCBCR_SYNC_16: | ||
947 | if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) { | ||
948 | dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n"); | ||
949 | return -EINVAL; | ||
950 | } | ||
951 | break; | ||
952 | default: | ||
953 | /* should never come here */ | ||
954 | dev_dbg(isif_cfg.dev, "Invalid interface type\n"); | ||
955 | return -EINVAL; | ||
956 | } | ||
957 | |||
958 | regw(modeset, MODESET); | ||
959 | |||
960 | /* Set up pix order */ | ||
961 | ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT; | ||
962 | |||
963 | regw(ccdcfg, CCDCFG); | ||
964 | |||
965 | /* configure video window */ | ||
966 | if ((isif_cfg.if_type == VPFE_BT1120) || | ||
967 | (isif_cfg.if_type == VPFE_YCBCR_SYNC_16)) | ||
968 | isif_setwin(¶ms->win, params->frm_fmt, 1); | ||
969 | else | ||
970 | isif_setwin(¶ms->win, params->frm_fmt, 2); | ||
971 | |||
972 | /* | ||
973 | * configure the horizontal line offset | ||
974 | * this is done by rounding up width to a multiple of 16 pixels | ||
975 | * and multiply by two to account for y:cb:cr 4:2:2 data | ||
976 | */ | ||
977 | regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE); | ||
978 | |||
979 | /* configure the memory line offset */ | ||
980 | if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) && | ||
981 | (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)) | ||
982 | /* two fields are interleaved in memory */ | ||
983 | regw(0x00000249, SDOFST); | ||
984 | |||
985 | /* Setup test pattern if enabled */ | ||
986 | if (isif_cfg.bayer.config_params.test_pat_gen) { | ||
987 | sync.ccdpg_hdpol = params->hd_pol; | ||
988 | sync.ccdpg_vdpol = params->vd_pol; | ||
989 | dm365_vpss_set_sync_pol(sync); | ||
990 | dm365_vpss_set_pg_frame_size(frame_size); | ||
991 | } | ||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | static int isif_configure(void) | ||
996 | { | ||
997 | if (isif_cfg.if_type == VPFE_RAW_BAYER) | ||
998 | return isif_config_raw(); | ||
999 | return isif_config_ycbcr(); | ||
1000 | } | ||
1001 | |||
1002 | static int isif_close(struct device *device) | ||
1003 | { | ||
1004 | /* copy defaults to module params */ | ||
1005 | isif_cfg.bayer.config_params = isif_config_defaults; | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static struct ccdc_hw_device isif_hw_dev = { | ||
1010 | .name = "ISIF", | ||
1011 | .owner = THIS_MODULE, | ||
1012 | .hw_ops = { | ||
1013 | .open = isif_open, | ||
1014 | .close = isif_close, | ||
1015 | .enable = isif_enable, | ||
1016 | .enable_out_to_sdram = isif_enable_output_to_sdram, | ||
1017 | .set_hw_if_params = isif_set_hw_if_params, | ||
1018 | .configure = isif_configure, | ||
1019 | .set_buftype = isif_set_buftype, | ||
1020 | .get_buftype = isif_get_buftype, | ||
1021 | .enum_pix = isif_enum_pix, | ||
1022 | .set_pixel_format = isif_set_pixel_format, | ||
1023 | .get_pixel_format = isif_get_pixel_format, | ||
1024 | .set_frame_format = isif_set_frame_format, | ||
1025 | .get_frame_format = isif_get_frame_format, | ||
1026 | .set_image_window = isif_set_image_window, | ||
1027 | .get_image_window = isif_get_image_window, | ||
1028 | .get_line_length = isif_get_line_length, | ||
1029 | .setfbaddr = isif_setfbaddr, | ||
1030 | .getfid = isif_getfid, | ||
1031 | }, | ||
1032 | }; | ||
1033 | |||
1034 | static int __init isif_probe(struct platform_device *pdev) | ||
1035 | { | ||
1036 | void (*setup_pinmux)(void); | ||
1037 | struct resource *res; | ||
1038 | void *__iomem addr; | ||
1039 | int status = 0, i; | ||
1040 | |||
1041 | /* | ||
1042 | * first try to register with vpfe. If not correct platform, then we | ||
1043 | * don't have to iomap | ||
1044 | */ | ||
1045 | status = vpfe_register_ccdc_device(&isif_hw_dev); | ||
1046 | if (status < 0) | ||
1047 | return status; | ||
1048 | |||
1049 | /* Get and enable Master clock */ | ||
1050 | isif_cfg.mclk = clk_get(&pdev->dev, "master"); | ||
1051 | if (IS_ERR(isif_cfg.mclk)) { | ||
1052 | status = PTR_ERR(isif_cfg.mclk); | ||
1053 | goto fail_mclk; | ||
1054 | } | ||
1055 | if (clk_enable(isif_cfg.mclk)) { | ||
1056 | status = -ENODEV; | ||
1057 | goto fail_mclk; | ||
1058 | } | ||
1059 | |||
1060 | /* Platform data holds setup_pinmux function ptr */ | ||
1061 | if (NULL == pdev->dev.platform_data) { | ||
1062 | status = -ENODEV; | ||
1063 | goto fail_mclk; | ||
1064 | } | ||
1065 | setup_pinmux = pdev->dev.platform_data; | ||
1066 | /* | ||
1067 | * setup Mux configuration for ccdc which may be different for | ||
1068 | * different SoCs using this CCDC | ||
1069 | */ | ||
1070 | setup_pinmux(); | ||
1071 | |||
1072 | i = 0; | ||
1073 | /* Get the ISIF base address, linearization table0 and table1 addr. */ | ||
1074 | while (i < 3) { | ||
1075 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
1076 | if (!res) { | ||
1077 | status = -ENODEV; | ||
1078 | goto fail_nobase_res; | ||
1079 | } | ||
1080 | res = request_mem_region(res->start, resource_size(res), | ||
1081 | res->name); | ||
1082 | if (!res) { | ||
1083 | status = -EBUSY; | ||
1084 | goto fail_nobase_res; | ||
1085 | } | ||
1086 | addr = ioremap_nocache(res->start, resource_size(res)); | ||
1087 | if (!addr) { | ||
1088 | status = -ENOMEM; | ||
1089 | goto fail_base_iomap; | ||
1090 | } | ||
1091 | switch (i) { | ||
1092 | case 0: | ||
1093 | /* ISIF base address */ | ||
1094 | isif_cfg.base_addr = addr; | ||
1095 | break; | ||
1096 | case 1: | ||
1097 | /* ISIF linear tbl0 address */ | ||
1098 | isif_cfg.linear_tbl0_addr = addr; | ||
1099 | break; | ||
1100 | default: | ||
1101 | /* ISIF linear tbl0 address */ | ||
1102 | isif_cfg.linear_tbl1_addr = addr; | ||
1103 | break; | ||
1104 | } | ||
1105 | i++; | ||
1106 | } | ||
1107 | isif_cfg.dev = &pdev->dev; | ||
1108 | |||
1109 | printk(KERN_NOTICE "%s is registered with vpfe.\n", | ||
1110 | isif_hw_dev.name); | ||
1111 | return 0; | ||
1112 | fail_base_iomap: | ||
1113 | release_mem_region(res->start, resource_size(res)); | ||
1114 | i--; | ||
1115 | fail_nobase_res: | ||
1116 | if (isif_cfg.base_addr) | ||
1117 | iounmap(isif_cfg.base_addr); | ||
1118 | if (isif_cfg.linear_tbl0_addr) | ||
1119 | iounmap(isif_cfg.linear_tbl0_addr); | ||
1120 | |||
1121 | while (i >= 0) { | ||
1122 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
1123 | release_mem_region(res->start, resource_size(res)); | ||
1124 | i--; | ||
1125 | } | ||
1126 | fail_mclk: | ||
1127 | clk_put(isif_cfg.mclk); | ||
1128 | vpfe_unregister_ccdc_device(&isif_hw_dev); | ||
1129 | return status; | ||
1130 | } | ||
1131 | |||
1132 | static int isif_remove(struct platform_device *pdev) | ||
1133 | { | ||
1134 | struct resource *res; | ||
1135 | int i = 0; | ||
1136 | |||
1137 | iounmap(isif_cfg.base_addr); | ||
1138 | iounmap(isif_cfg.linear_tbl0_addr); | ||
1139 | iounmap(isif_cfg.linear_tbl1_addr); | ||
1140 | while (i < 3) { | ||
1141 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
1142 | if (res) | ||
1143 | release_mem_region(res->start, resource_size(res)); | ||
1144 | i++; | ||
1145 | } | ||
1146 | vpfe_unregister_ccdc_device(&isif_hw_dev); | ||
1147 | return 0; | ||
1148 | } | ||
1149 | |||
1150 | static struct platform_driver isif_driver = { | ||
1151 | .driver = { | ||
1152 | .name = "isif", | ||
1153 | .owner = THIS_MODULE, | ||
1154 | }, | ||
1155 | .remove = __devexit_p(isif_remove), | ||
1156 | .probe = isif_probe, | ||
1157 | }; | ||
1158 | |||
1159 | static int __init isif_init(void) | ||
1160 | { | ||
1161 | return platform_driver_register(&isif_driver); | ||
1162 | } | ||
1163 | |||
1164 | static void isif_exit(void) | ||
1165 | { | ||
1166 | platform_driver_unregister(&isif_driver); | ||
1167 | } | ||
1168 | |||
1169 | module_init(isif_init); | ||
1170 | module_exit(isif_exit); | ||
1171 | |||
1172 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/davinci/isif_regs.h b/drivers/media/video/davinci/isif_regs.h new file mode 100644 index 00000000000..aa69a463c12 --- /dev/null +++ b/drivers/media/video/davinci/isif_regs.h | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ISIF_REGS_H | ||
19 | #define _ISIF_REGS_H | ||
20 | |||
21 | /* ISIF registers relative offsets */ | ||
22 | #define SYNCEN 0x00 | ||
23 | #define MODESET 0x04 | ||
24 | #define HDW 0x08 | ||
25 | #define VDW 0x0c | ||
26 | #define PPLN 0x10 | ||
27 | #define LPFR 0x14 | ||
28 | #define SPH 0x18 | ||
29 | #define LNH 0x1c | ||
30 | #define SLV0 0x20 | ||
31 | #define SLV1 0x24 | ||
32 | #define LNV 0x28 | ||
33 | #define CULH 0x2c | ||
34 | #define CULV 0x30 | ||
35 | #define HSIZE 0x34 | ||
36 | #define SDOFST 0x38 | ||
37 | #define CADU 0x3c | ||
38 | #define CADL 0x40 | ||
39 | #define LINCFG0 0x44 | ||
40 | #define LINCFG1 0x48 | ||
41 | #define CCOLP 0x4c | ||
42 | #define CRGAIN 0x50 | ||
43 | #define CGRGAIN 0x54 | ||
44 | #define CGBGAIN 0x58 | ||
45 | #define CBGAIN 0x5c | ||
46 | #define COFSTA 0x60 | ||
47 | #define FLSHCFG0 0x64 | ||
48 | #define FLSHCFG1 0x68 | ||
49 | #define FLSHCFG2 0x6c | ||
50 | #define VDINT0 0x70 | ||
51 | #define VDINT1 0x74 | ||
52 | #define VDINT2 0x78 | ||
53 | #define MISC 0x7c | ||
54 | #define CGAMMAWD 0x80 | ||
55 | #define REC656IF 0x84 | ||
56 | #define CCDCFG 0x88 | ||
57 | /***************************************************** | ||
58 | * Defect Correction registers | ||
59 | *****************************************************/ | ||
60 | #define DFCCTL 0x8c | ||
61 | #define VDFSATLV 0x90 | ||
62 | #define DFCMEMCTL 0x94 | ||
63 | #define DFCMEM0 0x98 | ||
64 | #define DFCMEM1 0x9c | ||
65 | #define DFCMEM2 0xa0 | ||
66 | #define DFCMEM3 0xa4 | ||
67 | #define DFCMEM4 0xa8 | ||
68 | /**************************************************** | ||
69 | * Black Clamp registers | ||
70 | ****************************************************/ | ||
71 | #define CLAMPCFG 0xac | ||
72 | #define CLDCOFST 0xb0 | ||
73 | #define CLSV 0xb4 | ||
74 | #define CLHWIN0 0xb8 | ||
75 | #define CLHWIN1 0xbc | ||
76 | #define CLHWIN2 0xc0 | ||
77 | #define CLVRV 0xc4 | ||
78 | #define CLVWIN0 0xc8 | ||
79 | #define CLVWIN1 0xcc | ||
80 | #define CLVWIN2 0xd0 | ||
81 | #define CLVWIN3 0xd4 | ||
82 | /**************************************************** | ||
83 | * Lense Shading Correction | ||
84 | ****************************************************/ | ||
85 | #define DATAHOFST 0xd8 | ||
86 | #define DATAVOFST 0xdc | ||
87 | #define LSCHVAL 0xe0 | ||
88 | #define LSCVVAL 0xe4 | ||
89 | #define TWODLSCCFG 0xe8 | ||
90 | #define TWODLSCOFST 0xec | ||
91 | #define TWODLSCINI 0xf0 | ||
92 | #define TWODLSCGRBU 0xf4 | ||
93 | #define TWODLSCGRBL 0xf8 | ||
94 | #define TWODLSCGROF 0xfc | ||
95 | #define TWODLSCORBU 0x100 | ||
96 | #define TWODLSCORBL 0x104 | ||
97 | #define TWODLSCOROF 0x108 | ||
98 | #define TWODLSCIRQEN 0x10c | ||
99 | #define TWODLSCIRQST 0x110 | ||
100 | /**************************************************** | ||
101 | * Data formatter | ||
102 | ****************************************************/ | ||
103 | #define FMTCFG 0x114 | ||
104 | #define FMTPLEN 0x118 | ||
105 | #define FMTSPH 0x11c | ||
106 | #define FMTLNH 0x120 | ||
107 | #define FMTSLV 0x124 | ||
108 | #define FMTLNV 0x128 | ||
109 | #define FMTRLEN 0x12c | ||
110 | #define FMTHCNT 0x130 | ||
111 | #define FMTAPTR_BASE 0x134 | ||
112 | /* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ | ||
113 | #define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) | ||
114 | #define FMTPGMVF0 0x174 | ||
115 | #define FMTPGMVF1 0x178 | ||
116 | #define FMTPGMAPU0 0x17c | ||
117 | #define FMTPGMAPU1 0x180 | ||
118 | #define FMTPGMAPS0 0x184 | ||
119 | #define FMTPGMAPS1 0x188 | ||
120 | #define FMTPGMAPS2 0x18c | ||
121 | #define FMTPGMAPS3 0x190 | ||
122 | #define FMTPGMAPS4 0x194 | ||
123 | #define FMTPGMAPS5 0x198 | ||
124 | #define FMTPGMAPS6 0x19c | ||
125 | #define FMTPGMAPS7 0x1a0 | ||
126 | /************************************************ | ||
127 | * Color Space Converter | ||
128 | ************************************************/ | ||
129 | #define CSCCTL 0x1a4 | ||
130 | #define CSCM0 0x1a8 | ||
131 | #define CSCM1 0x1ac | ||
132 | #define CSCM2 0x1b0 | ||
133 | #define CSCM3 0x1b4 | ||
134 | #define CSCM4 0x1b8 | ||
135 | #define CSCM5 0x1bc | ||
136 | #define CSCM6 0x1c0 | ||
137 | #define CSCM7 0x1c4 | ||
138 | #define OBWIN0 0x1c8 | ||
139 | #define OBWIN1 0x1cc | ||
140 | #define OBWIN2 0x1d0 | ||
141 | #define OBWIN3 0x1d4 | ||
142 | #define OBVAL0 0x1d8 | ||
143 | #define OBVAL1 0x1dc | ||
144 | #define OBVAL2 0x1e0 | ||
145 | #define OBVAL3 0x1e4 | ||
146 | #define OBVAL4 0x1e8 | ||
147 | #define OBVAL5 0x1ec | ||
148 | #define OBVAL6 0x1f0 | ||
149 | #define OBVAL7 0x1f4 | ||
150 | #define CLKCTL 0x1f8 | ||
151 | |||
152 | /* Masks & Shifts below */ | ||
153 | #define START_PX_HOR_MASK 0x7FFF | ||
154 | #define NUM_PX_HOR_MASK 0x7FFF | ||
155 | #define START_VER_ONE_MASK 0x7FFF | ||
156 | #define START_VER_TWO_MASK 0x7FFF | ||
157 | #define NUM_LINES_VER 0x7FFF | ||
158 | |||
159 | /* gain - offset masks */ | ||
160 | #define GAIN_INTEGER_SHIFT 9 | ||
161 | #define OFFSET_MASK 0xFFF | ||
162 | #define GAIN_SDRAM_EN_SHIFT 12 | ||
163 | #define GAIN_IPIPE_EN_SHIFT 13 | ||
164 | #define GAIN_H3A_EN_SHIFT 14 | ||
165 | #define OFST_SDRAM_EN_SHIFT 8 | ||
166 | #define OFST_IPIPE_EN_SHIFT 9 | ||
167 | #define OFST_H3A_EN_SHIFT 10 | ||
168 | #define GAIN_OFFSET_EN_MASK 0x7700 | ||
169 | |||
170 | /* Culling */ | ||
171 | #define CULL_PAT_EVEN_LINE_SHIFT 8 | ||
172 | |||
173 | /* CCDCFG register */ | ||
174 | #define ISIF_YCINSWP_RAW (0x00 << 4) | ||
175 | #define ISIF_YCINSWP_YCBCR (0x01 << 4) | ||
176 | #define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) | ||
177 | #define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) | ||
178 | #define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) | ||
179 | #define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) | ||
180 | #define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) | ||
181 | #define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) | ||
182 | #define ISIF_DATA_PACK_MASK 3 | ||
183 | #define ISIF_DATA_PACK16 0 | ||
184 | #define ISIF_DATA_PACK12 1 | ||
185 | #define ISIF_DATA_PACK8 2 | ||
186 | #define ISIF_PIX_ORDER_SHIFT 11 | ||
187 | #define ISIF_BW656_ENABLE (0x01 << 5) | ||
188 | |||
189 | /* MODESET registers */ | ||
190 | #define ISIF_VDHDOUT_INPUT (0x00 << 0) | ||
191 | #define ISIF_INPUT_SHIFT 12 | ||
192 | #define ISIF_RAW_INPUT_MODE 0 | ||
193 | #define ISIF_FID_POL_SHIFT 4 | ||
194 | #define ISIF_HD_POL_SHIFT 3 | ||
195 | #define ISIF_VD_POL_SHIFT 2 | ||
196 | #define ISIF_DATAPOL_NORMAL 0 | ||
197 | #define ISIF_DATAPOL_SHIFT 6 | ||
198 | #define ISIF_EXWEN_DISABLE 0 | ||
199 | #define ISIF_EXWEN_SHIFT 5 | ||
200 | #define ISIF_FRM_FMT_SHIFT 7 | ||
201 | #define ISIF_DATASFT_SHIFT 8 | ||
202 | #define ISIF_LPF_SHIFT 14 | ||
203 | #define ISIF_LPF_MASK 1 | ||
204 | |||
205 | /* GAMMAWD registers */ | ||
206 | #define ISIF_ALAW_GAMA_WD_MASK 0xF | ||
207 | #define ISIF_ALAW_GAMA_WD_SHIFT 1 | ||
208 | #define ISIF_ALAW_ENABLE 1 | ||
209 | #define ISIF_GAMMAWD_CFA_SHIFT 5 | ||
210 | |||
211 | /* HSIZE registers */ | ||
212 | #define ISIF_HSIZE_FLIP_MASK 1 | ||
213 | #define ISIF_HSIZE_FLIP_SHIFT 12 | ||
214 | |||
215 | /* MISC registers */ | ||
216 | #define ISIF_DPCM_EN_SHIFT 12 | ||
217 | #define ISIF_DPCM_PREDICTOR_SHIFT 13 | ||
218 | |||
219 | /* Black clamp related */ | ||
220 | #define ISIF_BC_MODE_COLOR_SHIFT 4 | ||
221 | #define ISIF_HORZ_BC_MODE_SHIFT 1 | ||
222 | #define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 | ||
223 | #define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 | ||
224 | #define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 | ||
225 | #define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 | ||
226 | #define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 | ||
227 | #define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 | ||
228 | |||
229 | /* VDFC registers */ | ||
230 | #define ISIF_VDFC_EN_SHIFT 4 | ||
231 | #define ISIF_VDFC_CORR_MOD_SHIFT 5 | ||
232 | #define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 | ||
233 | #define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 | ||
234 | #define ISIF_VDFC_POS_MASK 0x1FFF | ||
235 | #define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 | ||
236 | |||
237 | /* CSC registers */ | ||
238 | #define ISIF_CSC_COEF_INTEG_MASK 7 | ||
239 | #define ISIF_CSC_COEF_DECIMAL_MASK 0x1f | ||
240 | #define ISIF_CSC_COEF_INTEG_SHIFT 5 | ||
241 | #define ISIF_CSCM_MSB_SHIFT 8 | ||
242 | #define ISIF_DF_CSC_SPH_MASK 0x1FFF | ||
243 | #define ISIF_DF_CSC_LNH_MASK 0x1FFF | ||
244 | #define ISIF_DF_CSC_SLV_MASK 0x1FFF | ||
245 | #define ISIF_DF_CSC_LNV_MASK 0x1FFF | ||
246 | #define ISIF_DF_NUMLINES 0x7FFF | ||
247 | #define ISIF_DF_NUMPIX 0x1FFF | ||
248 | |||
249 | /* Offsets for LSC/DFC/Gain */ | ||
250 | #define ISIF_DATA_H_OFFSET_MASK 0x1FFF | ||
251 | #define ISIF_DATA_V_OFFSET_MASK 0x1FFF | ||
252 | |||
253 | /* Linearization */ | ||
254 | #define ISIF_LIN_CORRSFT_SHIFT 4 | ||
255 | #define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 | ||
256 | |||
257 | |||
258 | /* Pattern registers */ | ||
259 | #define ISIF_PG_EN (1 << 3) | ||
260 | #define ISIF_SEL_PG_SRC (3 << 4) | ||
261 | #define ISIF_PG_VD_POL_SHIFT 0 | ||
262 | #define ISIF_PG_HD_POL_SHIFT 1 | ||
263 | |||
264 | /*random other junk*/ | ||
265 | #define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) | ||
266 | #define ISIF_SYNCEN_WEN_MASK (1 << 1) | ||
267 | #define ISIF_SYNCEN_WEN_SHIFT 1 | ||
268 | |||
269 | #endif | ||
diff --git a/drivers/media/video/davinci/vpbe.c b/drivers/media/video/davinci/vpbe.c new file mode 100644 index 00000000000..d773d30de22 --- /dev/null +++ b/drivers/media/video/davinci/vpbe.c | |||
@@ -0,0 +1,864 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | */ | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <linux/time.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/clk.h> | ||
29 | #include <linux/err.h> | ||
30 | |||
31 | #include <media/v4l2-device.h> | ||
32 | #include <media/davinci/vpbe_types.h> | ||
33 | #include <media/davinci/vpbe.h> | ||
34 | #include <media/davinci/vpss.h> | ||
35 | #include <media/davinci/vpbe_venc.h> | ||
36 | |||
37 | #define VPBE_DEFAULT_OUTPUT "Composite" | ||
38 | #define VPBE_DEFAULT_MODE "ntsc" | ||
39 | |||
40 | static char *def_output = VPBE_DEFAULT_OUTPUT; | ||
41 | static char *def_mode = VPBE_DEFAULT_MODE; | ||
42 | static int debug; | ||
43 | |||
44 | module_param(def_output, charp, S_IRUGO); | ||
45 | module_param(def_mode, charp, S_IRUGO); | ||
46 | module_param(debug, int, 0644); | ||
47 | |||
48 | MODULE_PARM_DESC(def_output, "vpbe output name (default:Composite)"); | ||
49 | MODULE_PARM_DESC(def_mode, "vpbe output mode name (default:ntsc"); | ||
50 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
51 | |||
52 | MODULE_DESCRIPTION("TI DMXXX VPBE Display controller"); | ||
53 | MODULE_LICENSE("GPL"); | ||
54 | MODULE_AUTHOR("Texas Instruments"); | ||
55 | |||
56 | /** | ||
57 | * vpbe_current_encoder_info - Get config info for current encoder | ||
58 | * @vpbe_dev - vpbe device ptr | ||
59 | * | ||
60 | * Return ptr to current encoder config info | ||
61 | */ | ||
62 | static struct encoder_config_info* | ||
63 | vpbe_current_encoder_info(struct vpbe_device *vpbe_dev) | ||
64 | { | ||
65 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
66 | int index = vpbe_dev->current_sd_index; | ||
67 | |||
68 | return ((index == 0) ? &cfg->venc : | ||
69 | &cfg->ext_encoders[index-1]); | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * vpbe_find_encoder_sd_index - Given a name find encoder sd index | ||
74 | * | ||
75 | * @vpbe_config - ptr to vpbe cfg | ||
76 | * @output_index - index used by application | ||
77 | * | ||
78 | * Return sd index of the encoder | ||
79 | */ | ||
80 | static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg, | ||
81 | int index) | ||
82 | { | ||
83 | char *encoder_name = cfg->outputs[index].subdev_name; | ||
84 | int i; | ||
85 | |||
86 | /* Venc is always first */ | ||
87 | if (!strcmp(encoder_name, cfg->venc.module_name)) | ||
88 | return 0; | ||
89 | |||
90 | for (i = 0; i < cfg->num_ext_encoders; i++) { | ||
91 | if (!strcmp(encoder_name, | ||
92 | cfg->ext_encoders[i].module_name)) | ||
93 | return i+1; | ||
94 | } | ||
95 | |||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * vpbe_g_cropcap - Get crop capabilities of the display | ||
101 | * @vpbe_dev - vpbe device ptr | ||
102 | * @cropcap - cropcap is a ptr to struct v4l2_cropcap | ||
103 | * | ||
104 | * Update the crop capabilities in crop cap for current | ||
105 | * mode | ||
106 | */ | ||
107 | static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, | ||
108 | struct v4l2_cropcap *cropcap) | ||
109 | { | ||
110 | if (NULL == cropcap) | ||
111 | return -EINVAL; | ||
112 | cropcap->bounds.left = 0; | ||
113 | cropcap->bounds.top = 0; | ||
114 | cropcap->bounds.width = vpbe_dev->current_timings.xres; | ||
115 | cropcap->bounds.height = vpbe_dev->current_timings.yres; | ||
116 | cropcap->defrect = cropcap->bounds; | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /** | ||
122 | * vpbe_enum_outputs - enumerate outputs | ||
123 | * @vpbe_dev - vpbe device ptr | ||
124 | * @output - ptr to v4l2_output structure | ||
125 | * | ||
126 | * Enumerates the outputs available at the vpbe display | ||
127 | * returns the status, -EINVAL if end of output list | ||
128 | */ | ||
129 | static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev, | ||
130 | struct v4l2_output *output) | ||
131 | { | ||
132 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
133 | int temp_index = output->index; | ||
134 | |||
135 | if (temp_index >= cfg->num_outputs) | ||
136 | return -EINVAL; | ||
137 | |||
138 | *output = cfg->outputs[temp_index].output; | ||
139 | output->index = temp_index; | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode) | ||
145 | { | ||
146 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
147 | struct vpbe_enc_mode_info var; | ||
148 | int curr_output = vpbe_dev->current_out_index; | ||
149 | int i; | ||
150 | |||
151 | if (NULL == mode) | ||
152 | return -EINVAL; | ||
153 | |||
154 | for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { | ||
155 | var = cfg->outputs[curr_output].modes[i]; | ||
156 | if (!strcmp(mode, var.name)) { | ||
157 | vpbe_dev->current_timings = var; | ||
158 | return 0; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, | ||
166 | struct vpbe_enc_mode_info *mode_info) | ||
167 | { | ||
168 | if (NULL == mode_info) | ||
169 | return -EINVAL; | ||
170 | |||
171 | *mode_info = vpbe_dev->current_timings; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, | ||
177 | unsigned int dv_preset) | ||
178 | { | ||
179 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
180 | struct vpbe_enc_mode_info var; | ||
181 | int curr_output = vpbe_dev->current_out_index; | ||
182 | int i; | ||
183 | |||
184 | for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { | ||
185 | var = cfg->outputs[curr_output].modes[i]; | ||
186 | if ((var.timings_type & VPBE_ENC_DV_PRESET) && | ||
187 | (var.timings.dv_preset == dv_preset)) { | ||
188 | vpbe_dev->current_timings = var; | ||
189 | return 0; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | /* Get std by std id */ | ||
197 | static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, | ||
198 | v4l2_std_id std_id) | ||
199 | { | ||
200 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
201 | struct vpbe_enc_mode_info var; | ||
202 | int curr_output = vpbe_dev->current_out_index; | ||
203 | int i; | ||
204 | |||
205 | for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { | ||
206 | var = cfg->outputs[curr_output].modes[i]; | ||
207 | if ((var.timings_type & VPBE_ENC_STD) && | ||
208 | (var.timings.std_id & std_id)) { | ||
209 | vpbe_dev->current_timings = var; | ||
210 | return 0; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | static int vpbe_get_std_info_by_name(struct vpbe_device *vpbe_dev, | ||
218 | char *std_name) | ||
219 | { | ||
220 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
221 | struct vpbe_enc_mode_info var; | ||
222 | int curr_output = vpbe_dev->current_out_index; | ||
223 | int i; | ||
224 | |||
225 | for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { | ||
226 | var = cfg->outputs[curr_output].modes[i]; | ||
227 | if (!strcmp(var.name, std_name)) { | ||
228 | vpbe_dev->current_timings = var; | ||
229 | return 0; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | return -EINVAL; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * vpbe_set_output - Set output | ||
238 | * @vpbe_dev - vpbe device ptr | ||
239 | * @index - index of output | ||
240 | * | ||
241 | * Set vpbe output to the output specified by the index | ||
242 | */ | ||
243 | static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) | ||
244 | { | ||
245 | struct encoder_config_info *curr_enc_info = | ||
246 | vpbe_current_encoder_info(vpbe_dev); | ||
247 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
248 | int enc_out_index; | ||
249 | int sd_index; | ||
250 | int ret = 0; | ||
251 | |||
252 | if (index >= cfg->num_outputs) | ||
253 | return -EINVAL; | ||
254 | |||
255 | mutex_lock(&vpbe_dev->lock); | ||
256 | |||
257 | sd_index = vpbe_dev->current_sd_index; | ||
258 | enc_out_index = cfg->outputs[index].output.index; | ||
259 | /* | ||
260 | * Currently we switch the encoder based on output selected | ||
261 | * by the application. If media controller is implemented later | ||
262 | * there is will be an API added to setup_link between venc | ||
263 | * and external encoder. So in that case below comparison always | ||
264 | * match and encoder will not be switched. But if application | ||
265 | * chose not to use media controller, then this provides current | ||
266 | * way of switching encoder at the venc output. | ||
267 | */ | ||
268 | if (strcmp(curr_enc_info->module_name, | ||
269 | cfg->outputs[index].subdev_name)) { | ||
270 | /* Need to switch the encoder at the output */ | ||
271 | sd_index = vpbe_find_encoder_sd_index(cfg, index); | ||
272 | if (sd_index < 0) { | ||
273 | ret = -EINVAL; | ||
274 | goto out; | ||
275 | } | ||
276 | |||
277 | if (ret) | ||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | /* Set output at the encoder */ | ||
282 | ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, | ||
283 | s_routing, 0, enc_out_index, 0); | ||
284 | if (ret) | ||
285 | goto out; | ||
286 | |||
287 | /* | ||
288 | * It is assumed that venc or extenal encoder will set a default | ||
289 | * mode in the sub device. For external encoder or LCD pannel output, | ||
290 | * we also need to set up the lcd port for the required mode. So setup | ||
291 | * the lcd port for the default mode that is configured in the board | ||
292 | * arch/arm/mach-davinci/board-dm355-evm.setup file for the external | ||
293 | * encoder. | ||
294 | */ | ||
295 | ret = vpbe_get_mode_info(vpbe_dev, | ||
296 | cfg->outputs[index].default_mode); | ||
297 | if (!ret) { | ||
298 | struct osd_state *osd_device = vpbe_dev->osd_device; | ||
299 | |||
300 | osd_device->ops.set_left_margin(osd_device, | ||
301 | vpbe_dev->current_timings.left_margin); | ||
302 | osd_device->ops.set_top_margin(osd_device, | ||
303 | vpbe_dev->current_timings.upper_margin); | ||
304 | vpbe_dev->current_sd_index = sd_index; | ||
305 | vpbe_dev->current_out_index = index; | ||
306 | } | ||
307 | out: | ||
308 | mutex_unlock(&vpbe_dev->lock); | ||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) | ||
313 | { | ||
314 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
315 | int ret = 0; | ||
316 | int i; | ||
317 | |||
318 | for (i = 0; i < cfg->num_outputs; i++) { | ||
319 | if (!strcmp(def_output, | ||
320 | cfg->outputs[i].output.name)) { | ||
321 | ret = vpbe_set_output(vpbe_dev, i); | ||
322 | if (!ret) | ||
323 | vpbe_dev->current_out_index = i; | ||
324 | return ret; | ||
325 | } | ||
326 | } | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | /** | ||
331 | * vpbe_get_output - Get output | ||
332 | * @vpbe_dev - vpbe device ptr | ||
333 | * | ||
334 | * return current vpbe output to the the index | ||
335 | */ | ||
336 | static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) | ||
337 | { | ||
338 | return vpbe_dev->current_out_index; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * vpbe_s_dv_preset - Set the given preset timings in the encoder | ||
343 | * | ||
344 | * Sets the preset if supported by the current encoder. Return the status. | ||
345 | * 0 - success & -EINVAL on error | ||
346 | */ | ||
347 | static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, | ||
348 | struct v4l2_dv_preset *dv_preset) | ||
349 | { | ||
350 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
351 | int out_index = vpbe_dev->current_out_index; | ||
352 | int sd_index = vpbe_dev->current_sd_index; | ||
353 | int ret; | ||
354 | |||
355 | |||
356 | if (!(cfg->outputs[out_index].output.capabilities & | ||
357 | V4L2_OUT_CAP_PRESETS)) | ||
358 | return -EINVAL; | ||
359 | |||
360 | ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); | ||
361 | |||
362 | if (ret) | ||
363 | return ret; | ||
364 | |||
365 | mutex_lock(&vpbe_dev->lock); | ||
366 | |||
367 | |||
368 | ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, | ||
369 | s_dv_preset, dv_preset); | ||
370 | /* set the lcd controller output for the given mode */ | ||
371 | if (!ret) { | ||
372 | struct osd_state *osd_device = vpbe_dev->osd_device; | ||
373 | |||
374 | osd_device->ops.set_left_margin(osd_device, | ||
375 | vpbe_dev->current_timings.left_margin); | ||
376 | osd_device->ops.set_top_margin(osd_device, | ||
377 | vpbe_dev->current_timings.upper_margin); | ||
378 | } | ||
379 | mutex_unlock(&vpbe_dev->lock); | ||
380 | |||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * vpbe_g_dv_preset - Get the preset in the current encoder | ||
386 | * | ||
387 | * Get the preset in the current encoder. Return the status. 0 - success | ||
388 | * -EINVAL on error | ||
389 | */ | ||
390 | static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, | ||
391 | struct v4l2_dv_preset *dv_preset) | ||
392 | { | ||
393 | if (vpbe_dev->current_timings.timings_type & | ||
394 | VPBE_ENC_DV_PRESET) { | ||
395 | dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | return -EINVAL; | ||
400 | } | ||
401 | |||
402 | /** | ||
403 | * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder | ||
404 | * | ||
405 | * Get the preset in the current encoder. Return the status. 0 - success | ||
406 | * -EINVAL on error | ||
407 | */ | ||
408 | static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, | ||
409 | struct v4l2_dv_enum_preset *preset_info) | ||
410 | { | ||
411 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
412 | int out_index = vpbe_dev->current_out_index; | ||
413 | struct vpbe_output *output = &cfg->outputs[out_index]; | ||
414 | int j = 0; | ||
415 | int i; | ||
416 | |||
417 | if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) | ||
418 | return -EINVAL; | ||
419 | |||
420 | for (i = 0; i < output->num_modes; i++) { | ||
421 | if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { | ||
422 | if (j == preset_info->index) | ||
423 | break; | ||
424 | j++; | ||
425 | } | ||
426 | } | ||
427 | |||
428 | if (i == output->num_modes) | ||
429 | return -EINVAL; | ||
430 | |||
431 | return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, | ||
432 | preset_info); | ||
433 | } | ||
434 | |||
435 | /** | ||
436 | * vpbe_s_std - Set the given standard in the encoder | ||
437 | * | ||
438 | * Sets the standard if supported by the current encoder. Return the status. | ||
439 | * 0 - success & -EINVAL on error | ||
440 | */ | ||
441 | static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) | ||
442 | { | ||
443 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
444 | int out_index = vpbe_dev->current_out_index; | ||
445 | int sd_index = vpbe_dev->current_sd_index; | ||
446 | int ret; | ||
447 | |||
448 | if (!(cfg->outputs[out_index].output.capabilities & | ||
449 | V4L2_OUT_CAP_STD)) | ||
450 | return -EINVAL; | ||
451 | |||
452 | ret = vpbe_get_std_info(vpbe_dev, *std_id); | ||
453 | if (ret) | ||
454 | return ret; | ||
455 | |||
456 | mutex_lock(&vpbe_dev->lock); | ||
457 | |||
458 | ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, | ||
459 | s_std_output, *std_id); | ||
460 | /* set the lcd controller output for the given mode */ | ||
461 | if (!ret) { | ||
462 | struct osd_state *osd_device = vpbe_dev->osd_device; | ||
463 | |||
464 | osd_device->ops.set_left_margin(osd_device, | ||
465 | vpbe_dev->current_timings.left_margin); | ||
466 | osd_device->ops.set_top_margin(osd_device, | ||
467 | vpbe_dev->current_timings.upper_margin); | ||
468 | } | ||
469 | mutex_unlock(&vpbe_dev->lock); | ||
470 | |||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | /** | ||
475 | * vpbe_g_std - Get the standard in the current encoder | ||
476 | * | ||
477 | * Get the standard in the current encoder. Return the status. 0 - success | ||
478 | * -EINVAL on error | ||
479 | */ | ||
480 | static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) | ||
481 | { | ||
482 | struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; | ||
483 | |||
484 | if (cur_timings.timings_type & VPBE_ENC_STD) { | ||
485 | *std_id = cur_timings.timings.std_id; | ||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | return -EINVAL; | ||
490 | } | ||
491 | |||
492 | /** | ||
493 | * vpbe_set_mode - Set mode in the current encoder using mode info | ||
494 | * | ||
495 | * Use the mode string to decide what timings to set in the encoder | ||
496 | * This is typically useful when fbset command is used to change the current | ||
497 | * timings by specifying a string to indicate the timings. | ||
498 | */ | ||
499 | static int vpbe_set_mode(struct vpbe_device *vpbe_dev, | ||
500 | struct vpbe_enc_mode_info *mode_info) | ||
501 | { | ||
502 | struct vpbe_enc_mode_info *preset_mode = NULL; | ||
503 | struct vpbe_config *cfg = vpbe_dev->cfg; | ||
504 | struct v4l2_dv_preset dv_preset; | ||
505 | struct osd_state *osd_device; | ||
506 | int out_index = vpbe_dev->current_out_index; | ||
507 | int ret = 0; | ||
508 | int i; | ||
509 | |||
510 | if ((NULL == mode_info) || (NULL == mode_info->name)) | ||
511 | return -EINVAL; | ||
512 | |||
513 | for (i = 0; i < cfg->outputs[out_index].num_modes; i++) { | ||
514 | if (!strcmp(mode_info->name, | ||
515 | cfg->outputs[out_index].modes[i].name)) { | ||
516 | preset_mode = &cfg->outputs[out_index].modes[i]; | ||
517 | /* | ||
518 | * it may be one of the 3 timings type. Check and | ||
519 | * invoke right API | ||
520 | */ | ||
521 | if (preset_mode->timings_type & VPBE_ENC_STD) | ||
522 | return vpbe_s_std(vpbe_dev, | ||
523 | &preset_mode->timings.std_id); | ||
524 | if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { | ||
525 | dv_preset.preset = | ||
526 | preset_mode->timings.dv_preset; | ||
527 | return vpbe_s_dv_preset(vpbe_dev, &dv_preset); | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | |||
532 | /* Only custom timing should reach here */ | ||
533 | if (preset_mode == NULL) | ||
534 | return -EINVAL; | ||
535 | |||
536 | mutex_lock(&vpbe_dev->lock); | ||
537 | |||
538 | osd_device = vpbe_dev->osd_device; | ||
539 | vpbe_dev->current_timings = *preset_mode; | ||
540 | osd_device->ops.set_left_margin(osd_device, | ||
541 | vpbe_dev->current_timings.left_margin); | ||
542 | osd_device->ops.set_top_margin(osd_device, | ||
543 | vpbe_dev->current_timings.upper_margin); | ||
544 | |||
545 | mutex_unlock(&vpbe_dev->lock); | ||
546 | |||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) | ||
551 | { | ||
552 | int ret; | ||
553 | |||
554 | ret = vpbe_get_std_info_by_name(vpbe_dev, def_mode); | ||
555 | if (ret) | ||
556 | return ret; | ||
557 | |||
558 | /* set the default mode in the encoder */ | ||
559 | return vpbe_set_mode(vpbe_dev, &vpbe_dev->current_timings); | ||
560 | } | ||
561 | |||
562 | static int platform_device_get(struct device *dev, void *data) | ||
563 | { | ||
564 | struct platform_device *pdev = to_platform_device(dev); | ||
565 | struct vpbe_device *vpbe_dev = data; | ||
566 | |||
567 | if (strcmp("vpbe-osd", pdev->name) == 0) | ||
568 | vpbe_dev->osd_device = platform_get_drvdata(pdev); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * vpbe_initialize() - Initialize the vpbe display controller | ||
575 | * @vpbe_dev - vpbe device ptr | ||
576 | * | ||
577 | * Master frame buffer device drivers calls this to initialize vpbe | ||
578 | * display controller. This will then registers v4l2 device and the sub | ||
579 | * devices and sets a current encoder sub device for display. v4l2 display | ||
580 | * device driver is the master and frame buffer display device driver is | ||
581 | * the slave. Frame buffer display driver checks the initialized during | ||
582 | * probe and exit if not initialized. Returns status. | ||
583 | */ | ||
584 | static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) | ||
585 | { | ||
586 | struct encoder_config_info *enc_info; | ||
587 | struct v4l2_subdev **enc_subdev; | ||
588 | struct osd_state *osd_device; | ||
589 | struct i2c_adapter *i2c_adap; | ||
590 | int output_index; | ||
591 | int num_encoders; | ||
592 | int ret = 0; | ||
593 | int err; | ||
594 | int i; | ||
595 | |||
596 | /* | ||
597 | * v4l2 abd FBDev frame buffer devices will get the vpbe_dev pointer | ||
598 | * from the platform device by iteration of platform drivers and | ||
599 | * matching with device name | ||
600 | */ | ||
601 | if (NULL == vpbe_dev || NULL == dev) { | ||
602 | printk(KERN_ERR "Null device pointers.\n"); | ||
603 | return -ENODEV; | ||
604 | } | ||
605 | |||
606 | if (vpbe_dev->initialized) | ||
607 | return 0; | ||
608 | |||
609 | mutex_lock(&vpbe_dev->lock); | ||
610 | |||
611 | if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { | ||
612 | /* We have dac clock available for platform */ | ||
613 | vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); | ||
614 | if (IS_ERR(vpbe_dev->dac_clk)) { | ||
615 | ret = PTR_ERR(vpbe_dev->dac_clk); | ||
616 | goto vpbe_unlock; | ||
617 | } | ||
618 | if (clk_enable(vpbe_dev->dac_clk)) { | ||
619 | ret = -ENODEV; | ||
620 | goto vpbe_unlock; | ||
621 | } | ||
622 | } | ||
623 | |||
624 | /* first enable vpss clocks */ | ||
625 | vpss_enable_clock(VPSS_VPBE_CLOCK, 1); | ||
626 | |||
627 | /* First register a v4l2 device */ | ||
628 | ret = v4l2_device_register(dev, &vpbe_dev->v4l2_dev); | ||
629 | if (ret) { | ||
630 | v4l2_err(dev->driver, | ||
631 | "Unable to register v4l2 device.\n"); | ||
632 | goto vpbe_fail_clock; | ||
633 | } | ||
634 | v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); | ||
635 | |||
636 | err = bus_for_each_dev(&platform_bus_type, NULL, vpbe_dev, | ||
637 | platform_device_get); | ||
638 | if (err < 0) | ||
639 | return err; | ||
640 | |||
641 | vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, | ||
642 | vpbe_dev->cfg->venc.module_name); | ||
643 | /* register venc sub device */ | ||
644 | if (vpbe_dev->venc == NULL) { | ||
645 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
646 | "vpbe unable to init venc sub device\n"); | ||
647 | ret = -ENODEV; | ||
648 | goto vpbe_fail_v4l2_device; | ||
649 | } | ||
650 | /* initialize osd device */ | ||
651 | osd_device = vpbe_dev->osd_device; | ||
652 | |||
653 | if (NULL != osd_device->ops.initialize) { | ||
654 | err = osd_device->ops.initialize(osd_device); | ||
655 | if (err) { | ||
656 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
657 | "unable to initialize the OSD device"); | ||
658 | err = -ENOMEM; | ||
659 | goto vpbe_fail_v4l2_device; | ||
660 | } | ||
661 | } | ||
662 | |||
663 | /* | ||
664 | * Register any external encoders that are configured. At index 0 we | ||
665 | * store venc sd index. | ||
666 | */ | ||
667 | num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; | ||
668 | vpbe_dev->encoders = kmalloc( | ||
669 | sizeof(struct v4l2_subdev *)*num_encoders, | ||
670 | GFP_KERNEL); | ||
671 | if (NULL == vpbe_dev->encoders) { | ||
672 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
673 | "unable to allocate memory for encoders sub devices"); | ||
674 | ret = -ENOMEM; | ||
675 | goto vpbe_fail_v4l2_device; | ||
676 | } | ||
677 | |||
678 | i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); | ||
679 | for (i = 0; i < (vpbe_dev->cfg->num_ext_encoders + 1); i++) { | ||
680 | if (i == 0) { | ||
681 | /* venc is at index 0 */ | ||
682 | enc_subdev = &vpbe_dev->encoders[i]; | ||
683 | *enc_subdev = vpbe_dev->venc; | ||
684 | continue; | ||
685 | } | ||
686 | enc_info = &vpbe_dev->cfg->ext_encoders[i]; | ||
687 | if (enc_info->is_i2c) { | ||
688 | enc_subdev = &vpbe_dev->encoders[i]; | ||
689 | *enc_subdev = v4l2_i2c_new_subdev_board( | ||
690 | &vpbe_dev->v4l2_dev, i2c_adap, | ||
691 | &enc_info->board_info, NULL); | ||
692 | if (*enc_subdev) | ||
693 | v4l2_info(&vpbe_dev->v4l2_dev, | ||
694 | "v4l2 sub device %s registered\n", | ||
695 | enc_info->module_name); | ||
696 | else { | ||
697 | v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" | ||
698 | " failed to register", | ||
699 | enc_info->module_name); | ||
700 | ret = -ENODEV; | ||
701 | goto vpbe_fail_sd_register; | ||
702 | } | ||
703 | } else | ||
704 | v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" | ||
705 | " currently not supported"); | ||
706 | } | ||
707 | |||
708 | /* set the current encoder and output to that of venc by default */ | ||
709 | vpbe_dev->current_sd_index = 0; | ||
710 | vpbe_dev->current_out_index = 0; | ||
711 | output_index = 0; | ||
712 | |||
713 | mutex_unlock(&vpbe_dev->lock); | ||
714 | |||
715 | printk(KERN_NOTICE "Setting default output to %s\n", def_output); | ||
716 | ret = vpbe_set_default_output(vpbe_dev); | ||
717 | if (ret) { | ||
718 | v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s", | ||
719 | def_output); | ||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | printk(KERN_NOTICE "Setting default mode to %s\n", def_mode); | ||
724 | ret = vpbe_set_default_mode(vpbe_dev); | ||
725 | if (ret) { | ||
726 | v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s", | ||
727 | def_mode); | ||
728 | return ret; | ||
729 | } | ||
730 | vpbe_dev->initialized = 1; | ||
731 | /* TBD handling of bootargs for default output and mode */ | ||
732 | return 0; | ||
733 | |||
734 | vpbe_fail_sd_register: | ||
735 | kfree(vpbe_dev->encoders); | ||
736 | vpbe_fail_v4l2_device: | ||
737 | v4l2_device_unregister(&vpbe_dev->v4l2_dev); | ||
738 | vpbe_fail_clock: | ||
739 | if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) | ||
740 | clk_put(vpbe_dev->dac_clk); | ||
741 | vpbe_unlock: | ||
742 | mutex_unlock(&vpbe_dev->lock); | ||
743 | return ret; | ||
744 | } | ||
745 | |||
746 | /** | ||
747 | * vpbe_deinitialize() - de-initialize the vpbe display controller | ||
748 | * @dev - Master and slave device ptr | ||
749 | * | ||
750 | * vpbe_master and slave frame buffer devices calls this to de-initialize | ||
751 | * the display controller. It is called when master and slave device | ||
752 | * driver modules are removed and no longer requires the display controller. | ||
753 | */ | ||
754 | static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) | ||
755 | { | ||
756 | v4l2_device_unregister(&vpbe_dev->v4l2_dev); | ||
757 | if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) | ||
758 | clk_put(vpbe_dev->dac_clk); | ||
759 | |||
760 | kfree(vpbe_dev->encoders); | ||
761 | vpbe_dev->initialized = 0; | ||
762 | /* disable vpss clocks */ | ||
763 | vpss_enable_clock(VPSS_VPBE_CLOCK, 0); | ||
764 | } | ||
765 | |||
766 | static struct vpbe_device_ops vpbe_dev_ops = { | ||
767 | .g_cropcap = vpbe_g_cropcap, | ||
768 | .enum_outputs = vpbe_enum_outputs, | ||
769 | .set_output = vpbe_set_output, | ||
770 | .get_output = vpbe_get_output, | ||
771 | .s_dv_preset = vpbe_s_dv_preset, | ||
772 | .g_dv_preset = vpbe_g_dv_preset, | ||
773 | .enum_dv_presets = vpbe_enum_dv_presets, | ||
774 | .s_std = vpbe_s_std, | ||
775 | .g_std = vpbe_g_std, | ||
776 | .initialize = vpbe_initialize, | ||
777 | .deinitialize = vpbe_deinitialize, | ||
778 | .get_mode_info = vpbe_get_current_mode_info, | ||
779 | .set_mode = vpbe_set_mode, | ||
780 | }; | ||
781 | |||
782 | static __devinit int vpbe_probe(struct platform_device *pdev) | ||
783 | { | ||
784 | struct vpbe_device *vpbe_dev; | ||
785 | struct vpbe_config *cfg; | ||
786 | int ret = -EINVAL; | ||
787 | |||
788 | if (pdev->dev.platform_data == NULL) { | ||
789 | v4l2_err(pdev->dev.driver, "No platform data\n"); | ||
790 | return -ENODEV; | ||
791 | } | ||
792 | cfg = pdev->dev.platform_data; | ||
793 | |||
794 | if (!cfg->module_name[0] || | ||
795 | !cfg->osd.module_name[0] || | ||
796 | !cfg->venc.module_name[0]) { | ||
797 | v4l2_err(pdev->dev.driver, "vpbe display module names not" | ||
798 | " defined\n"); | ||
799 | return ret; | ||
800 | } | ||
801 | |||
802 | vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); | ||
803 | if (vpbe_dev == NULL) { | ||
804 | v4l2_err(pdev->dev.driver, "Unable to allocate memory" | ||
805 | " for vpbe_device\n"); | ||
806 | return -ENOMEM; | ||
807 | } | ||
808 | vpbe_dev->cfg = cfg; | ||
809 | vpbe_dev->ops = vpbe_dev_ops; | ||
810 | vpbe_dev->pdev = &pdev->dev; | ||
811 | |||
812 | if (cfg->outputs->num_modes > 0) | ||
813 | vpbe_dev->current_timings = vpbe_dev->cfg->outputs[0].modes[0]; | ||
814 | else | ||
815 | return -ENODEV; | ||
816 | |||
817 | /* set the driver data in platform device */ | ||
818 | platform_set_drvdata(pdev, vpbe_dev); | ||
819 | mutex_init(&vpbe_dev->lock); | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static int vpbe_remove(struct platform_device *device) | ||
825 | { | ||
826 | struct vpbe_device *vpbe_dev = platform_get_drvdata(device); | ||
827 | |||
828 | kfree(vpbe_dev); | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | static struct platform_driver vpbe_driver = { | ||
834 | .driver = { | ||
835 | .name = "vpbe_controller", | ||
836 | .owner = THIS_MODULE, | ||
837 | }, | ||
838 | .probe = vpbe_probe, | ||
839 | .remove = vpbe_remove, | ||
840 | }; | ||
841 | |||
842 | /** | ||
843 | * vpbe_init: initialize the vpbe driver | ||
844 | * | ||
845 | * This function registers device and driver to the kernel | ||
846 | */ | ||
847 | static __init int vpbe_init(void) | ||
848 | { | ||
849 | return platform_driver_register(&vpbe_driver); | ||
850 | } | ||
851 | |||
852 | /** | ||
853 | * vpbe_cleanup : cleanup function for vpbe driver | ||
854 | * | ||
855 | * This will un-registers the device and driver to the kernel | ||
856 | */ | ||
857 | static void vpbe_cleanup(void) | ||
858 | { | ||
859 | platform_driver_unregister(&vpbe_driver); | ||
860 | } | ||
861 | |||
862 | /* Function for module initialization and cleanup */ | ||
863 | module_init(vpbe_init); | ||
864 | module_exit(vpbe_cleanup); | ||
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c new file mode 100644 index 00000000000..7f1d83a6d57 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_display.c | |||
@@ -0,0 +1,1860 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | ||
6 | * published by the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed WITHOUT ANY WARRANTY of any | ||
9 | * kind, whether express or implied; without even the implied warranty | ||
10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <linux/time.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/mutex.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include <asm/pgtable.h> | ||
29 | #include <mach/cputype.h> | ||
30 | |||
31 | #include <media/v4l2-dev.h> | ||
32 | #include <media/v4l2-common.h> | ||
33 | #include <media/v4l2-ioctl.h> | ||
34 | #include <media/v4l2-device.h> | ||
35 | #include <media/davinci/vpbe_display.h> | ||
36 | #include <media/davinci/vpbe_types.h> | ||
37 | #include <media/davinci/vpbe.h> | ||
38 | #include <media/davinci/vpbe_venc.h> | ||
39 | #include <media/davinci/vpbe_osd.h> | ||
40 | #include "vpbe_venc_regs.h" | ||
41 | |||
42 | #define VPBE_DISPLAY_DRIVER "vpbe-v4l2" | ||
43 | |||
44 | static int debug; | ||
45 | |||
46 | #define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2) | ||
47 | #define VPBE_DEFAULT_NUM_BUFS 3 | ||
48 | |||
49 | module_param(debug, int, 0644); | ||
50 | |||
51 | static int venc_is_second_field(struct vpbe_display *disp_dev) | ||
52 | { | ||
53 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
54 | int ret; | ||
55 | int val; | ||
56 | |||
57 | ret = v4l2_subdev_call(vpbe_dev->venc, | ||
58 | core, | ||
59 | ioctl, | ||
60 | VENC_GET_FLD, | ||
61 | &val); | ||
62 | if (ret < 0) { | ||
63 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
64 | "Error in getting Field ID 0\n"); | ||
65 | } | ||
66 | return val; | ||
67 | } | ||
68 | |||
69 | static void vpbe_isr_even_field(struct vpbe_display *disp_obj, | ||
70 | struct vpbe_layer *layer) | ||
71 | { | ||
72 | struct timespec timevalue; | ||
73 | |||
74 | if (layer->cur_frm == layer->next_frm) | ||
75 | return; | ||
76 | ktime_get_ts(&timevalue); | ||
77 | layer->cur_frm->ts.tv_sec = timevalue.tv_sec; | ||
78 | layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC; | ||
79 | layer->cur_frm->state = VIDEOBUF_DONE; | ||
80 | wake_up_interruptible(&layer->cur_frm->done); | ||
81 | /* Make cur_frm pointing to next_frm */ | ||
82 | layer->cur_frm = layer->next_frm; | ||
83 | } | ||
84 | |||
85 | static void vpbe_isr_odd_field(struct vpbe_display *disp_obj, | ||
86 | struct vpbe_layer *layer) | ||
87 | { | ||
88 | struct osd_state *osd_device = disp_obj->osd_device; | ||
89 | unsigned long addr; | ||
90 | |||
91 | spin_lock(&disp_obj->dma_queue_lock); | ||
92 | if (list_empty(&layer->dma_queue) || | ||
93 | (layer->cur_frm != layer->next_frm)) { | ||
94 | spin_unlock(&disp_obj->dma_queue_lock); | ||
95 | return; | ||
96 | } | ||
97 | /* | ||
98 | * one field is displayed configure | ||
99 | * the next frame if it is available | ||
100 | * otherwise hold on current frame | ||
101 | * Get next from the buffer queue | ||
102 | */ | ||
103 | layer->next_frm = list_entry( | ||
104 | layer->dma_queue.next, | ||
105 | struct videobuf_buffer, | ||
106 | queue); | ||
107 | /* Remove that from the buffer queue */ | ||
108 | list_del(&layer->next_frm->queue); | ||
109 | spin_unlock(&disp_obj->dma_queue_lock); | ||
110 | /* Mark state of the frame to active */ | ||
111 | layer->next_frm->state = VIDEOBUF_ACTIVE; | ||
112 | addr = videobuf_to_dma_contig(layer->next_frm); | ||
113 | osd_device->ops.start_layer(osd_device, | ||
114 | layer->layer_info.id, | ||
115 | addr, | ||
116 | disp_obj->cbcr_ofst); | ||
117 | } | ||
118 | |||
119 | /* interrupt service routine */ | ||
120 | static irqreturn_t venc_isr(int irq, void *arg) | ||
121 | { | ||
122 | struct vpbe_display *disp_dev = (struct vpbe_display *)arg; | ||
123 | struct vpbe_layer *layer; | ||
124 | static unsigned last_event; | ||
125 | unsigned event = 0; | ||
126 | int fid; | ||
127 | int i; | ||
128 | |||
129 | if ((NULL == arg) || (NULL == disp_dev->dev[0])) | ||
130 | return IRQ_HANDLED; | ||
131 | |||
132 | if (venc_is_second_field(disp_dev)) | ||
133 | event |= VENC_SECOND_FIELD; | ||
134 | else | ||
135 | event |= VENC_FIRST_FIELD; | ||
136 | |||
137 | if (event == (last_event & ~VENC_END_OF_FRAME)) { | ||
138 | /* | ||
139 | * If the display is non-interlaced, then we need to flag the | ||
140 | * end-of-frame event at every interrupt regardless of the | ||
141 | * value of the FIDST bit. We can conclude that the display is | ||
142 | * non-interlaced if the value of the FIDST bit is unchanged | ||
143 | * from the previous interrupt. | ||
144 | */ | ||
145 | event |= VENC_END_OF_FRAME; | ||
146 | } else if (event == VENC_SECOND_FIELD) { | ||
147 | /* end-of-frame for interlaced display */ | ||
148 | event |= VENC_END_OF_FRAME; | ||
149 | } | ||
150 | last_event = event; | ||
151 | |||
152 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
153 | layer = disp_dev->dev[i]; | ||
154 | /* If streaming is started in this layer */ | ||
155 | if (!layer->started) | ||
156 | continue; | ||
157 | |||
158 | if (layer->layer_first_int) { | ||
159 | layer->layer_first_int = 0; | ||
160 | continue; | ||
161 | } | ||
162 | /* Check the field format */ | ||
163 | if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && | ||
164 | (event & VENC_END_OF_FRAME)) { | ||
165 | /* Progressive mode */ | ||
166 | |||
167 | vpbe_isr_even_field(disp_dev, layer); | ||
168 | vpbe_isr_odd_field(disp_dev, layer); | ||
169 | } else { | ||
170 | /* Interlaced mode */ | ||
171 | |||
172 | layer->field_id ^= 1; | ||
173 | if (event & VENC_FIRST_FIELD) | ||
174 | fid = 0; | ||
175 | else | ||
176 | fid = 1; | ||
177 | |||
178 | /* | ||
179 | * If field id does not match with store | ||
180 | * field id | ||
181 | */ | ||
182 | if (fid != layer->field_id) { | ||
183 | /* Make them in sync */ | ||
184 | layer->field_id = fid; | ||
185 | continue; | ||
186 | } | ||
187 | /* | ||
188 | * device field id and local field id are | ||
189 | * in sync. If this is even field | ||
190 | */ | ||
191 | if (0 == fid) | ||
192 | vpbe_isr_even_field(disp_dev, layer); | ||
193 | else /* odd field */ | ||
194 | vpbe_isr_odd_field(disp_dev, layer); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return IRQ_HANDLED; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * vpbe_buffer_prepare() | ||
203 | * This is the callback function called from videobuf_qbuf() function | ||
204 | * the buffer is prepared and user space virtual address is converted into | ||
205 | * physical address | ||
206 | */ | ||
207 | static int vpbe_buffer_prepare(struct videobuf_queue *q, | ||
208 | struct videobuf_buffer *vb, | ||
209 | enum v4l2_field field) | ||
210 | { | ||
211 | struct vpbe_fh *fh = q->priv_data; | ||
212 | struct vpbe_layer *layer = fh->layer; | ||
213 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
214 | unsigned long addr; | ||
215 | int ret; | ||
216 | |||
217 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
218 | "vpbe_buffer_prepare\n"); | ||
219 | |||
220 | /* If buffer is not initialized, initialize it */ | ||
221 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
222 | vb->width = layer->pix_fmt.width; | ||
223 | vb->height = layer->pix_fmt.height; | ||
224 | vb->size = layer->pix_fmt.sizeimage; | ||
225 | vb->field = field; | ||
226 | |||
227 | ret = videobuf_iolock(q, vb, NULL); | ||
228 | if (ret < 0) { | ||
229 | v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \ | ||
230 | user address\n"); | ||
231 | return -EINVAL; | ||
232 | } | ||
233 | |||
234 | addr = videobuf_to_dma_contig(vb); | ||
235 | |||
236 | if (q->streaming) { | ||
237 | if (!IS_ALIGNED(addr, 8)) { | ||
238 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
239 | "buffer_prepare:offset is \ | ||
240 | not aligned to 32 bytes\n"); | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | } | ||
244 | vb->state = VIDEOBUF_PREPARED; | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * vpbe_buffer_setup() | ||
251 | * This function allocates memory for the buffers | ||
252 | */ | ||
253 | static int vpbe_buffer_setup(struct videobuf_queue *q, | ||
254 | unsigned int *count, | ||
255 | unsigned int *size) | ||
256 | { | ||
257 | /* Get the file handle object and layer object */ | ||
258 | struct vpbe_fh *fh = q->priv_data; | ||
259 | struct vpbe_layer *layer = fh->layer; | ||
260 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
261 | |||
262 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); | ||
263 | |||
264 | *size = layer->pix_fmt.sizeimage; | ||
265 | |||
266 | /* Store number of buffers allocated in numbuffer member */ | ||
267 | if (*count < VPBE_DEFAULT_NUM_BUFS) | ||
268 | *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS; | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * vpbe_buffer_queue() | ||
275 | * This function adds the buffer to DMA queue | ||
276 | */ | ||
277 | static void vpbe_buffer_queue(struct videobuf_queue *q, | ||
278 | struct videobuf_buffer *vb) | ||
279 | { | ||
280 | /* Get the file handle object and layer object */ | ||
281 | struct vpbe_fh *fh = q->priv_data; | ||
282 | struct vpbe_layer *layer = fh->layer; | ||
283 | struct vpbe_display *disp = fh->disp_dev; | ||
284 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
285 | unsigned long flags; | ||
286 | |||
287 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
288 | "vpbe_buffer_queue\n"); | ||
289 | |||
290 | /* add the buffer to the DMA queue */ | ||
291 | spin_lock_irqsave(&disp->dma_queue_lock, flags); | ||
292 | list_add_tail(&vb->queue, &layer->dma_queue); | ||
293 | spin_unlock_irqrestore(&disp->dma_queue_lock, flags); | ||
294 | /* Change state of the buffer */ | ||
295 | vb->state = VIDEOBUF_QUEUED; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * vpbe_buffer_release() | ||
300 | * This function is called from the videobuf layer to free memory allocated to | ||
301 | * the buffers | ||
302 | */ | ||
303 | static void vpbe_buffer_release(struct videobuf_queue *q, | ||
304 | struct videobuf_buffer *vb) | ||
305 | { | ||
306 | /* Get the file handle object and layer object */ | ||
307 | struct vpbe_fh *fh = q->priv_data; | ||
308 | struct vpbe_layer *layer = fh->layer; | ||
309 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
310 | |||
311 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
312 | "vpbe_buffer_release\n"); | ||
313 | |||
314 | if (V4L2_MEMORY_USERPTR != layer->memory) | ||
315 | videobuf_dma_contig_free(q, vb); | ||
316 | |||
317 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
318 | } | ||
319 | |||
320 | static struct videobuf_queue_ops video_qops = { | ||
321 | .buf_setup = vpbe_buffer_setup, | ||
322 | .buf_prepare = vpbe_buffer_prepare, | ||
323 | .buf_queue = vpbe_buffer_queue, | ||
324 | .buf_release = vpbe_buffer_release, | ||
325 | }; | ||
326 | |||
327 | static | ||
328 | struct vpbe_layer* | ||
329 | _vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev, | ||
330 | struct vpbe_layer *layer) | ||
331 | { | ||
332 | enum vpbe_display_device_id thiswin, otherwin; | ||
333 | thiswin = layer->device_id; | ||
334 | |||
335 | otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? | ||
336 | VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; | ||
337 | return disp_dev->dev[otherwin]; | ||
338 | } | ||
339 | |||
340 | static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, | ||
341 | struct vpbe_layer *layer) | ||
342 | { | ||
343 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
344 | struct osd_state *osd_device = disp_dev->osd_device; | ||
345 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
346 | unsigned long addr; | ||
347 | int ret; | ||
348 | |||
349 | addr = videobuf_to_dma_contig(layer->cur_frm); | ||
350 | /* Set address in the display registers */ | ||
351 | osd_device->ops.start_layer(osd_device, | ||
352 | layer->layer_info.id, | ||
353 | addr, | ||
354 | disp_dev->cbcr_ofst); | ||
355 | |||
356 | ret = osd_device->ops.enable_layer(osd_device, | ||
357 | layer->layer_info.id, 0); | ||
358 | if (ret < 0) { | ||
359 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
360 | "Error in enabling osd window layer 0\n"); | ||
361 | return -1; | ||
362 | } | ||
363 | |||
364 | /* Enable the window */ | ||
365 | layer->layer_info.enable = 1; | ||
366 | if (cfg->pixfmt == PIXFMT_NV12) { | ||
367 | struct vpbe_layer *otherlayer = | ||
368 | _vpbe_display_get_other_win_layer(disp_dev, layer); | ||
369 | |||
370 | ret = osd_device->ops.enable_layer(osd_device, | ||
371 | otherlayer->layer_info.id, 1); | ||
372 | if (ret < 0) { | ||
373 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
374 | "Error in enabling osd window layer 1\n"); | ||
375 | return -1; | ||
376 | } | ||
377 | otherlayer->layer_info.enable = 1; | ||
378 | } | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static void | ||
383 | vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, | ||
384 | struct vpbe_layer *layer, | ||
385 | int expected_xsize, int expected_ysize) | ||
386 | { | ||
387 | struct display_layer_info *layer_info = &layer->layer_info; | ||
388 | struct v4l2_pix_format *pixfmt = &layer->pix_fmt; | ||
389 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
390 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
391 | int calculated_xsize; | ||
392 | int h_exp = 0; | ||
393 | int v_exp = 0; | ||
394 | int h_scale; | ||
395 | int v_scale; | ||
396 | |||
397 | v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; | ||
398 | |||
399 | /* | ||
400 | * Application initially set the image format. Current display | ||
401 | * size is obtained from the vpbe display controller. expected_xsize | ||
402 | * and expected_ysize are set through S_CROP ioctl. Based on this, | ||
403 | * driver will calculate the scale factors for vertical and | ||
404 | * horizontal direction so that the image is displayed scaled | ||
405 | * and expanded. Application uses expansion to display the image | ||
406 | * in a square pixel. Otherwise it is displayed using displays | ||
407 | * pixel aspect ratio.It is expected that application chooses | ||
408 | * the crop coordinates for cropped or scaled display. if crop | ||
409 | * size is less than the image size, it is displayed cropped or | ||
410 | * it is displayed scaled and/or expanded. | ||
411 | * | ||
412 | * to begin with, set the crop window same as expected. Later we | ||
413 | * will override with scaled window size | ||
414 | */ | ||
415 | |||
416 | cfg->xsize = pixfmt->width; | ||
417 | cfg->ysize = pixfmt->height; | ||
418 | layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ | ||
419 | layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ | ||
420 | layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ | ||
421 | layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ | ||
422 | |||
423 | if (pixfmt->width < expected_xsize) { | ||
424 | h_scale = vpbe_dev->current_timings.xres / pixfmt->width; | ||
425 | if (h_scale < 2) | ||
426 | h_scale = 1; | ||
427 | else if (h_scale >= 4) | ||
428 | h_scale = 4; | ||
429 | else | ||
430 | h_scale = 2; | ||
431 | cfg->xsize *= h_scale; | ||
432 | if (cfg->xsize < expected_xsize) { | ||
433 | if ((standard_id & V4L2_STD_525_60) || | ||
434 | (standard_id & V4L2_STD_625_50)) { | ||
435 | calculated_xsize = (cfg->xsize * | ||
436 | VPBE_DISPLAY_H_EXP_RATIO_N) / | ||
437 | VPBE_DISPLAY_H_EXP_RATIO_D; | ||
438 | if (calculated_xsize <= expected_xsize) { | ||
439 | h_exp = 1; | ||
440 | cfg->xsize = calculated_xsize; | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | if (h_scale == 2) | ||
445 | layer_info->h_zoom = ZOOM_X2; | ||
446 | else if (h_scale == 4) | ||
447 | layer_info->h_zoom = ZOOM_X4; | ||
448 | if (h_exp) | ||
449 | layer_info->h_exp = H_EXP_9_OVER_8; | ||
450 | } else { | ||
451 | /* no scaling, only cropping. Set display area to crop area */ | ||
452 | cfg->xsize = expected_xsize; | ||
453 | } | ||
454 | |||
455 | if (pixfmt->height < expected_ysize) { | ||
456 | v_scale = expected_ysize / pixfmt->height; | ||
457 | if (v_scale < 2) | ||
458 | v_scale = 1; | ||
459 | else if (v_scale >= 4) | ||
460 | v_scale = 4; | ||
461 | else | ||
462 | v_scale = 2; | ||
463 | cfg->ysize *= v_scale; | ||
464 | if (cfg->ysize < expected_ysize) { | ||
465 | if ((standard_id & V4L2_STD_625_50)) { | ||
466 | calculated_xsize = (cfg->ysize * | ||
467 | VPBE_DISPLAY_V_EXP_RATIO_N) / | ||
468 | VPBE_DISPLAY_V_EXP_RATIO_D; | ||
469 | if (calculated_xsize <= expected_ysize) { | ||
470 | v_exp = 1; | ||
471 | cfg->ysize = calculated_xsize; | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | if (v_scale == 2) | ||
476 | layer_info->v_zoom = ZOOM_X2; | ||
477 | else if (v_scale == 4) | ||
478 | layer_info->v_zoom = ZOOM_X4; | ||
479 | if (v_exp) | ||
480 | layer_info->h_exp = V_EXP_6_OVER_5; | ||
481 | } else { | ||
482 | /* no scaling, only cropping. Set display area to crop area */ | ||
483 | cfg->ysize = expected_ysize; | ||
484 | } | ||
485 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
486 | "crop display xsize = %d, ysize = %d\n", | ||
487 | cfg->xsize, cfg->ysize); | ||
488 | } | ||
489 | |||
490 | static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, | ||
491 | struct vpbe_layer *layer, | ||
492 | int top, int left) | ||
493 | { | ||
494 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
495 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
496 | |||
497 | cfg->xpos = min((unsigned int)left, | ||
498 | vpbe_dev->current_timings.xres - cfg->xsize); | ||
499 | cfg->ypos = min((unsigned int)top, | ||
500 | vpbe_dev->current_timings.yres - cfg->ysize); | ||
501 | |||
502 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
503 | "new xpos = %d, ypos = %d\n", | ||
504 | cfg->xpos, cfg->ypos); | ||
505 | } | ||
506 | |||
507 | static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev, | ||
508 | struct v4l2_rect *c) | ||
509 | { | ||
510 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
511 | |||
512 | if ((c->width == 0) || | ||
513 | ((c->width + c->left) > vpbe_dev->current_timings.xres)) | ||
514 | c->width = vpbe_dev->current_timings.xres - c->left; | ||
515 | |||
516 | if ((c->height == 0) || ((c->height + c->top) > | ||
517 | vpbe_dev->current_timings.yres)) | ||
518 | c->height = vpbe_dev->current_timings.yres - c->top; | ||
519 | |||
520 | /* window height must be even for interlaced display */ | ||
521 | if (vpbe_dev->current_timings.interlaced) | ||
522 | c->height &= (~0x01); | ||
523 | |||
524 | } | ||
525 | |||
526 | /** | ||
527 | * vpbe_try_format() | ||
528 | * If user application provides width and height, and have bytesperline set | ||
529 | * to zero, driver calculates bytesperline and sizeimage based on hardware | ||
530 | * limits. | ||
531 | */ | ||
532 | static int vpbe_try_format(struct vpbe_display *disp_dev, | ||
533 | struct v4l2_pix_format *pixfmt, int check) | ||
534 | { | ||
535 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
536 | int min_height = 1; | ||
537 | int min_width = 32; | ||
538 | int max_height; | ||
539 | int max_width; | ||
540 | int bpp; | ||
541 | |||
542 | if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && | ||
543 | (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) | ||
544 | /* choose default as V4L2_PIX_FMT_UYVY */ | ||
545 | pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; | ||
546 | |||
547 | /* Check the field format */ | ||
548 | if ((pixfmt->field != V4L2_FIELD_INTERLACED) && | ||
549 | (pixfmt->field != V4L2_FIELD_NONE)) { | ||
550 | if (vpbe_dev->current_timings.interlaced) | ||
551 | pixfmt->field = V4L2_FIELD_INTERLACED; | ||
552 | else | ||
553 | pixfmt->field = V4L2_FIELD_NONE; | ||
554 | } | ||
555 | |||
556 | if (pixfmt->field == V4L2_FIELD_INTERLACED) | ||
557 | min_height = 2; | ||
558 | |||
559 | if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) | ||
560 | bpp = 1; | ||
561 | else | ||
562 | bpp = 2; | ||
563 | |||
564 | max_width = vpbe_dev->current_timings.xres; | ||
565 | max_height = vpbe_dev->current_timings.yres; | ||
566 | |||
567 | min_width /= bpp; | ||
568 | |||
569 | if (!pixfmt->width || (pixfmt->width < min_width) || | ||
570 | (pixfmt->width > max_width)) { | ||
571 | pixfmt->width = vpbe_dev->current_timings.xres; | ||
572 | } | ||
573 | |||
574 | if (!pixfmt->height || (pixfmt->height < min_height) || | ||
575 | (pixfmt->height > max_height)) { | ||
576 | pixfmt->height = vpbe_dev->current_timings.yres; | ||
577 | } | ||
578 | |||
579 | if (pixfmt->bytesperline < (pixfmt->width * bpp)) | ||
580 | pixfmt->bytesperline = pixfmt->width * bpp; | ||
581 | |||
582 | /* Make the bytesperline 32 byte aligned */ | ||
583 | pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31); | ||
584 | |||
585 | if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) | ||
586 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height + | ||
587 | (pixfmt->bytesperline * pixfmt->height >> 1); | ||
588 | else | ||
589 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
590 | |||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | static int vpbe_display_g_priority(struct file *file, void *priv, | ||
595 | enum v4l2_priority *p) | ||
596 | { | ||
597 | struct vpbe_fh *fh = file->private_data; | ||
598 | struct vpbe_layer *layer = fh->layer; | ||
599 | |||
600 | *p = v4l2_prio_max(&layer->prio); | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | static int vpbe_display_s_priority(struct file *file, void *priv, | ||
606 | enum v4l2_priority p) | ||
607 | { | ||
608 | struct vpbe_fh *fh = file->private_data; | ||
609 | struct vpbe_layer *layer = fh->layer; | ||
610 | int ret; | ||
611 | |||
612 | ret = v4l2_prio_change(&layer->prio, &fh->prio, p); | ||
613 | |||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | static int vpbe_display_querycap(struct file *file, void *priv, | ||
618 | struct v4l2_capability *cap) | ||
619 | { | ||
620 | struct vpbe_fh *fh = file->private_data; | ||
621 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
622 | |||
623 | cap->version = VPBE_DISPLAY_VERSION_CODE; | ||
624 | cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; | ||
625 | strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver)); | ||
626 | strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info)); | ||
627 | strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int vpbe_display_s_crop(struct file *file, void *priv, | ||
633 | struct v4l2_crop *crop) | ||
634 | { | ||
635 | struct vpbe_fh *fh = file->private_data; | ||
636 | struct vpbe_layer *layer = fh->layer; | ||
637 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
638 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
639 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
640 | struct osd_state *osd_device = disp_dev->osd_device; | ||
641 | struct v4l2_rect *rect = &crop->c; | ||
642 | int ret; | ||
643 | |||
644 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
645 | "VIDIOC_S_CROP, layer id = %d\n", layer->device_id); | ||
646 | |||
647 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
648 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); | ||
649 | return -EINVAL; | ||
650 | } | ||
651 | |||
652 | if (rect->top < 0) | ||
653 | rect->top = 0; | ||
654 | if (rect->left < 0) | ||
655 | rect->left = 0; | ||
656 | |||
657 | vpbe_disp_check_window_params(disp_dev, rect); | ||
658 | |||
659 | osd_device->ops.get_layer_config(osd_device, | ||
660 | layer->layer_info.id, cfg); | ||
661 | |||
662 | vpbe_disp_calculate_scale_factor(disp_dev, layer, | ||
663 | rect->width, | ||
664 | rect->height); | ||
665 | vpbe_disp_adj_position(disp_dev, layer, rect->top, | ||
666 | rect->left); | ||
667 | ret = osd_device->ops.set_layer_config(osd_device, | ||
668 | layer->layer_info.id, cfg); | ||
669 | if (ret < 0) { | ||
670 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
671 | "Error in set layer config:\n"); | ||
672 | return -EINVAL; | ||
673 | } | ||
674 | |||
675 | /* apply zooming and h or v expansion */ | ||
676 | osd_device->ops.set_zoom(osd_device, | ||
677 | layer->layer_info.id, | ||
678 | layer->layer_info.h_zoom, | ||
679 | layer->layer_info.v_zoom); | ||
680 | ret = osd_device->ops.set_vid_expansion(osd_device, | ||
681 | layer->layer_info.h_exp, | ||
682 | layer->layer_info.v_exp); | ||
683 | if (ret < 0) { | ||
684 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
685 | "Error in set vid expansion:\n"); | ||
686 | return -EINVAL; | ||
687 | } | ||
688 | |||
689 | if ((layer->layer_info.h_zoom != ZOOM_X1) || | ||
690 | (layer->layer_info.v_zoom != ZOOM_X1) || | ||
691 | (layer->layer_info.h_exp != H_EXP_OFF) || | ||
692 | (layer->layer_info.v_exp != V_EXP_OFF)) | ||
693 | /* Enable expansion filter */ | ||
694 | osd_device->ops.set_interpolation_filter(osd_device, 1); | ||
695 | else | ||
696 | osd_device->ops.set_interpolation_filter(osd_device, 0); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int vpbe_display_g_crop(struct file *file, void *priv, | ||
702 | struct v4l2_crop *crop) | ||
703 | { | ||
704 | struct vpbe_fh *fh = file->private_data; | ||
705 | struct vpbe_layer *layer = fh->layer; | ||
706 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
707 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
708 | struct osd_state *osd_device = fh->disp_dev->osd_device; | ||
709 | struct v4l2_rect *rect = &crop->c; | ||
710 | int ret; | ||
711 | |||
712 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
713 | "VIDIOC_G_CROP, layer id = %d\n", | ||
714 | layer->device_id); | ||
715 | |||
716 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
717 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); | ||
718 | ret = -EINVAL; | ||
719 | } | ||
720 | osd_device->ops.get_layer_config(osd_device, | ||
721 | layer->layer_info.id, cfg); | ||
722 | rect->top = cfg->ypos; | ||
723 | rect->left = cfg->xpos; | ||
724 | rect->width = cfg->xsize; | ||
725 | rect->height = cfg->ysize; | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int vpbe_display_cropcap(struct file *file, void *priv, | ||
731 | struct v4l2_cropcap *cropcap) | ||
732 | { | ||
733 | struct vpbe_fh *fh = file->private_data; | ||
734 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
735 | |||
736 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); | ||
737 | |||
738 | cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
739 | cropcap->bounds.left = 0; | ||
740 | cropcap->bounds.top = 0; | ||
741 | cropcap->bounds.width = vpbe_dev->current_timings.xres; | ||
742 | cropcap->bounds.height = vpbe_dev->current_timings.yres; | ||
743 | cropcap->pixelaspect = vpbe_dev->current_timings.aspect; | ||
744 | cropcap->defrect = cropcap->bounds; | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int vpbe_display_g_fmt(struct file *file, void *priv, | ||
749 | struct v4l2_format *fmt) | ||
750 | { | ||
751 | struct vpbe_fh *fh = file->private_data; | ||
752 | struct vpbe_layer *layer = fh->layer; | ||
753 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
754 | |||
755 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
756 | "VIDIOC_G_FMT, layer id = %d\n", | ||
757 | layer->device_id); | ||
758 | |||
759 | /* If buffer type is video output */ | ||
760 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { | ||
761 | v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); | ||
762 | return -EINVAL; | ||
763 | } | ||
764 | /* Fill in the information about format */ | ||
765 | fmt->fmt.pix = layer->pix_fmt; | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | static int vpbe_display_enum_fmt(struct file *file, void *priv, | ||
771 | struct v4l2_fmtdesc *fmt) | ||
772 | { | ||
773 | struct vpbe_fh *fh = file->private_data; | ||
774 | struct vpbe_layer *layer = fh->layer; | ||
775 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
776 | unsigned int index = 0; | ||
777 | |||
778 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
779 | "VIDIOC_ENUM_FMT, layer id = %d\n", | ||
780 | layer->device_id); | ||
781 | if (fmt->index > 1) { | ||
782 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | |||
786 | /* Fill in the information about format */ | ||
787 | index = fmt->index; | ||
788 | memset(fmt, 0, sizeof(*fmt)); | ||
789 | fmt->index = index; | ||
790 | fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
791 | if (index == 0) { | ||
792 | strcpy(fmt->description, "YUV 4:2:2 - UYVY"); | ||
793 | fmt->pixelformat = V4L2_PIX_FMT_UYVY; | ||
794 | } else { | ||
795 | strcpy(fmt->description, "Y/CbCr 4:2:0"); | ||
796 | fmt->pixelformat = V4L2_PIX_FMT_NV12; | ||
797 | } | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static int vpbe_display_s_fmt(struct file *file, void *priv, | ||
803 | struct v4l2_format *fmt) | ||
804 | { | ||
805 | struct vpbe_fh *fh = file->private_data; | ||
806 | struct vpbe_layer *layer = fh->layer; | ||
807 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
808 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
809 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
810 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
811 | struct osd_state *osd_device = disp_dev->osd_device; | ||
812 | int ret; | ||
813 | |||
814 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
815 | "VIDIOC_S_FMT, layer id = %d\n", | ||
816 | layer->device_id); | ||
817 | |||
818 | /* If streaming is started, return error */ | ||
819 | if (layer->started) { | ||
820 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
821 | return -EBUSY; | ||
822 | } | ||
823 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { | ||
824 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); | ||
825 | return -EINVAL; | ||
826 | } | ||
827 | /* Check for valid pixel format */ | ||
828 | ret = vpbe_try_format(disp_dev, pixfmt, 1); | ||
829 | if (ret) | ||
830 | return ret; | ||
831 | |||
832 | /* YUV420 is requested, check availability of the | ||
833 | other video window */ | ||
834 | |||
835 | layer->pix_fmt = *pixfmt; | ||
836 | |||
837 | /* Get osd layer config */ | ||
838 | osd_device->ops.get_layer_config(osd_device, | ||
839 | layer->layer_info.id, cfg); | ||
840 | /* Store the pixel format in the layer object */ | ||
841 | cfg->xsize = pixfmt->width; | ||
842 | cfg->ysize = pixfmt->height; | ||
843 | cfg->line_length = pixfmt->bytesperline; | ||
844 | cfg->ypos = 0; | ||
845 | cfg->xpos = 0; | ||
846 | cfg->interlaced = vpbe_dev->current_timings.interlaced; | ||
847 | |||
848 | if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat) | ||
849 | cfg->pixfmt = PIXFMT_YCbCrI; | ||
850 | |||
851 | /* Change of the default pixel format for both video windows */ | ||
852 | if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { | ||
853 | struct vpbe_layer *otherlayer; | ||
854 | cfg->pixfmt = PIXFMT_NV12; | ||
855 | otherlayer = _vpbe_display_get_other_win_layer(disp_dev, | ||
856 | layer); | ||
857 | otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; | ||
858 | } | ||
859 | |||
860 | /* Set the layer config in the osd window */ | ||
861 | ret = osd_device->ops.set_layer_config(osd_device, | ||
862 | layer->layer_info.id, cfg); | ||
863 | if (ret < 0) { | ||
864 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
865 | "Error in S_FMT params:\n"); | ||
866 | return -EINVAL; | ||
867 | } | ||
868 | |||
869 | /* Readback and fill the local copy of current pix format */ | ||
870 | osd_device->ops.get_layer_config(osd_device, | ||
871 | layer->layer_info.id, cfg); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int vpbe_display_try_fmt(struct file *file, void *priv, | ||
877 | struct v4l2_format *fmt) | ||
878 | { | ||
879 | struct vpbe_fh *fh = file->private_data; | ||
880 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
881 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
882 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
883 | |||
884 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); | ||
885 | |||
886 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { | ||
887 | v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); | ||
888 | return -EINVAL; | ||
889 | } | ||
890 | |||
891 | /* Check for valid field format */ | ||
892 | return vpbe_try_format(disp_dev, pixfmt, 0); | ||
893 | |||
894 | } | ||
895 | |||
896 | /** | ||
897 | * vpbe_display_s_std - Set the given standard in the encoder | ||
898 | * | ||
899 | * Sets the standard if supported by the current encoder. Return the status. | ||
900 | * 0 - success & -EINVAL on error | ||
901 | */ | ||
902 | static int vpbe_display_s_std(struct file *file, void *priv, | ||
903 | v4l2_std_id *std_id) | ||
904 | { | ||
905 | struct vpbe_fh *fh = priv; | ||
906 | struct vpbe_layer *layer = fh->layer; | ||
907 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
908 | int ret; | ||
909 | |||
910 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); | ||
911 | |||
912 | /* If streaming is started, return error */ | ||
913 | if (layer->started) { | ||
914 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
915 | return -EBUSY; | ||
916 | } | ||
917 | if (NULL != vpbe_dev->ops.s_std) { | ||
918 | ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); | ||
919 | if (ret) { | ||
920 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
921 | "Failed to set standard for sub devices\n"); | ||
922 | return -EINVAL; | ||
923 | } | ||
924 | } else { | ||
925 | return -EINVAL; | ||
926 | } | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | /** | ||
932 | * vpbe_display_g_std - Get the standard in the current encoder | ||
933 | * | ||
934 | * Get the standard in the current encoder. Return the status. 0 - success | ||
935 | * -EINVAL on error | ||
936 | */ | ||
937 | static int vpbe_display_g_std(struct file *file, void *priv, | ||
938 | v4l2_std_id *std_id) | ||
939 | { | ||
940 | struct vpbe_fh *fh = priv; | ||
941 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
942 | |||
943 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); | ||
944 | |||
945 | /* Get the standard from the current encoder */ | ||
946 | if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { | ||
947 | *std_id = vpbe_dev->current_timings.timings.std_id; | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | return -EINVAL; | ||
952 | } | ||
953 | |||
954 | /** | ||
955 | * vpbe_display_enum_output - enumerate outputs | ||
956 | * | ||
957 | * Enumerates the outputs available at the vpbe display | ||
958 | * returns the status, -EINVAL if end of output list | ||
959 | */ | ||
960 | static int vpbe_display_enum_output(struct file *file, void *priv, | ||
961 | struct v4l2_output *output) | ||
962 | { | ||
963 | struct vpbe_fh *fh = priv; | ||
964 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
965 | int ret; | ||
966 | |||
967 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); | ||
968 | |||
969 | /* Enumerate outputs */ | ||
970 | |||
971 | if (NULL == vpbe_dev->ops.enum_outputs) | ||
972 | return -EINVAL; | ||
973 | |||
974 | ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); | ||
975 | if (ret) { | ||
976 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
977 | "Failed to enumerate outputs\n"); | ||
978 | return -EINVAL; | ||
979 | } | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /** | ||
985 | * vpbe_display_s_output - Set output to | ||
986 | * the output specified by the index | ||
987 | */ | ||
988 | static int vpbe_display_s_output(struct file *file, void *priv, | ||
989 | unsigned int i) | ||
990 | { | ||
991 | struct vpbe_fh *fh = priv; | ||
992 | struct vpbe_layer *layer = fh->layer; | ||
993 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
994 | int ret; | ||
995 | |||
996 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); | ||
997 | /* If streaming is started, return error */ | ||
998 | if (layer->started) { | ||
999 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
1000 | return -EBUSY; | ||
1001 | } | ||
1002 | if (NULL == vpbe_dev->ops.set_output) | ||
1003 | return -EINVAL; | ||
1004 | |||
1005 | ret = vpbe_dev->ops.set_output(vpbe_dev, i); | ||
1006 | if (ret) { | ||
1007 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1008 | "Failed to set output for sub devices\n"); | ||
1009 | return -EINVAL; | ||
1010 | } | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | /** | ||
1016 | * vpbe_display_g_output - Get output from subdevice | ||
1017 | * for a given by the index | ||
1018 | */ | ||
1019 | static int vpbe_display_g_output(struct file *file, void *priv, | ||
1020 | unsigned int *i) | ||
1021 | { | ||
1022 | struct vpbe_fh *fh = priv; | ||
1023 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1024 | |||
1025 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); | ||
1026 | /* Get the standard from the current encoder */ | ||
1027 | *i = vpbe_dev->current_out_index; | ||
1028 | |||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | /** | ||
1033 | * vpbe_display_enum_dv_presets - Enumerate the dv presets | ||
1034 | * | ||
1035 | * enum the preset in the current encoder. Return the status. 0 - success | ||
1036 | * -EINVAL on error | ||
1037 | */ | ||
1038 | static int | ||
1039 | vpbe_display_enum_dv_presets(struct file *file, void *priv, | ||
1040 | struct v4l2_dv_enum_preset *preset) | ||
1041 | { | ||
1042 | struct vpbe_fh *fh = priv; | ||
1043 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1044 | int ret; | ||
1045 | |||
1046 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); | ||
1047 | |||
1048 | /* Enumerate outputs */ | ||
1049 | if (NULL == vpbe_dev->ops.enum_dv_presets) | ||
1050 | return -EINVAL; | ||
1051 | |||
1052 | ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); | ||
1053 | if (ret) { | ||
1054 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1055 | "Failed to enumerate dv presets info\n"); | ||
1056 | return -EINVAL; | ||
1057 | } | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | /** | ||
1063 | * vpbe_display_s_dv_preset - Set the dv presets | ||
1064 | * | ||
1065 | * Set the preset in the current encoder. Return the status. 0 - success | ||
1066 | * -EINVAL on error | ||
1067 | */ | ||
1068 | static int | ||
1069 | vpbe_display_s_dv_preset(struct file *file, void *priv, | ||
1070 | struct v4l2_dv_preset *preset) | ||
1071 | { | ||
1072 | struct vpbe_fh *fh = priv; | ||
1073 | struct vpbe_layer *layer = fh->layer; | ||
1074 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1075 | int ret; | ||
1076 | |||
1077 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); | ||
1078 | |||
1079 | |||
1080 | /* If streaming is started, return error */ | ||
1081 | if (layer->started) { | ||
1082 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
1083 | return -EBUSY; | ||
1084 | } | ||
1085 | |||
1086 | /* Set the given standard in the encoder */ | ||
1087 | if (NULL != vpbe_dev->ops.s_dv_preset) | ||
1088 | return -EINVAL; | ||
1089 | |||
1090 | ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); | ||
1091 | if (ret) { | ||
1092 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1093 | "Failed to set the dv presets info\n"); | ||
1094 | return -EINVAL; | ||
1095 | } | ||
1096 | /* set the current norm to zero to be consistent. If STD is used | ||
1097 | * v4l2 layer will set the norm properly on successful s_std call | ||
1098 | */ | ||
1099 | layer->video_dev.current_norm = 0; | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | /** | ||
1105 | * vpbe_display_g_dv_preset - Set the dv presets | ||
1106 | * | ||
1107 | * Get the preset in the current encoder. Return the status. 0 - success | ||
1108 | * -EINVAL on error | ||
1109 | */ | ||
1110 | static int | ||
1111 | vpbe_display_g_dv_preset(struct file *file, void *priv, | ||
1112 | struct v4l2_dv_preset *dv_preset) | ||
1113 | { | ||
1114 | struct vpbe_fh *fh = priv; | ||
1115 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1116 | |||
1117 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); | ||
1118 | |||
1119 | /* Get the given standard in the encoder */ | ||
1120 | |||
1121 | if (vpbe_dev->current_timings.timings_type & | ||
1122 | VPBE_ENC_DV_PRESET) { | ||
1123 | dv_preset->preset = | ||
1124 | vpbe_dev->current_timings.timings.dv_preset; | ||
1125 | } else { | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int vpbe_display_streamoff(struct file *file, void *priv, | ||
1133 | enum v4l2_buf_type buf_type) | ||
1134 | { | ||
1135 | struct vpbe_fh *fh = file->private_data; | ||
1136 | struct vpbe_layer *layer = fh->layer; | ||
1137 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1138 | struct osd_state *osd_device = fh->disp_dev->osd_device; | ||
1139 | int ret; | ||
1140 | |||
1141 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1142 | "VIDIOC_STREAMOFF,layer id = %d\n", | ||
1143 | layer->device_id); | ||
1144 | |||
1145 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { | ||
1146 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1147 | return -EINVAL; | ||
1148 | } | ||
1149 | |||
1150 | /* If io is allowed for this file handle, return error */ | ||
1151 | if (!fh->io_allowed) { | ||
1152 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1153 | return -EACCES; | ||
1154 | } | ||
1155 | |||
1156 | /* If streaming is not started, return error */ | ||
1157 | if (!layer->started) { | ||
1158 | v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer" | ||
1159 | " id = %d\n", layer->device_id); | ||
1160 | return -EINVAL; | ||
1161 | } | ||
1162 | |||
1163 | osd_device->ops.disable_layer(osd_device, | ||
1164 | layer->layer_info.id); | ||
1165 | layer->started = 0; | ||
1166 | ret = videobuf_streamoff(&layer->buffer_queue); | ||
1167 | |||
1168 | return ret; | ||
1169 | } | ||
1170 | |||
1171 | static int vpbe_display_streamon(struct file *file, void *priv, | ||
1172 | enum v4l2_buf_type buf_type) | ||
1173 | { | ||
1174 | struct vpbe_fh *fh = file->private_data; | ||
1175 | struct vpbe_layer *layer = fh->layer; | ||
1176 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
1177 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1178 | struct osd_state *osd_device = disp_dev->osd_device; | ||
1179 | int ret; | ||
1180 | |||
1181 | osd_device->ops.disable_layer(osd_device, | ||
1182 | layer->layer_info.id); | ||
1183 | |||
1184 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n", | ||
1185 | layer->device_id); | ||
1186 | |||
1187 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { | ||
1188 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1189 | return -EINVAL; | ||
1190 | } | ||
1191 | |||
1192 | /* If file handle is not allowed IO, return error */ | ||
1193 | if (!fh->io_allowed) { | ||
1194 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1195 | return -EACCES; | ||
1196 | } | ||
1197 | /* If Streaming is already started, return error */ | ||
1198 | if (layer->started) { | ||
1199 | v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n"); | ||
1200 | return -EBUSY; | ||
1201 | } | ||
1202 | |||
1203 | /* | ||
1204 | * Call videobuf_streamon to start streaming | ||
1205 | * in videobuf | ||
1206 | */ | ||
1207 | ret = videobuf_streamon(&layer->buffer_queue); | ||
1208 | if (ret) { | ||
1209 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1210 | "error in videobuf_streamon\n"); | ||
1211 | return ret; | ||
1212 | } | ||
1213 | /* If buffer queue is empty, return error */ | ||
1214 | if (list_empty(&layer->dma_queue)) { | ||
1215 | v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); | ||
1216 | goto streamoff; | ||
1217 | } | ||
1218 | /* Get the next frame from the buffer queue */ | ||
1219 | layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, | ||
1220 | struct videobuf_buffer, queue); | ||
1221 | /* Remove buffer from the buffer queue */ | ||
1222 | list_del(&layer->cur_frm->queue); | ||
1223 | /* Mark state of the current frame to active */ | ||
1224 | layer->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1225 | /* Initialize field_id and started member */ | ||
1226 | layer->field_id = 0; | ||
1227 | |||
1228 | /* Set parameters in OSD and VENC */ | ||
1229 | ret = vpbe_set_osd_display_params(disp_dev, layer); | ||
1230 | if (ret < 0) | ||
1231 | goto streamoff; | ||
1232 | |||
1233 | /* | ||
1234 | * if request format is yuv420 semiplanar, need to | ||
1235 | * enable both video windows | ||
1236 | */ | ||
1237 | layer->started = 1; | ||
1238 | |||
1239 | layer->layer_first_int = 1; | ||
1240 | |||
1241 | return ret; | ||
1242 | streamoff: | ||
1243 | ret = videobuf_streamoff(&layer->buffer_queue); | ||
1244 | return ret; | ||
1245 | } | ||
1246 | |||
1247 | static int vpbe_display_dqbuf(struct file *file, void *priv, | ||
1248 | struct v4l2_buffer *buf) | ||
1249 | { | ||
1250 | struct vpbe_fh *fh = file->private_data; | ||
1251 | struct vpbe_layer *layer = fh->layer; | ||
1252 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1253 | int ret; | ||
1254 | |||
1255 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1256 | "VIDIOC_DQBUF, layer id = %d\n", | ||
1257 | layer->device_id); | ||
1258 | |||
1259 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { | ||
1260 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1261 | return -EINVAL; | ||
1262 | } | ||
1263 | /* If this file handle is not allowed to do IO, return error */ | ||
1264 | if (!fh->io_allowed) { | ||
1265 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1266 | return -EACCES; | ||
1267 | } | ||
1268 | if (file->f_flags & O_NONBLOCK) | ||
1269 | /* Call videobuf_dqbuf for non blocking mode */ | ||
1270 | ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1); | ||
1271 | else | ||
1272 | /* Call videobuf_dqbuf for blocking mode */ | ||
1273 | ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0); | ||
1274 | |||
1275 | return ret; | ||
1276 | } | ||
1277 | |||
1278 | static int vpbe_display_qbuf(struct file *file, void *priv, | ||
1279 | struct v4l2_buffer *p) | ||
1280 | { | ||
1281 | struct vpbe_fh *fh = file->private_data; | ||
1282 | struct vpbe_layer *layer = fh->layer; | ||
1283 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1284 | |||
1285 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1286 | "VIDIOC_QBUF, layer id = %d\n", | ||
1287 | layer->device_id); | ||
1288 | |||
1289 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) { | ||
1290 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1291 | return -EINVAL; | ||
1292 | } | ||
1293 | |||
1294 | /* If this file handle is not allowed to do IO, return error */ | ||
1295 | if (!fh->io_allowed) { | ||
1296 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1297 | return -EACCES; | ||
1298 | } | ||
1299 | |||
1300 | return videobuf_qbuf(&layer->buffer_queue, p); | ||
1301 | } | ||
1302 | |||
1303 | static int vpbe_display_querybuf(struct file *file, void *priv, | ||
1304 | struct v4l2_buffer *buf) | ||
1305 | { | ||
1306 | struct vpbe_fh *fh = file->private_data; | ||
1307 | struct vpbe_layer *layer = fh->layer; | ||
1308 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1309 | int ret; | ||
1310 | |||
1311 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1312 | "VIDIOC_QUERYBUF, layer id = %d\n", | ||
1313 | layer->device_id); | ||
1314 | |||
1315 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { | ||
1316 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1317 | return -EINVAL; | ||
1318 | } | ||
1319 | |||
1320 | /* Call videobuf_querybuf to get information */ | ||
1321 | ret = videobuf_querybuf(&layer->buffer_queue, buf); | ||
1322 | |||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1326 | static int vpbe_display_reqbufs(struct file *file, void *priv, | ||
1327 | struct v4l2_requestbuffers *req_buf) | ||
1328 | { | ||
1329 | struct vpbe_fh *fh = file->private_data; | ||
1330 | struct vpbe_layer *layer = fh->layer; | ||
1331 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1332 | int ret; | ||
1333 | |||
1334 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n"); | ||
1335 | |||
1336 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { | ||
1337 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1338 | return -EINVAL; | ||
1339 | } | ||
1340 | |||
1341 | /* If io users of the layer is not zero, return error */ | ||
1342 | if (0 != layer->io_usrs) { | ||
1343 | v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n"); | ||
1344 | return -EBUSY; | ||
1345 | } | ||
1346 | /* Initialize videobuf queue as per the buffer type */ | ||
1347 | videobuf_queue_dma_contig_init(&layer->buffer_queue, | ||
1348 | &video_qops, | ||
1349 | vpbe_dev->pdev, | ||
1350 | &layer->irqlock, | ||
1351 | V4L2_BUF_TYPE_VIDEO_OUTPUT, | ||
1352 | layer->pix_fmt.field, | ||
1353 | sizeof(struct videobuf_buffer), | ||
1354 | fh, NULL); | ||
1355 | |||
1356 | /* Set io allowed member of file handle to TRUE */ | ||
1357 | fh->io_allowed = 1; | ||
1358 | /* Increment io usrs member of layer object to 1 */ | ||
1359 | layer->io_usrs = 1; | ||
1360 | /* Store type of memory requested in layer object */ | ||
1361 | layer->memory = req_buf->memory; | ||
1362 | /* Initialize buffer queue */ | ||
1363 | INIT_LIST_HEAD(&layer->dma_queue); | ||
1364 | /* Allocate buffers */ | ||
1365 | ret = videobuf_reqbufs(&layer->buffer_queue, req_buf); | ||
1366 | |||
1367 | return ret; | ||
1368 | } | ||
1369 | |||
1370 | /* | ||
1371 | * vpbe_display_mmap() | ||
1372 | * It is used to map kernel space buffers into user spaces | ||
1373 | */ | ||
1374 | static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma) | ||
1375 | { | ||
1376 | /* Get the layer object and file handle object */ | ||
1377 | struct vpbe_fh *fh = filep->private_data; | ||
1378 | struct vpbe_layer *layer = fh->layer; | ||
1379 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1380 | |||
1381 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n"); | ||
1382 | |||
1383 | return videobuf_mmap_mapper(&layer->buffer_queue, vma); | ||
1384 | } | ||
1385 | |||
1386 | /* vpbe_display_poll(): It is used for select/poll system call | ||
1387 | */ | ||
1388 | static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait) | ||
1389 | { | ||
1390 | struct vpbe_fh *fh = filep->private_data; | ||
1391 | struct vpbe_layer *layer = fh->layer; | ||
1392 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1393 | unsigned int err = 0; | ||
1394 | |||
1395 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n"); | ||
1396 | if (layer->started) | ||
1397 | err = videobuf_poll_stream(filep, &layer->buffer_queue, wait); | ||
1398 | return err; | ||
1399 | } | ||
1400 | |||
1401 | /* | ||
1402 | * vpbe_display_open() | ||
1403 | * It creates object of file handle structure and stores it in private_data | ||
1404 | * member of filepointer | ||
1405 | */ | ||
1406 | static int vpbe_display_open(struct file *file) | ||
1407 | { | ||
1408 | struct vpbe_fh *fh = NULL; | ||
1409 | struct vpbe_layer *layer = video_drvdata(file); | ||
1410 | struct vpbe_display *disp_dev = layer->disp_dev; | ||
1411 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
1412 | struct osd_state *osd_device = disp_dev->osd_device; | ||
1413 | int err; | ||
1414 | |||
1415 | /* Allocate memory for the file handle object */ | ||
1416 | fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL); | ||
1417 | if (fh == NULL) { | ||
1418 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1419 | "unable to allocate memory for file handle object\n"); | ||
1420 | return -ENOMEM; | ||
1421 | } | ||
1422 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1423 | "vpbe display open plane = %d\n", | ||
1424 | layer->device_id); | ||
1425 | |||
1426 | /* store pointer to fh in private_data member of filep */ | ||
1427 | file->private_data = fh; | ||
1428 | fh->layer = layer; | ||
1429 | fh->disp_dev = disp_dev; | ||
1430 | |||
1431 | if (!layer->usrs) { | ||
1432 | |||
1433 | /* First claim the layer for this device */ | ||
1434 | err = osd_device->ops.request_layer(osd_device, | ||
1435 | layer->layer_info.id); | ||
1436 | if (err < 0) { | ||
1437 | /* Couldn't get layer */ | ||
1438 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1439 | "Display Manager failed to allocate layer\n"); | ||
1440 | kfree(fh); | ||
1441 | return -EINVAL; | ||
1442 | } | ||
1443 | } | ||
1444 | /* Increment layer usrs counter */ | ||
1445 | layer->usrs++; | ||
1446 | /* Set io_allowed member to false */ | ||
1447 | fh->io_allowed = 0; | ||
1448 | /* Initialize priority of this instance to default priority */ | ||
1449 | fh->prio = V4L2_PRIORITY_UNSET; | ||
1450 | v4l2_prio_open(&layer->prio, &fh->prio); | ||
1451 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1452 | "vpbe display device opened successfully\n"); | ||
1453 | return 0; | ||
1454 | } | ||
1455 | |||
1456 | /* | ||
1457 | * vpbe_display_release() | ||
1458 | * This function deletes buffer queue, frees the buffers and the davinci | ||
1459 | * display file * handle | ||
1460 | */ | ||
1461 | static int vpbe_display_release(struct file *file) | ||
1462 | { | ||
1463 | /* Get the layer object and file handle object */ | ||
1464 | struct vpbe_fh *fh = file->private_data; | ||
1465 | struct vpbe_layer *layer = fh->layer; | ||
1466 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
1467 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
1468 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
1469 | struct osd_state *osd_device = disp_dev->osd_device; | ||
1470 | |||
1471 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); | ||
1472 | |||
1473 | /* if this instance is doing IO */ | ||
1474 | if (fh->io_allowed) { | ||
1475 | /* Reset io_usrs member of layer object */ | ||
1476 | layer->io_usrs = 0; | ||
1477 | |||
1478 | osd_device->ops.disable_layer(osd_device, | ||
1479 | layer->layer_info.id); | ||
1480 | layer->started = 0; | ||
1481 | /* Free buffers allocated */ | ||
1482 | videobuf_queue_cancel(&layer->buffer_queue); | ||
1483 | videobuf_mmap_free(&layer->buffer_queue); | ||
1484 | } | ||
1485 | |||
1486 | /* Decrement layer usrs counter */ | ||
1487 | layer->usrs--; | ||
1488 | /* If this file handle has initialize encoder device, reset it */ | ||
1489 | if (!layer->usrs) { | ||
1490 | if (cfg->pixfmt == PIXFMT_NV12) { | ||
1491 | struct vpbe_layer *otherlayer; | ||
1492 | otherlayer = | ||
1493 | _vpbe_display_get_other_win_layer(disp_dev, layer); | ||
1494 | osd_device->ops.disable_layer(osd_device, | ||
1495 | otherlayer->layer_info.id); | ||
1496 | osd_device->ops.release_layer(osd_device, | ||
1497 | otherlayer->layer_info.id); | ||
1498 | } | ||
1499 | osd_device->ops.disable_layer(osd_device, | ||
1500 | layer->layer_info.id); | ||
1501 | osd_device->ops.release_layer(osd_device, | ||
1502 | layer->layer_info.id); | ||
1503 | } | ||
1504 | /* Close the priority */ | ||
1505 | v4l2_prio_close(&layer->prio, fh->prio); | ||
1506 | file->private_data = NULL; | ||
1507 | |||
1508 | /* Free memory allocated to file handle object */ | ||
1509 | kfree(fh); | ||
1510 | |||
1511 | disp_dev->cbcr_ofst = 0; | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1517 | static int vpbe_display_g_register(struct file *file, void *priv, | ||
1518 | struct v4l2_dbg_register *reg) | ||
1519 | { | ||
1520 | struct v4l2_dbg_match *match = ®->match; | ||
1521 | |||
1522 | if (match->type >= 2) { | ||
1523 | v4l2_subdev_call(vpbe_dev->venc, | ||
1524 | core, | ||
1525 | g_register, | ||
1526 | reg); | ||
1527 | } | ||
1528 | |||
1529 | return 0; | ||
1530 | } | ||
1531 | |||
1532 | static int vpbe_display_s_register(struct file *file, void *priv, | ||
1533 | struct v4l2_dbg_register *reg) | ||
1534 | { | ||
1535 | return 0; | ||
1536 | } | ||
1537 | #endif | ||
1538 | |||
1539 | /* vpbe capture ioctl operations */ | ||
1540 | static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { | ||
1541 | .vidioc_querycap = vpbe_display_querycap, | ||
1542 | .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, | ||
1543 | .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, | ||
1544 | .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, | ||
1545 | .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, | ||
1546 | .vidioc_reqbufs = vpbe_display_reqbufs, | ||
1547 | .vidioc_querybuf = vpbe_display_querybuf, | ||
1548 | .vidioc_qbuf = vpbe_display_qbuf, | ||
1549 | .vidioc_dqbuf = vpbe_display_dqbuf, | ||
1550 | .vidioc_streamon = vpbe_display_streamon, | ||
1551 | .vidioc_streamoff = vpbe_display_streamoff, | ||
1552 | .vidioc_cropcap = vpbe_display_cropcap, | ||
1553 | .vidioc_g_crop = vpbe_display_g_crop, | ||
1554 | .vidioc_s_crop = vpbe_display_s_crop, | ||
1555 | .vidioc_g_priority = vpbe_display_g_priority, | ||
1556 | .vidioc_s_priority = vpbe_display_s_priority, | ||
1557 | .vidioc_s_std = vpbe_display_s_std, | ||
1558 | .vidioc_g_std = vpbe_display_g_std, | ||
1559 | .vidioc_enum_output = vpbe_display_enum_output, | ||
1560 | .vidioc_s_output = vpbe_display_s_output, | ||
1561 | .vidioc_g_output = vpbe_display_g_output, | ||
1562 | .vidioc_s_dv_preset = vpbe_display_s_dv_preset, | ||
1563 | .vidioc_g_dv_preset = vpbe_display_g_dv_preset, | ||
1564 | .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, | ||
1565 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1566 | .vidioc_g_register = vpbe_display_g_register, | ||
1567 | .vidioc_s_register = vpbe_display_s_register, | ||
1568 | #endif | ||
1569 | }; | ||
1570 | |||
1571 | static struct v4l2_file_operations vpbe_fops = { | ||
1572 | .owner = THIS_MODULE, | ||
1573 | .open = vpbe_display_open, | ||
1574 | .release = vpbe_display_release, | ||
1575 | .unlocked_ioctl = video_ioctl2, | ||
1576 | .mmap = vpbe_display_mmap, | ||
1577 | .poll = vpbe_display_poll | ||
1578 | }; | ||
1579 | |||
1580 | static int vpbe_device_get(struct device *dev, void *data) | ||
1581 | { | ||
1582 | struct platform_device *pdev = to_platform_device(dev); | ||
1583 | struct vpbe_display *vpbe_disp = data; | ||
1584 | |||
1585 | if (strcmp("vpbe_controller", pdev->name) == 0) | ||
1586 | vpbe_disp->vpbe_dev = platform_get_drvdata(pdev); | ||
1587 | |||
1588 | if (strcmp("vpbe-osd", pdev->name) == 0) | ||
1589 | vpbe_disp->osd_device = platform_get_drvdata(pdev); | ||
1590 | |||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev, | ||
1595 | struct platform_device *pdev) | ||
1596 | { | ||
1597 | struct vpbe_layer *vpbe_display_layer = NULL; | ||
1598 | struct video_device *vbd = NULL; | ||
1599 | |||
1600 | /* Allocate memory for four plane display objects */ | ||
1601 | |||
1602 | disp_dev->dev[i] = | ||
1603 | kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL); | ||
1604 | |||
1605 | /* If memory allocation fails, return error */ | ||
1606 | if (!disp_dev->dev[i]) { | ||
1607 | printk(KERN_ERR "ran out of memory\n"); | ||
1608 | return -ENOMEM; | ||
1609 | } | ||
1610 | spin_lock_init(&disp_dev->dev[i]->irqlock); | ||
1611 | mutex_init(&disp_dev->dev[i]->opslock); | ||
1612 | |||
1613 | /* Get the pointer to the layer object */ | ||
1614 | vpbe_display_layer = disp_dev->dev[i]; | ||
1615 | vbd = &vpbe_display_layer->video_dev; | ||
1616 | /* Initialize field of video device */ | ||
1617 | vbd->release = video_device_release_empty; | ||
1618 | vbd->fops = &vpbe_fops; | ||
1619 | vbd->ioctl_ops = &vpbe_ioctl_ops; | ||
1620 | vbd->minor = -1; | ||
1621 | vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; | ||
1622 | vbd->lock = &vpbe_display_layer->opslock; | ||
1623 | |||
1624 | if (disp_dev->vpbe_dev->current_timings.timings_type & | ||
1625 | VPBE_ENC_STD) { | ||
1626 | vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); | ||
1627 | vbd->current_norm = | ||
1628 | disp_dev->vpbe_dev-> | ||
1629 | current_timings.timings.std_id; | ||
1630 | } else | ||
1631 | vbd->current_norm = 0; | ||
1632 | |||
1633 | snprintf(vbd->name, sizeof(vbd->name), | ||
1634 | "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", | ||
1635 | (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, | ||
1636 | (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, | ||
1637 | (VPBE_DISPLAY_VERSION_CODE) & 0xff); | ||
1638 | |||
1639 | vpbe_display_layer->device_id = i; | ||
1640 | |||
1641 | vpbe_display_layer->layer_info.id = | ||
1642 | ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); | ||
1643 | |||
1644 | /* Initialize prio member of layer object */ | ||
1645 | v4l2_prio_init(&vpbe_display_layer->prio); | ||
1646 | |||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | static __devinit int register_device(struct vpbe_layer *vpbe_display_layer, | ||
1651 | struct vpbe_display *disp_dev, | ||
1652 | struct platform_device *pdev) { | ||
1653 | int err; | ||
1654 | |||
1655 | v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, | ||
1656 | "Trying to register VPBE display device.\n"); | ||
1657 | v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, | ||
1658 | "layer=%x,layer->video_dev=%x\n", | ||
1659 | (int)vpbe_display_layer, | ||
1660 | (int)&vpbe_display_layer->video_dev); | ||
1661 | |||
1662 | err = video_register_device(&vpbe_display_layer->video_dev, | ||
1663 | VFL_TYPE_GRABBER, | ||
1664 | -1); | ||
1665 | if (err) | ||
1666 | return -ENODEV; | ||
1667 | |||
1668 | vpbe_display_layer->disp_dev = disp_dev; | ||
1669 | /* set the driver data in platform device */ | ||
1670 | platform_set_drvdata(pdev, disp_dev); | ||
1671 | video_set_drvdata(&vpbe_display_layer->video_dev, | ||
1672 | vpbe_display_layer); | ||
1673 | |||
1674 | return 0; | ||
1675 | } | ||
1676 | |||
1677 | |||
1678 | |||
1679 | /* | ||
1680 | * vpbe_display_probe() | ||
1681 | * This function creates device entries by register itself to the V4L2 driver | ||
1682 | * and initializes fields of each layer objects | ||
1683 | */ | ||
1684 | static __devinit int vpbe_display_probe(struct platform_device *pdev) | ||
1685 | { | ||
1686 | struct vpbe_layer *vpbe_display_layer; | ||
1687 | struct vpbe_display *disp_dev; | ||
1688 | struct resource *res = NULL; | ||
1689 | int k; | ||
1690 | int i; | ||
1691 | int err; | ||
1692 | int irq; | ||
1693 | |||
1694 | printk(KERN_DEBUG "vpbe_display_probe\n"); | ||
1695 | /* Allocate memory for vpbe_display */ | ||
1696 | disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL); | ||
1697 | if (!disp_dev) { | ||
1698 | printk(KERN_ERR "ran out of memory\n"); | ||
1699 | return -ENOMEM; | ||
1700 | } | ||
1701 | |||
1702 | spin_lock_init(&disp_dev->dma_queue_lock); | ||
1703 | /* | ||
1704 | * Scan all the platform devices to find the vpbe | ||
1705 | * controller device and get the vpbe_dev object | ||
1706 | */ | ||
1707 | err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev, | ||
1708 | vpbe_device_get); | ||
1709 | if (err < 0) | ||
1710 | return err; | ||
1711 | /* Initialize the vpbe display controller */ | ||
1712 | if (NULL != disp_dev->vpbe_dev->ops.initialize) { | ||
1713 | err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev, | ||
1714 | disp_dev->vpbe_dev); | ||
1715 | if (err) { | ||
1716 | v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, | ||
1717 | "Error initing vpbe\n"); | ||
1718 | err = -ENOMEM; | ||
1719 | goto probe_out; | ||
1720 | } | ||
1721 | } | ||
1722 | |||
1723 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1724 | if (init_vpbe_layer(i, disp_dev, pdev)) { | ||
1725 | err = -ENODEV; | ||
1726 | goto probe_out; | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1731 | if (!res) { | ||
1732 | v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, | ||
1733 | "Unable to get VENC interrupt resource\n"); | ||
1734 | err = -ENODEV; | ||
1735 | goto probe_out; | ||
1736 | } | ||
1737 | |||
1738 | irq = res->start; | ||
1739 | if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER, | ||
1740 | disp_dev)) { | ||
1741 | v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, | ||
1742 | "Unable to request interrupt\n"); | ||
1743 | err = -ENODEV; | ||
1744 | goto probe_out; | ||
1745 | } | ||
1746 | |||
1747 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1748 | if (register_device(disp_dev->dev[i], disp_dev, pdev)) { | ||
1749 | err = -ENODEV; | ||
1750 | goto probe_out; | ||
1751 | } | ||
1752 | } | ||
1753 | |||
1754 | printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); | ||
1755 | return 0; | ||
1756 | |||
1757 | probe_out: | ||
1758 | free_irq(res->start, disp_dev); | ||
1759 | for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { | ||
1760 | /* Get the pointer to the layer object */ | ||
1761 | vpbe_display_layer = disp_dev->dev[k]; | ||
1762 | /* Unregister video device */ | ||
1763 | if (vpbe_display_layer) { | ||
1764 | video_unregister_device( | ||
1765 | &vpbe_display_layer->video_dev); | ||
1766 | kfree(disp_dev->dev[k]); | ||
1767 | } | ||
1768 | } | ||
1769 | kfree(disp_dev); | ||
1770 | return err; | ||
1771 | } | ||
1772 | |||
1773 | /* | ||
1774 | * vpbe_display_remove() | ||
1775 | * It un-register hardware layer from V4L2 driver | ||
1776 | */ | ||
1777 | static int vpbe_display_remove(struct platform_device *pdev) | ||
1778 | { | ||
1779 | struct vpbe_layer *vpbe_display_layer; | ||
1780 | struct vpbe_display *disp_dev = platform_get_drvdata(pdev); | ||
1781 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
1782 | struct resource *res; | ||
1783 | int i; | ||
1784 | |||
1785 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); | ||
1786 | |||
1787 | /* unregister irq */ | ||
1788 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1789 | free_irq(res->start, disp_dev); | ||
1790 | |||
1791 | /* deinitialize the vpbe display controller */ | ||
1792 | if (NULL != vpbe_dev->ops.deinitialize) | ||
1793 | vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); | ||
1794 | /* un-register device */ | ||
1795 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1796 | /* Get the pointer to the layer object */ | ||
1797 | vpbe_display_layer = disp_dev->dev[i]; | ||
1798 | /* Unregister video device */ | ||
1799 | video_unregister_device(&vpbe_display_layer->video_dev); | ||
1800 | |||
1801 | } | ||
1802 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1803 | kfree(disp_dev->dev[i]); | ||
1804 | disp_dev->dev[i] = NULL; | ||
1805 | } | ||
1806 | |||
1807 | return 0; | ||
1808 | } | ||
1809 | |||
1810 | static struct platform_driver vpbe_display_driver = { | ||
1811 | .driver = { | ||
1812 | .name = VPBE_DISPLAY_DRIVER, | ||
1813 | .owner = THIS_MODULE, | ||
1814 | .bus = &platform_bus_type, | ||
1815 | }, | ||
1816 | .probe = vpbe_display_probe, | ||
1817 | .remove = __devexit_p(vpbe_display_remove), | ||
1818 | }; | ||
1819 | |||
1820 | /* | ||
1821 | * vpbe_display_init() | ||
1822 | * This function registers device and driver to the kernel, requests irq | ||
1823 | * handler and allocates memory for layer objects | ||
1824 | */ | ||
1825 | static __devinit int vpbe_display_init(void) | ||
1826 | { | ||
1827 | int err; | ||
1828 | |||
1829 | printk(KERN_DEBUG "vpbe_display_init\n"); | ||
1830 | |||
1831 | /* Register driver to the kernel */ | ||
1832 | err = platform_driver_register(&vpbe_display_driver); | ||
1833 | if (0 != err) | ||
1834 | return err; | ||
1835 | |||
1836 | printk(KERN_DEBUG "vpbe_display_init:" | ||
1837 | "VPBE V4L2 Display Driver V1.0 loaded\n"); | ||
1838 | return 0; | ||
1839 | } | ||
1840 | |||
1841 | /* | ||
1842 | * vpbe_display_cleanup() | ||
1843 | * This function un-registers device and driver to the kernel, frees requested | ||
1844 | * irq handler and de-allocates memory allocated for layer objects. | ||
1845 | */ | ||
1846 | static void vpbe_display_cleanup(void) | ||
1847 | { | ||
1848 | printk(KERN_DEBUG "vpbe_display_cleanup\n"); | ||
1849 | |||
1850 | /* platform driver unregister */ | ||
1851 | platform_driver_unregister(&vpbe_display_driver); | ||
1852 | } | ||
1853 | |||
1854 | /* Function for module initialization and cleanup */ | ||
1855 | module_init(vpbe_display_init); | ||
1856 | module_exit(vpbe_display_cleanup); | ||
1857 | |||
1858 | MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller"); | ||
1859 | MODULE_LICENSE("GPL"); | ||
1860 | MODULE_AUTHOR("Texas Instruments"); | ||
diff --git a/drivers/media/video/davinci/vpbe_osd.c b/drivers/media/video/davinci/vpbe_osd.c new file mode 100644 index 00000000000..5352884998f --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd.c | |||
@@ -0,0 +1,1231 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2010 Texas Instruments Inc | ||
3 | * Copyright (C) 2007 MontaVista Software, Inc. | ||
4 | * | ||
5 | * Andy Lowe (alowe@mvista.com), MontaVista Software | ||
6 | * - Initial version | ||
7 | * Murali Karicheri (mkaricheri@gmail.com), Texas Instruments Ltd. | ||
8 | * - ported to sub device interface | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation version 2. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/clk.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include <mach/io.h> | ||
32 | #include <mach/cputype.h> | ||
33 | #include <mach/hardware.h> | ||
34 | |||
35 | #include <media/davinci/vpss.h> | ||
36 | #include <media/v4l2-device.h> | ||
37 | #include <media/davinci/vpbe_types.h> | ||
38 | #include <media/davinci/vpbe_osd.h> | ||
39 | |||
40 | #include <linux/io.h> | ||
41 | #include "vpbe_osd_regs.h" | ||
42 | |||
43 | #define MODULE_NAME VPBE_OSD_SUBDEV_NAME | ||
44 | |||
45 | /* register access routines */ | ||
46 | static inline u32 osd_read(struct osd_state *sd, u32 offset) | ||
47 | { | ||
48 | struct osd_state *osd = sd; | ||
49 | |||
50 | return readl(osd->osd_base + offset); | ||
51 | } | ||
52 | |||
53 | static inline u32 osd_write(struct osd_state *sd, u32 val, u32 offset) | ||
54 | { | ||
55 | struct osd_state *osd = sd; | ||
56 | |||
57 | writel(val, osd->osd_base + offset); | ||
58 | |||
59 | return val; | ||
60 | } | ||
61 | |||
62 | static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) | ||
63 | { | ||
64 | struct osd_state *osd = sd; | ||
65 | |||
66 | u32 addr = osd->osd_base + offset; | ||
67 | u32 val = readl(addr) | mask; | ||
68 | |||
69 | writel(val, addr); | ||
70 | |||
71 | return val; | ||
72 | } | ||
73 | |||
74 | static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) | ||
75 | { | ||
76 | struct osd_state *osd = sd; | ||
77 | |||
78 | u32 addr = osd->osd_base + offset; | ||
79 | u32 val = readl(addr) & ~mask; | ||
80 | |||
81 | writel(val, addr); | ||
82 | |||
83 | return val; | ||
84 | } | ||
85 | |||
86 | static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, | ||
87 | u32 offset) | ||
88 | { | ||
89 | struct osd_state *osd = sd; | ||
90 | |||
91 | u32 addr = osd->osd_base + offset; | ||
92 | u32 new_val = (readl(addr) & ~mask) | (val & mask); | ||
93 | |||
94 | writel(new_val, addr); | ||
95 | |||
96 | return new_val; | ||
97 | } | ||
98 | |||
99 | /* define some macros for layer and pixfmt classification */ | ||
100 | #define is_osd_win(layer) (((layer) == WIN_OSD0) || ((layer) == WIN_OSD1)) | ||
101 | #define is_vid_win(layer) (((layer) == WIN_VID0) || ((layer) == WIN_VID1)) | ||
102 | #define is_rgb_pixfmt(pixfmt) \ | ||
103 | (((pixfmt) == PIXFMT_RGB565) || ((pixfmt) == PIXFMT_RGB888)) | ||
104 | #define is_yc_pixfmt(pixfmt) \ | ||
105 | (((pixfmt) == PIXFMT_YCbCrI) || ((pixfmt) == PIXFMT_YCrCbI) || \ | ||
106 | ((pixfmt) == PIXFMT_NV12)) | ||
107 | #define MAX_WIN_SIZE OSD_VIDWIN0XP_V0X | ||
108 | #define MAX_LINE_LENGTH (OSD_VIDWIN0OFST_V0LO << 5) | ||
109 | |||
110 | /** | ||
111 | * _osd_dm6446_vid0_pingpong() - field inversion fix for DM6446 | ||
112 | * @sd - ptr to struct osd_state | ||
113 | * @field_inversion - inversion flag | ||
114 | * @fb_base_phys - frame buffer address | ||
115 | * @lconfig - ptr to layer config | ||
116 | * | ||
117 | * This routine implements a workaround for the field signal inversion silicon | ||
118 | * erratum described in Advisory 1.3.8 for the DM6446. The fb_base_phys and | ||
119 | * lconfig parameters apply to the vid0 window. This routine should be called | ||
120 | * whenever the vid0 layer configuration or start address is modified, or when | ||
121 | * the OSD field inversion setting is modified. | ||
122 | * Returns: 1 if the ping-pong buffers need to be toggled in the vsync isr, or | ||
123 | * 0 otherwise | ||
124 | */ | ||
125 | static int _osd_dm6446_vid0_pingpong(struct osd_state *sd, | ||
126 | int field_inversion, | ||
127 | unsigned long fb_base_phys, | ||
128 | const struct osd_layer_config *lconfig) | ||
129 | { | ||
130 | struct osd_platform_data *pdata; | ||
131 | |||
132 | pdata = (struct osd_platform_data *)sd->dev->platform_data; | ||
133 | if (pdata->field_inv_wa_enable) { | ||
134 | |||
135 | if (!field_inversion || !lconfig->interlaced) { | ||
136 | osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); | ||
137 | osd_write(sd, fb_base_phys & ~0x1F, OSD_PPVWIN0ADR); | ||
138 | osd_modify(sd, OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, 0, | ||
139 | OSD_MISCCTL); | ||
140 | return 0; | ||
141 | } else { | ||
142 | unsigned miscctl = OSD_MISCCTL_PPRV; | ||
143 | |||
144 | osd_write(sd, | ||
145 | (fb_base_phys & ~0x1F) - lconfig->line_length, | ||
146 | OSD_VIDWIN0ADR); | ||
147 | osd_write(sd, | ||
148 | (fb_base_phys & ~0x1F) + lconfig->line_length, | ||
149 | OSD_PPVWIN0ADR); | ||
150 | osd_modify(sd, | ||
151 | OSD_MISCCTL_PPSW | OSD_MISCCTL_PPRV, miscctl, | ||
152 | OSD_MISCCTL); | ||
153 | |||
154 | return 1; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void _osd_set_field_inversion(struct osd_state *sd, int enable) | ||
162 | { | ||
163 | unsigned fsinv = 0; | ||
164 | |||
165 | if (enable) | ||
166 | fsinv = OSD_MODE_FSINV; | ||
167 | |||
168 | osd_modify(sd, OSD_MODE_FSINV, fsinv, OSD_MODE); | ||
169 | } | ||
170 | |||
171 | static void _osd_set_blink_attribute(struct osd_state *sd, int enable, | ||
172 | enum osd_blink_interval blink) | ||
173 | { | ||
174 | u32 osdatrmd = 0; | ||
175 | |||
176 | if (enable) { | ||
177 | osdatrmd |= OSD_OSDATRMD_BLNK; | ||
178 | osdatrmd |= blink << OSD_OSDATRMD_BLNKINT_SHIFT; | ||
179 | } | ||
180 | /* caller must ensure that OSD1 is configured in attribute mode */ | ||
181 | osd_modify(sd, OSD_OSDATRMD_BLNKINT | OSD_OSDATRMD_BLNK, osdatrmd, | ||
182 | OSD_OSDATRMD); | ||
183 | } | ||
184 | |||
185 | static void _osd_set_rom_clut(struct osd_state *sd, | ||
186 | enum osd_rom_clut rom_clut) | ||
187 | { | ||
188 | if (rom_clut == ROM_CLUT0) | ||
189 | osd_clear(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); | ||
190 | else | ||
191 | osd_set(sd, OSD_MISCCTL_RSEL, OSD_MISCCTL); | ||
192 | } | ||
193 | |||
194 | static void _osd_set_palette_map(struct osd_state *sd, | ||
195 | enum osd_win_layer osdwin, | ||
196 | unsigned char pixel_value, | ||
197 | unsigned char clut_index, | ||
198 | enum osd_pix_format pixfmt) | ||
199 | { | ||
200 | static const int map_2bpp[] = { 0, 5, 10, 15 }; | ||
201 | static const int map_1bpp[] = { 0, 15 }; | ||
202 | int bmp_offset; | ||
203 | int bmp_shift; | ||
204 | int bmp_mask; | ||
205 | int bmp_reg; | ||
206 | |||
207 | switch (pixfmt) { | ||
208 | case PIXFMT_1BPP: | ||
209 | bmp_reg = map_1bpp[pixel_value & 0x1]; | ||
210 | break; | ||
211 | case PIXFMT_2BPP: | ||
212 | bmp_reg = map_2bpp[pixel_value & 0x3]; | ||
213 | break; | ||
214 | case PIXFMT_4BPP: | ||
215 | bmp_reg = pixel_value & 0xf; | ||
216 | break; | ||
217 | default: | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | switch (osdwin) { | ||
222 | case OSDWIN_OSD0: | ||
223 | bmp_offset = OSD_W0BMP01 + (bmp_reg >> 1) * sizeof(u32); | ||
224 | break; | ||
225 | case OSDWIN_OSD1: | ||
226 | bmp_offset = OSD_W1BMP01 + (bmp_reg >> 1) * sizeof(u32); | ||
227 | break; | ||
228 | default: | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | if (bmp_reg & 1) { | ||
233 | bmp_shift = 8; | ||
234 | bmp_mask = 0xff << 8; | ||
235 | } else { | ||
236 | bmp_shift = 0; | ||
237 | bmp_mask = 0xff; | ||
238 | } | ||
239 | |||
240 | osd_modify(sd, bmp_mask, clut_index << bmp_shift, bmp_offset); | ||
241 | } | ||
242 | |||
243 | static void _osd_set_rec601_attenuation(struct osd_state *sd, | ||
244 | enum osd_win_layer osdwin, int enable) | ||
245 | { | ||
246 | switch (osdwin) { | ||
247 | case OSDWIN_OSD0: | ||
248 | osd_modify(sd, OSD_OSDWIN0MD_ATN0E, | ||
249 | enable ? OSD_OSDWIN0MD_ATN0E : 0, | ||
250 | OSD_OSDWIN0MD); | ||
251 | break; | ||
252 | case OSDWIN_OSD1: | ||
253 | osd_modify(sd, OSD_OSDWIN1MD_ATN1E, | ||
254 | enable ? OSD_OSDWIN1MD_ATN1E : 0, | ||
255 | OSD_OSDWIN1MD); | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | static void _osd_set_blending_factor(struct osd_state *sd, | ||
261 | enum osd_win_layer osdwin, | ||
262 | enum osd_blending_factor blend) | ||
263 | { | ||
264 | switch (osdwin) { | ||
265 | case OSDWIN_OSD0: | ||
266 | osd_modify(sd, OSD_OSDWIN0MD_BLND0, | ||
267 | blend << OSD_OSDWIN0MD_BLND0_SHIFT, OSD_OSDWIN0MD); | ||
268 | break; | ||
269 | case OSDWIN_OSD1: | ||
270 | osd_modify(sd, OSD_OSDWIN1MD_BLND1, | ||
271 | blend << OSD_OSDWIN1MD_BLND1_SHIFT, OSD_OSDWIN1MD); | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static void _osd_enable_color_key(struct osd_state *sd, | ||
277 | enum osd_win_layer osdwin, | ||
278 | unsigned colorkey, | ||
279 | enum osd_pix_format pixfmt) | ||
280 | { | ||
281 | switch (pixfmt) { | ||
282 | case PIXFMT_RGB565: | ||
283 | osd_write(sd, colorkey & OSD_TRANSPVAL_RGBTRANS, | ||
284 | OSD_TRANSPVAL); | ||
285 | break; | ||
286 | default: | ||
287 | break; | ||
288 | } | ||
289 | |||
290 | switch (osdwin) { | ||
291 | case OSDWIN_OSD0: | ||
292 | osd_set(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); | ||
293 | break; | ||
294 | case OSDWIN_OSD1: | ||
295 | osd_set(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); | ||
296 | break; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static void _osd_disable_color_key(struct osd_state *sd, | ||
301 | enum osd_win_layer osdwin) | ||
302 | { | ||
303 | switch (osdwin) { | ||
304 | case OSDWIN_OSD0: | ||
305 | osd_clear(sd, OSD_OSDWIN0MD_TE0, OSD_OSDWIN0MD); | ||
306 | break; | ||
307 | case OSDWIN_OSD1: | ||
308 | osd_clear(sd, OSD_OSDWIN1MD_TE1, OSD_OSDWIN1MD); | ||
309 | break; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | static void _osd_set_osd_clut(struct osd_state *sd, | ||
314 | enum osd_win_layer osdwin, | ||
315 | enum osd_clut clut) | ||
316 | { | ||
317 | u32 winmd = 0; | ||
318 | |||
319 | switch (osdwin) { | ||
320 | case OSDWIN_OSD0: | ||
321 | if (clut == RAM_CLUT) | ||
322 | winmd |= OSD_OSDWIN0MD_CLUTS0; | ||
323 | osd_modify(sd, OSD_OSDWIN0MD_CLUTS0, winmd, OSD_OSDWIN0MD); | ||
324 | break; | ||
325 | case OSDWIN_OSD1: | ||
326 | if (clut == RAM_CLUT) | ||
327 | winmd |= OSD_OSDWIN1MD_CLUTS1; | ||
328 | osd_modify(sd, OSD_OSDWIN1MD_CLUTS1, winmd, OSD_OSDWIN1MD); | ||
329 | break; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | static void _osd_set_zoom(struct osd_state *sd, enum osd_layer layer, | ||
334 | enum osd_zoom_factor h_zoom, | ||
335 | enum osd_zoom_factor v_zoom) | ||
336 | { | ||
337 | u32 winmd = 0; | ||
338 | |||
339 | switch (layer) { | ||
340 | case WIN_OSD0: | ||
341 | winmd |= (h_zoom << OSD_OSDWIN0MD_OHZ0_SHIFT); | ||
342 | winmd |= (v_zoom << OSD_OSDWIN0MD_OVZ0_SHIFT); | ||
343 | osd_modify(sd, OSD_OSDWIN0MD_OHZ0 | OSD_OSDWIN0MD_OVZ0, winmd, | ||
344 | OSD_OSDWIN0MD); | ||
345 | break; | ||
346 | case WIN_VID0: | ||
347 | winmd |= (h_zoom << OSD_VIDWINMD_VHZ0_SHIFT); | ||
348 | winmd |= (v_zoom << OSD_VIDWINMD_VVZ0_SHIFT); | ||
349 | osd_modify(sd, OSD_VIDWINMD_VHZ0 | OSD_VIDWINMD_VVZ0, winmd, | ||
350 | OSD_VIDWINMD); | ||
351 | break; | ||
352 | case WIN_OSD1: | ||
353 | winmd |= (h_zoom << OSD_OSDWIN1MD_OHZ1_SHIFT); | ||
354 | winmd |= (v_zoom << OSD_OSDWIN1MD_OVZ1_SHIFT); | ||
355 | osd_modify(sd, OSD_OSDWIN1MD_OHZ1 | OSD_OSDWIN1MD_OVZ1, winmd, | ||
356 | OSD_OSDWIN1MD); | ||
357 | break; | ||
358 | case WIN_VID1: | ||
359 | winmd |= (h_zoom << OSD_VIDWINMD_VHZ1_SHIFT); | ||
360 | winmd |= (v_zoom << OSD_VIDWINMD_VVZ1_SHIFT); | ||
361 | osd_modify(sd, OSD_VIDWINMD_VHZ1 | OSD_VIDWINMD_VVZ1, winmd, | ||
362 | OSD_VIDWINMD); | ||
363 | break; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | static void _osd_disable_layer(struct osd_state *sd, enum osd_layer layer) | ||
368 | { | ||
369 | switch (layer) { | ||
370 | case WIN_OSD0: | ||
371 | osd_clear(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); | ||
372 | break; | ||
373 | case WIN_VID0: | ||
374 | osd_clear(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); | ||
375 | break; | ||
376 | case WIN_OSD1: | ||
377 | /* disable attribute mode as well as disabling the window */ | ||
378 | osd_clear(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, | ||
379 | OSD_OSDWIN1MD); | ||
380 | break; | ||
381 | case WIN_VID1: | ||
382 | osd_clear(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); | ||
383 | break; | ||
384 | } | ||
385 | } | ||
386 | |||
387 | static void osd_disable_layer(struct osd_state *sd, enum osd_layer layer) | ||
388 | { | ||
389 | struct osd_state *osd = sd; | ||
390 | struct osd_window_state *win = &osd->win[layer]; | ||
391 | unsigned long flags; | ||
392 | |||
393 | spin_lock_irqsave(&osd->lock, flags); | ||
394 | |||
395 | if (!win->is_enabled) { | ||
396 | spin_unlock_irqrestore(&osd->lock, flags); | ||
397 | return; | ||
398 | } | ||
399 | win->is_enabled = 0; | ||
400 | |||
401 | _osd_disable_layer(sd, layer); | ||
402 | |||
403 | spin_unlock_irqrestore(&osd->lock, flags); | ||
404 | } | ||
405 | |||
406 | static void _osd_enable_attribute_mode(struct osd_state *sd) | ||
407 | { | ||
408 | /* enable attribute mode for OSD1 */ | ||
409 | osd_set(sd, OSD_OSDWIN1MD_OASW, OSD_OSDWIN1MD); | ||
410 | } | ||
411 | |||
412 | static void _osd_enable_layer(struct osd_state *sd, enum osd_layer layer) | ||
413 | { | ||
414 | switch (layer) { | ||
415 | case WIN_OSD0: | ||
416 | osd_set(sd, OSD_OSDWIN0MD_OACT0, OSD_OSDWIN0MD); | ||
417 | break; | ||
418 | case WIN_VID0: | ||
419 | osd_set(sd, OSD_VIDWINMD_ACT0, OSD_VIDWINMD); | ||
420 | break; | ||
421 | case WIN_OSD1: | ||
422 | /* enable OSD1 and disable attribute mode */ | ||
423 | osd_modify(sd, OSD_OSDWIN1MD_OASW | OSD_OSDWIN1MD_OACT1, | ||
424 | OSD_OSDWIN1MD_OACT1, OSD_OSDWIN1MD); | ||
425 | break; | ||
426 | case WIN_VID1: | ||
427 | osd_set(sd, OSD_VIDWINMD_ACT1, OSD_VIDWINMD); | ||
428 | break; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static int osd_enable_layer(struct osd_state *sd, enum osd_layer layer, | ||
433 | int otherwin) | ||
434 | { | ||
435 | struct osd_state *osd = sd; | ||
436 | struct osd_window_state *win = &osd->win[layer]; | ||
437 | struct osd_layer_config *cfg = &win->lconfig; | ||
438 | unsigned long flags; | ||
439 | |||
440 | spin_lock_irqsave(&osd->lock, flags); | ||
441 | |||
442 | /* | ||
443 | * use otherwin flag to know this is the other vid window | ||
444 | * in YUV420 mode, if is, skip this check | ||
445 | */ | ||
446 | if (!otherwin && (!win->is_allocated || | ||
447 | !win->fb_base_phys || | ||
448 | !cfg->line_length || | ||
449 | !cfg->xsize || | ||
450 | !cfg->ysize)) { | ||
451 | spin_unlock_irqrestore(&osd->lock, flags); | ||
452 | return -1; | ||
453 | } | ||
454 | |||
455 | if (win->is_enabled) { | ||
456 | spin_unlock_irqrestore(&osd->lock, flags); | ||
457 | return 0; | ||
458 | } | ||
459 | win->is_enabled = 1; | ||
460 | |||
461 | if (cfg->pixfmt != PIXFMT_OSD_ATTR) | ||
462 | _osd_enable_layer(sd, layer); | ||
463 | else { | ||
464 | _osd_enable_attribute_mode(sd); | ||
465 | _osd_set_blink_attribute(sd, osd->is_blinking, osd->blink); | ||
466 | } | ||
467 | |||
468 | spin_unlock_irqrestore(&osd->lock, flags); | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static void _osd_start_layer(struct osd_state *sd, enum osd_layer layer, | ||
474 | unsigned long fb_base_phys, | ||
475 | unsigned long cbcr_ofst) | ||
476 | { | ||
477 | switch (layer) { | ||
478 | case WIN_OSD0: | ||
479 | osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN0ADR); | ||
480 | break; | ||
481 | case WIN_VID0: | ||
482 | osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN0ADR); | ||
483 | break; | ||
484 | case WIN_OSD1: | ||
485 | osd_write(sd, fb_base_phys & ~0x1F, OSD_OSDWIN1ADR); | ||
486 | break; | ||
487 | case WIN_VID1: | ||
488 | osd_write(sd, fb_base_phys & ~0x1F, OSD_VIDWIN1ADR); | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | static void osd_start_layer(struct osd_state *sd, enum osd_layer layer, | ||
494 | unsigned long fb_base_phys, | ||
495 | unsigned long cbcr_ofst) | ||
496 | { | ||
497 | struct osd_state *osd = sd; | ||
498 | struct osd_window_state *win = &osd->win[layer]; | ||
499 | struct osd_layer_config *cfg = &win->lconfig; | ||
500 | unsigned long flags; | ||
501 | |||
502 | spin_lock_irqsave(&osd->lock, flags); | ||
503 | |||
504 | win->fb_base_phys = fb_base_phys & ~0x1F; | ||
505 | _osd_start_layer(sd, layer, fb_base_phys, cbcr_ofst); | ||
506 | |||
507 | if (layer == WIN_VID0) { | ||
508 | osd->pingpong = | ||
509 | _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, | ||
510 | win->fb_base_phys, | ||
511 | cfg); | ||
512 | } | ||
513 | |||
514 | spin_unlock_irqrestore(&osd->lock, flags); | ||
515 | } | ||
516 | |||
517 | static void osd_get_layer_config(struct osd_state *sd, enum osd_layer layer, | ||
518 | struct osd_layer_config *lconfig) | ||
519 | { | ||
520 | struct osd_state *osd = sd; | ||
521 | struct osd_window_state *win = &osd->win[layer]; | ||
522 | unsigned long flags; | ||
523 | |||
524 | spin_lock_irqsave(&osd->lock, flags); | ||
525 | |||
526 | *lconfig = win->lconfig; | ||
527 | |||
528 | spin_unlock_irqrestore(&osd->lock, flags); | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * try_layer_config() - Try a specific configuration for the layer | ||
533 | * @sd - ptr to struct osd_state | ||
534 | * @layer - layer to configure | ||
535 | * @lconfig - layer configuration to try | ||
536 | * | ||
537 | * If the requested lconfig is completely rejected and the value of lconfig on | ||
538 | * exit is the current lconfig, then try_layer_config() returns 1. Otherwise, | ||
539 | * try_layer_config() returns 0. A return value of 0 does not necessarily mean | ||
540 | * that the value of lconfig on exit is identical to the value of lconfig on | ||
541 | * entry, but merely that it represents a change from the current lconfig. | ||
542 | */ | ||
543 | static int try_layer_config(struct osd_state *sd, enum osd_layer layer, | ||
544 | struct osd_layer_config *lconfig) | ||
545 | { | ||
546 | struct osd_state *osd = sd; | ||
547 | struct osd_window_state *win = &osd->win[layer]; | ||
548 | int bad_config; | ||
549 | |||
550 | /* verify that the pixel format is compatible with the layer */ | ||
551 | switch (lconfig->pixfmt) { | ||
552 | case PIXFMT_1BPP: | ||
553 | case PIXFMT_2BPP: | ||
554 | case PIXFMT_4BPP: | ||
555 | case PIXFMT_8BPP: | ||
556 | case PIXFMT_RGB565: | ||
557 | bad_config = !is_osd_win(layer); | ||
558 | break; | ||
559 | case PIXFMT_YCbCrI: | ||
560 | case PIXFMT_YCrCbI: | ||
561 | bad_config = !is_vid_win(layer); | ||
562 | break; | ||
563 | case PIXFMT_RGB888: | ||
564 | bad_config = !is_vid_win(layer); | ||
565 | break; | ||
566 | case PIXFMT_NV12: | ||
567 | bad_config = 1; | ||
568 | break; | ||
569 | case PIXFMT_OSD_ATTR: | ||
570 | bad_config = (layer != WIN_OSD1); | ||
571 | break; | ||
572 | default: | ||
573 | bad_config = 1; | ||
574 | break; | ||
575 | } | ||
576 | if (bad_config) { | ||
577 | /* | ||
578 | * The requested pixel format is incompatible with the layer, | ||
579 | * so keep the current layer configuration. | ||
580 | */ | ||
581 | *lconfig = win->lconfig; | ||
582 | return bad_config; | ||
583 | } | ||
584 | |||
585 | /* DM6446: */ | ||
586 | /* only one OSD window at a time can use RGB pixel formats */ | ||
587 | if (is_osd_win(layer) && is_rgb_pixfmt(lconfig->pixfmt)) { | ||
588 | enum osd_pix_format pixfmt; | ||
589 | if (layer == WIN_OSD0) | ||
590 | pixfmt = osd->win[WIN_OSD1].lconfig.pixfmt; | ||
591 | else | ||
592 | pixfmt = osd->win[WIN_OSD0].lconfig.pixfmt; | ||
593 | |||
594 | if (is_rgb_pixfmt(pixfmt)) { | ||
595 | /* | ||
596 | * The other OSD window is already configured for an | ||
597 | * RGB, so keep the current layer configuration. | ||
598 | */ | ||
599 | *lconfig = win->lconfig; | ||
600 | return 1; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | /* DM6446: only one video window at a time can use RGB888 */ | ||
605 | if (is_vid_win(layer) && lconfig->pixfmt == PIXFMT_RGB888) { | ||
606 | enum osd_pix_format pixfmt; | ||
607 | |||
608 | if (layer == WIN_VID0) | ||
609 | pixfmt = osd->win[WIN_VID1].lconfig.pixfmt; | ||
610 | else | ||
611 | pixfmt = osd->win[WIN_VID0].lconfig.pixfmt; | ||
612 | |||
613 | if (pixfmt == PIXFMT_RGB888) { | ||
614 | /* | ||
615 | * The other video window is already configured for | ||
616 | * RGB888, so keep the current layer configuration. | ||
617 | */ | ||
618 | *lconfig = win->lconfig; | ||
619 | return 1; | ||
620 | } | ||
621 | } | ||
622 | |||
623 | /* window dimensions must be non-zero */ | ||
624 | if (!lconfig->line_length || !lconfig->xsize || !lconfig->ysize) { | ||
625 | *lconfig = win->lconfig; | ||
626 | return 1; | ||
627 | } | ||
628 | |||
629 | /* round line_length up to a multiple of 32 */ | ||
630 | lconfig->line_length = ((lconfig->line_length + 31) / 32) * 32; | ||
631 | lconfig->line_length = | ||
632 | min(lconfig->line_length, (unsigned)MAX_LINE_LENGTH); | ||
633 | lconfig->xsize = min(lconfig->xsize, (unsigned)MAX_WIN_SIZE); | ||
634 | lconfig->ysize = min(lconfig->ysize, (unsigned)MAX_WIN_SIZE); | ||
635 | lconfig->xpos = min(lconfig->xpos, (unsigned)MAX_WIN_SIZE); | ||
636 | lconfig->ypos = min(lconfig->ypos, (unsigned)MAX_WIN_SIZE); | ||
637 | lconfig->interlaced = (lconfig->interlaced != 0); | ||
638 | if (lconfig->interlaced) { | ||
639 | /* ysize and ypos must be even for interlaced displays */ | ||
640 | lconfig->ysize &= ~1; | ||
641 | lconfig->ypos &= ~1; | ||
642 | } | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static void _osd_disable_vid_rgb888(struct osd_state *sd) | ||
648 | { | ||
649 | /* | ||
650 | * The DM6446 supports RGB888 pixel format in a single video window. | ||
651 | * This routine disables RGB888 pixel format for both video windows. | ||
652 | * The caller must ensure that neither video window is currently | ||
653 | * configured for RGB888 pixel format. | ||
654 | */ | ||
655 | osd_clear(sd, OSD_MISCCTL_RGBEN, OSD_MISCCTL); | ||
656 | } | ||
657 | |||
658 | static void _osd_enable_vid_rgb888(struct osd_state *sd, | ||
659 | enum osd_layer layer) | ||
660 | { | ||
661 | /* | ||
662 | * The DM6446 supports RGB888 pixel format in a single video window. | ||
663 | * This routine enables RGB888 pixel format for the specified video | ||
664 | * window. The caller must ensure that the other video window is not | ||
665 | * currently configured for RGB888 pixel format, as this routine will | ||
666 | * disable RGB888 pixel format for the other window. | ||
667 | */ | ||
668 | if (layer == WIN_VID0) { | ||
669 | osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, | ||
670 | OSD_MISCCTL_RGBEN, OSD_MISCCTL); | ||
671 | } else if (layer == WIN_VID1) { | ||
672 | osd_modify(sd, OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, | ||
673 | OSD_MISCCTL_RGBEN | OSD_MISCCTL_RGBWIN, | ||
674 | OSD_MISCCTL); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | static void _osd_set_cbcr_order(struct osd_state *sd, | ||
679 | enum osd_pix_format pixfmt) | ||
680 | { | ||
681 | /* | ||
682 | * The caller must ensure that all windows using YC pixfmt use the same | ||
683 | * Cb/Cr order. | ||
684 | */ | ||
685 | if (pixfmt == PIXFMT_YCbCrI) | ||
686 | osd_clear(sd, OSD_MODE_CS, OSD_MODE); | ||
687 | else if (pixfmt == PIXFMT_YCrCbI) | ||
688 | osd_set(sd, OSD_MODE_CS, OSD_MODE); | ||
689 | } | ||
690 | |||
691 | static void _osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, | ||
692 | const struct osd_layer_config *lconfig) | ||
693 | { | ||
694 | u32 winmd = 0, winmd_mask = 0, bmw = 0; | ||
695 | |||
696 | _osd_set_cbcr_order(sd, lconfig->pixfmt); | ||
697 | |||
698 | switch (layer) { | ||
699 | case WIN_OSD0: | ||
700 | winmd_mask |= OSD_OSDWIN0MD_RGB0E; | ||
701 | if (lconfig->pixfmt == PIXFMT_RGB565) | ||
702 | winmd |= OSD_OSDWIN0MD_RGB0E; | ||
703 | |||
704 | winmd_mask |= OSD_OSDWIN0MD_BMW0 | OSD_OSDWIN0MD_OFF0; | ||
705 | |||
706 | switch (lconfig->pixfmt) { | ||
707 | case PIXFMT_1BPP: | ||
708 | bmw = 0; | ||
709 | break; | ||
710 | case PIXFMT_2BPP: | ||
711 | bmw = 1; | ||
712 | break; | ||
713 | case PIXFMT_4BPP: | ||
714 | bmw = 2; | ||
715 | break; | ||
716 | case PIXFMT_8BPP: | ||
717 | bmw = 3; | ||
718 | break; | ||
719 | default: | ||
720 | break; | ||
721 | } | ||
722 | winmd |= (bmw << OSD_OSDWIN0MD_BMW0_SHIFT); | ||
723 | |||
724 | if (lconfig->interlaced) | ||
725 | winmd |= OSD_OSDWIN0MD_OFF0; | ||
726 | |||
727 | osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN0MD); | ||
728 | osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN0OFST); | ||
729 | osd_write(sd, lconfig->xpos, OSD_OSDWIN0XP); | ||
730 | osd_write(sd, lconfig->xsize, OSD_OSDWIN0XL); | ||
731 | if (lconfig->interlaced) { | ||
732 | osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN0YP); | ||
733 | osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN0YL); | ||
734 | } else { | ||
735 | osd_write(sd, lconfig->ypos, OSD_OSDWIN0YP); | ||
736 | osd_write(sd, lconfig->ysize, OSD_OSDWIN0YL); | ||
737 | } | ||
738 | break; | ||
739 | case WIN_VID0: | ||
740 | winmd_mask |= OSD_VIDWINMD_VFF0; | ||
741 | if (lconfig->interlaced) | ||
742 | winmd |= OSD_VIDWINMD_VFF0; | ||
743 | |||
744 | osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); | ||
745 | osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN0OFST); | ||
746 | osd_write(sd, lconfig->xpos, OSD_VIDWIN0XP); | ||
747 | osd_write(sd, lconfig->xsize, OSD_VIDWIN0XL); | ||
748 | /* | ||
749 | * For YUV420P format the register contents are | ||
750 | * duplicated in both VID registers | ||
751 | */ | ||
752 | if (lconfig->interlaced) { | ||
753 | osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN0YP); | ||
754 | osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN0YL); | ||
755 | } else { | ||
756 | osd_write(sd, lconfig->ypos, OSD_VIDWIN0YP); | ||
757 | osd_write(sd, lconfig->ysize, OSD_VIDWIN0YL); | ||
758 | } | ||
759 | break; | ||
760 | case WIN_OSD1: | ||
761 | /* | ||
762 | * The caller must ensure that OSD1 is disabled prior to | ||
763 | * switching from a normal mode to attribute mode or from | ||
764 | * attribute mode to a normal mode. | ||
765 | */ | ||
766 | if (lconfig->pixfmt == PIXFMT_OSD_ATTR) { | ||
767 | winmd_mask |= | ||
768 | OSD_OSDWIN1MD_ATN1E | OSD_OSDWIN1MD_RGB1E | | ||
769 | OSD_OSDWIN1MD_CLUTS1 | | ||
770 | OSD_OSDWIN1MD_BLND1 | OSD_OSDWIN1MD_TE1; | ||
771 | } else { | ||
772 | winmd_mask |= OSD_OSDWIN1MD_RGB1E; | ||
773 | if (lconfig->pixfmt == PIXFMT_RGB565) | ||
774 | winmd |= OSD_OSDWIN1MD_RGB1E; | ||
775 | |||
776 | winmd_mask |= OSD_OSDWIN1MD_BMW1; | ||
777 | switch (lconfig->pixfmt) { | ||
778 | case PIXFMT_1BPP: | ||
779 | bmw = 0; | ||
780 | break; | ||
781 | case PIXFMT_2BPP: | ||
782 | bmw = 1; | ||
783 | break; | ||
784 | case PIXFMT_4BPP: | ||
785 | bmw = 2; | ||
786 | break; | ||
787 | case PIXFMT_8BPP: | ||
788 | bmw = 3; | ||
789 | break; | ||
790 | default: | ||
791 | break; | ||
792 | } | ||
793 | winmd |= (bmw << OSD_OSDWIN1MD_BMW1_SHIFT); | ||
794 | } | ||
795 | |||
796 | winmd_mask |= OSD_OSDWIN1MD_OFF1; | ||
797 | if (lconfig->interlaced) | ||
798 | winmd |= OSD_OSDWIN1MD_OFF1; | ||
799 | |||
800 | osd_modify(sd, winmd_mask, winmd, OSD_OSDWIN1MD); | ||
801 | osd_write(sd, lconfig->line_length >> 5, OSD_OSDWIN1OFST); | ||
802 | osd_write(sd, lconfig->xpos, OSD_OSDWIN1XP); | ||
803 | osd_write(sd, lconfig->xsize, OSD_OSDWIN1XL); | ||
804 | if (lconfig->interlaced) { | ||
805 | osd_write(sd, lconfig->ypos >> 1, OSD_OSDWIN1YP); | ||
806 | osd_write(sd, lconfig->ysize >> 1, OSD_OSDWIN1YL); | ||
807 | } else { | ||
808 | osd_write(sd, lconfig->ypos, OSD_OSDWIN1YP); | ||
809 | osd_write(sd, lconfig->ysize, OSD_OSDWIN1YL); | ||
810 | } | ||
811 | break; | ||
812 | case WIN_VID1: | ||
813 | winmd_mask |= OSD_VIDWINMD_VFF1; | ||
814 | if (lconfig->interlaced) | ||
815 | winmd |= OSD_VIDWINMD_VFF1; | ||
816 | |||
817 | osd_modify(sd, winmd_mask, winmd, OSD_VIDWINMD); | ||
818 | osd_write(sd, lconfig->line_length >> 5, OSD_VIDWIN1OFST); | ||
819 | osd_write(sd, lconfig->xpos, OSD_VIDWIN1XP); | ||
820 | osd_write(sd, lconfig->xsize, OSD_VIDWIN1XL); | ||
821 | /* | ||
822 | * For YUV420P format the register contents are | ||
823 | * duplicated in both VID registers | ||
824 | */ | ||
825 | osd_modify(sd, OSD_MISCCTL_S420D, ~OSD_MISCCTL_S420D, | ||
826 | OSD_MISCCTL); | ||
827 | |||
828 | if (lconfig->interlaced) { | ||
829 | osd_write(sd, lconfig->ypos >> 1, OSD_VIDWIN1YP); | ||
830 | osd_write(sd, lconfig->ysize >> 1, OSD_VIDWIN1YL); | ||
831 | } else { | ||
832 | osd_write(sd, lconfig->ypos, OSD_VIDWIN1YP); | ||
833 | osd_write(sd, lconfig->ysize, OSD_VIDWIN1YL); | ||
834 | } | ||
835 | break; | ||
836 | } | ||
837 | } | ||
838 | |||
839 | static int osd_set_layer_config(struct osd_state *sd, enum osd_layer layer, | ||
840 | struct osd_layer_config *lconfig) | ||
841 | { | ||
842 | struct osd_state *osd = sd; | ||
843 | struct osd_window_state *win = &osd->win[layer]; | ||
844 | struct osd_layer_config *cfg = &win->lconfig; | ||
845 | unsigned long flags; | ||
846 | int reject_config; | ||
847 | |||
848 | spin_lock_irqsave(&osd->lock, flags); | ||
849 | |||
850 | reject_config = try_layer_config(sd, layer, lconfig); | ||
851 | if (reject_config) { | ||
852 | spin_unlock_irqrestore(&osd->lock, flags); | ||
853 | return reject_config; | ||
854 | } | ||
855 | |||
856 | /* update the current Cb/Cr order */ | ||
857 | if (is_yc_pixfmt(lconfig->pixfmt)) | ||
858 | osd->yc_pixfmt = lconfig->pixfmt; | ||
859 | |||
860 | /* | ||
861 | * If we are switching OSD1 from normal mode to attribute mode or from | ||
862 | * attribute mode to normal mode, then we must disable the window. | ||
863 | */ | ||
864 | if (layer == WIN_OSD1) { | ||
865 | if (((lconfig->pixfmt == PIXFMT_OSD_ATTR) && | ||
866 | (cfg->pixfmt != PIXFMT_OSD_ATTR)) || | ||
867 | ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && | ||
868 | (cfg->pixfmt == PIXFMT_OSD_ATTR))) { | ||
869 | win->is_enabled = 0; | ||
870 | _osd_disable_layer(sd, layer); | ||
871 | } | ||
872 | } | ||
873 | |||
874 | _osd_set_layer_config(sd, layer, lconfig); | ||
875 | |||
876 | if (layer == WIN_OSD1) { | ||
877 | struct osd_osdwin_state *osdwin_state = | ||
878 | &osd->osdwin[OSDWIN_OSD1]; | ||
879 | |||
880 | if ((lconfig->pixfmt != PIXFMT_OSD_ATTR) && | ||
881 | (cfg->pixfmt == PIXFMT_OSD_ATTR)) { | ||
882 | /* | ||
883 | * We just switched OSD1 from attribute mode to normal | ||
884 | * mode, so we must initialize the CLUT select, the | ||
885 | * blend factor, transparency colorkey enable, and | ||
886 | * attenuation enable (DM6446 only) bits in the | ||
887 | * OSDWIN1MD register. | ||
888 | */ | ||
889 | _osd_set_osd_clut(sd, OSDWIN_OSD1, | ||
890 | osdwin_state->clut); | ||
891 | _osd_set_blending_factor(sd, OSDWIN_OSD1, | ||
892 | osdwin_state->blend); | ||
893 | if (osdwin_state->colorkey_blending) { | ||
894 | _osd_enable_color_key(sd, OSDWIN_OSD1, | ||
895 | osdwin_state-> | ||
896 | colorkey, | ||
897 | lconfig->pixfmt); | ||
898 | } else | ||
899 | _osd_disable_color_key(sd, OSDWIN_OSD1); | ||
900 | _osd_set_rec601_attenuation(sd, OSDWIN_OSD1, | ||
901 | osdwin_state-> | ||
902 | rec601_attenuation); | ||
903 | } else if ((lconfig->pixfmt == PIXFMT_OSD_ATTR) && | ||
904 | (cfg->pixfmt != PIXFMT_OSD_ATTR)) { | ||
905 | /* | ||
906 | * We just switched OSD1 from normal mode to attribute | ||
907 | * mode, so we must initialize the blink enable and | ||
908 | * blink interval bits in the OSDATRMD register. | ||
909 | */ | ||
910 | _osd_set_blink_attribute(sd, osd->is_blinking, | ||
911 | osd->blink); | ||
912 | } | ||
913 | } | ||
914 | |||
915 | /* | ||
916 | * If we just switched to a 1-, 2-, or 4-bits-per-pixel bitmap format | ||
917 | * then configure a default palette map. | ||
918 | */ | ||
919 | if ((lconfig->pixfmt != cfg->pixfmt) && | ||
920 | ((lconfig->pixfmt == PIXFMT_1BPP) || | ||
921 | (lconfig->pixfmt == PIXFMT_2BPP) || | ||
922 | (lconfig->pixfmt == PIXFMT_4BPP))) { | ||
923 | enum osd_win_layer osdwin = | ||
924 | ((layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1); | ||
925 | struct osd_osdwin_state *osdwin_state = | ||
926 | &osd->osdwin[osdwin]; | ||
927 | unsigned char clut_index; | ||
928 | unsigned char clut_entries = 0; | ||
929 | |||
930 | switch (lconfig->pixfmt) { | ||
931 | case PIXFMT_1BPP: | ||
932 | clut_entries = 2; | ||
933 | break; | ||
934 | case PIXFMT_2BPP: | ||
935 | clut_entries = 4; | ||
936 | break; | ||
937 | case PIXFMT_4BPP: | ||
938 | clut_entries = 16; | ||
939 | break; | ||
940 | default: | ||
941 | break; | ||
942 | } | ||
943 | /* | ||
944 | * The default palette map maps the pixel value to the clut | ||
945 | * index, i.e. pixel value 0 maps to clut entry 0, pixel value | ||
946 | * 1 maps to clut entry 1, etc. | ||
947 | */ | ||
948 | for (clut_index = 0; clut_index < 16; clut_index++) { | ||
949 | osdwin_state->palette_map[clut_index] = clut_index; | ||
950 | if (clut_index < clut_entries) { | ||
951 | _osd_set_palette_map(sd, osdwin, clut_index, | ||
952 | clut_index, | ||
953 | lconfig->pixfmt); | ||
954 | } | ||
955 | } | ||
956 | } | ||
957 | |||
958 | *cfg = *lconfig; | ||
959 | /* DM6446: configure the RGB888 enable and window selection */ | ||
960 | if (osd->win[WIN_VID0].lconfig.pixfmt == PIXFMT_RGB888) | ||
961 | _osd_enable_vid_rgb888(sd, WIN_VID0); | ||
962 | else if (osd->win[WIN_VID1].lconfig.pixfmt == PIXFMT_RGB888) | ||
963 | _osd_enable_vid_rgb888(sd, WIN_VID1); | ||
964 | else | ||
965 | _osd_disable_vid_rgb888(sd); | ||
966 | |||
967 | if (layer == WIN_VID0) { | ||
968 | osd->pingpong = | ||
969 | _osd_dm6446_vid0_pingpong(sd, osd->field_inversion, | ||
970 | win->fb_base_phys, | ||
971 | cfg); | ||
972 | } | ||
973 | |||
974 | spin_unlock_irqrestore(&osd->lock, flags); | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static void osd_init_layer(struct osd_state *sd, enum osd_layer layer) | ||
980 | { | ||
981 | struct osd_state *osd = sd; | ||
982 | struct osd_window_state *win = &osd->win[layer]; | ||
983 | enum osd_win_layer osdwin; | ||
984 | struct osd_osdwin_state *osdwin_state; | ||
985 | struct osd_layer_config *cfg = &win->lconfig; | ||
986 | unsigned long flags; | ||
987 | |||
988 | spin_lock_irqsave(&osd->lock, flags); | ||
989 | |||
990 | win->is_enabled = 0; | ||
991 | _osd_disable_layer(sd, layer); | ||
992 | |||
993 | win->h_zoom = ZOOM_X1; | ||
994 | win->v_zoom = ZOOM_X1; | ||
995 | _osd_set_zoom(sd, layer, win->h_zoom, win->v_zoom); | ||
996 | |||
997 | win->fb_base_phys = 0; | ||
998 | _osd_start_layer(sd, layer, win->fb_base_phys, 0); | ||
999 | |||
1000 | cfg->line_length = 0; | ||
1001 | cfg->xsize = 0; | ||
1002 | cfg->ysize = 0; | ||
1003 | cfg->xpos = 0; | ||
1004 | cfg->ypos = 0; | ||
1005 | cfg->interlaced = 0; | ||
1006 | switch (layer) { | ||
1007 | case WIN_OSD0: | ||
1008 | case WIN_OSD1: | ||
1009 | osdwin = (layer == WIN_OSD0) ? OSDWIN_OSD0 : OSDWIN_OSD1; | ||
1010 | osdwin_state = &osd->osdwin[osdwin]; | ||
1011 | /* | ||
1012 | * Other code relies on the fact that OSD windows default to a | ||
1013 | * bitmap pixel format when they are deallocated, so don't | ||
1014 | * change this default pixel format. | ||
1015 | */ | ||
1016 | cfg->pixfmt = PIXFMT_8BPP; | ||
1017 | _osd_set_layer_config(sd, layer, cfg); | ||
1018 | osdwin_state->clut = RAM_CLUT; | ||
1019 | _osd_set_osd_clut(sd, osdwin, osdwin_state->clut); | ||
1020 | osdwin_state->colorkey_blending = 0; | ||
1021 | _osd_disable_color_key(sd, osdwin); | ||
1022 | osdwin_state->blend = OSD_8_VID_0; | ||
1023 | _osd_set_blending_factor(sd, osdwin, osdwin_state->blend); | ||
1024 | osdwin_state->rec601_attenuation = 0; | ||
1025 | _osd_set_rec601_attenuation(sd, osdwin, | ||
1026 | osdwin_state-> | ||
1027 | rec601_attenuation); | ||
1028 | if (osdwin == OSDWIN_OSD1) { | ||
1029 | osd->is_blinking = 0; | ||
1030 | osd->blink = BLINK_X1; | ||
1031 | } | ||
1032 | break; | ||
1033 | case WIN_VID0: | ||
1034 | case WIN_VID1: | ||
1035 | cfg->pixfmt = osd->yc_pixfmt; | ||
1036 | _osd_set_layer_config(sd, layer, cfg); | ||
1037 | break; | ||
1038 | } | ||
1039 | |||
1040 | spin_unlock_irqrestore(&osd->lock, flags); | ||
1041 | } | ||
1042 | |||
1043 | static void osd_release_layer(struct osd_state *sd, enum osd_layer layer) | ||
1044 | { | ||
1045 | struct osd_state *osd = sd; | ||
1046 | struct osd_window_state *win = &osd->win[layer]; | ||
1047 | unsigned long flags; | ||
1048 | |||
1049 | spin_lock_irqsave(&osd->lock, flags); | ||
1050 | |||
1051 | if (!win->is_allocated) { | ||
1052 | spin_unlock_irqrestore(&osd->lock, flags); | ||
1053 | return; | ||
1054 | } | ||
1055 | |||
1056 | spin_unlock_irqrestore(&osd->lock, flags); | ||
1057 | osd_init_layer(sd, layer); | ||
1058 | spin_lock_irqsave(&osd->lock, flags); | ||
1059 | |||
1060 | win->is_allocated = 0; | ||
1061 | |||
1062 | spin_unlock_irqrestore(&osd->lock, flags); | ||
1063 | } | ||
1064 | |||
1065 | static int osd_request_layer(struct osd_state *sd, enum osd_layer layer) | ||
1066 | { | ||
1067 | struct osd_state *osd = sd; | ||
1068 | struct osd_window_state *win = &osd->win[layer]; | ||
1069 | unsigned long flags; | ||
1070 | |||
1071 | spin_lock_irqsave(&osd->lock, flags); | ||
1072 | |||
1073 | if (win->is_allocated) { | ||
1074 | spin_unlock_irqrestore(&osd->lock, flags); | ||
1075 | return -1; | ||
1076 | } | ||
1077 | win->is_allocated = 1; | ||
1078 | |||
1079 | spin_unlock_irqrestore(&osd->lock, flags); | ||
1080 | |||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static void _osd_init(struct osd_state *sd) | ||
1085 | { | ||
1086 | osd_write(sd, 0, OSD_MODE); | ||
1087 | osd_write(sd, 0, OSD_VIDWINMD); | ||
1088 | osd_write(sd, 0, OSD_OSDWIN0MD); | ||
1089 | osd_write(sd, 0, OSD_OSDWIN1MD); | ||
1090 | osd_write(sd, 0, OSD_RECTCUR); | ||
1091 | osd_write(sd, 0, OSD_MISCCTL); | ||
1092 | } | ||
1093 | |||
1094 | static void osd_set_left_margin(struct osd_state *sd, u32 val) | ||
1095 | { | ||
1096 | osd_write(sd, val, OSD_BASEPX); | ||
1097 | } | ||
1098 | |||
1099 | static void osd_set_top_margin(struct osd_state *sd, u32 val) | ||
1100 | { | ||
1101 | osd_write(sd, val, OSD_BASEPY); | ||
1102 | } | ||
1103 | |||
1104 | static int osd_initialize(struct osd_state *osd) | ||
1105 | { | ||
1106 | if (osd == NULL) | ||
1107 | return -ENODEV; | ||
1108 | _osd_init(osd); | ||
1109 | |||
1110 | /* set default Cb/Cr order */ | ||
1111 | osd->yc_pixfmt = PIXFMT_YCbCrI; | ||
1112 | |||
1113 | _osd_set_field_inversion(osd, osd->field_inversion); | ||
1114 | _osd_set_rom_clut(osd, osd->rom_clut); | ||
1115 | |||
1116 | osd_init_layer(osd, WIN_OSD0); | ||
1117 | osd_init_layer(osd, WIN_VID0); | ||
1118 | osd_init_layer(osd, WIN_OSD1); | ||
1119 | osd_init_layer(osd, WIN_VID1); | ||
1120 | |||
1121 | return 0; | ||
1122 | } | ||
1123 | |||
1124 | static const struct vpbe_osd_ops osd_ops = { | ||
1125 | .initialize = osd_initialize, | ||
1126 | .request_layer = osd_request_layer, | ||
1127 | .release_layer = osd_release_layer, | ||
1128 | .enable_layer = osd_enable_layer, | ||
1129 | .disable_layer = osd_disable_layer, | ||
1130 | .set_layer_config = osd_set_layer_config, | ||
1131 | .get_layer_config = osd_get_layer_config, | ||
1132 | .start_layer = osd_start_layer, | ||
1133 | .set_left_margin = osd_set_left_margin, | ||
1134 | .set_top_margin = osd_set_top_margin, | ||
1135 | }; | ||
1136 | |||
1137 | static int osd_probe(struct platform_device *pdev) | ||
1138 | { | ||
1139 | struct osd_platform_data *pdata; | ||
1140 | struct osd_state *osd; | ||
1141 | struct resource *res; | ||
1142 | int ret = 0; | ||
1143 | |||
1144 | osd = kzalloc(sizeof(struct osd_state), GFP_KERNEL); | ||
1145 | if (osd == NULL) | ||
1146 | return -ENOMEM; | ||
1147 | |||
1148 | osd->dev = &pdev->dev; | ||
1149 | pdata = (struct osd_platform_data *)pdev->dev.platform_data; | ||
1150 | osd->vpbe_type = (enum vpbe_version)pdata->vpbe_type; | ||
1151 | if (NULL == pdev->dev.platform_data) { | ||
1152 | dev_err(osd->dev, "No platform data defined for OSD" | ||
1153 | " sub device\n"); | ||
1154 | ret = -ENOENT; | ||
1155 | goto free_mem; | ||
1156 | } | ||
1157 | |||
1158 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1159 | if (!res) { | ||
1160 | dev_err(osd->dev, "Unable to get OSD register address map\n"); | ||
1161 | ret = -ENODEV; | ||
1162 | goto free_mem; | ||
1163 | } | ||
1164 | osd->osd_base_phys = res->start; | ||
1165 | osd->osd_size = res->end - res->start + 1; | ||
1166 | if (!request_mem_region(osd->osd_base_phys, osd->osd_size, | ||
1167 | MODULE_NAME)) { | ||
1168 | dev_err(osd->dev, "Unable to reserve OSD MMIO region\n"); | ||
1169 | ret = -ENODEV; | ||
1170 | goto free_mem; | ||
1171 | } | ||
1172 | osd->osd_base = (unsigned long)ioremap_nocache(res->start, | ||
1173 | osd->osd_size); | ||
1174 | if (!osd->osd_base) { | ||
1175 | dev_err(osd->dev, "Unable to map the OSD region\n"); | ||
1176 | ret = -ENODEV; | ||
1177 | goto release_mem_region; | ||
1178 | } | ||
1179 | spin_lock_init(&osd->lock); | ||
1180 | osd->ops = osd_ops; | ||
1181 | platform_set_drvdata(pdev, osd); | ||
1182 | dev_notice(osd->dev, "OSD sub device probe success\n"); | ||
1183 | return ret; | ||
1184 | |||
1185 | release_mem_region: | ||
1186 | release_mem_region(osd->osd_base_phys, osd->osd_size); | ||
1187 | free_mem: | ||
1188 | kfree(osd); | ||
1189 | return ret; | ||
1190 | } | ||
1191 | |||
1192 | static int osd_remove(struct platform_device *pdev) | ||
1193 | { | ||
1194 | struct osd_state *osd = platform_get_drvdata(pdev); | ||
1195 | |||
1196 | iounmap((void *)osd->osd_base); | ||
1197 | release_mem_region(osd->osd_base_phys, osd->osd_size); | ||
1198 | kfree(osd); | ||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static struct platform_driver osd_driver = { | ||
1203 | .probe = osd_probe, | ||
1204 | .remove = osd_remove, | ||
1205 | .driver = { | ||
1206 | .name = MODULE_NAME, | ||
1207 | .owner = THIS_MODULE, | ||
1208 | }, | ||
1209 | }; | ||
1210 | |||
1211 | static int osd_init(void) | ||
1212 | { | ||
1213 | if (platform_driver_register(&osd_driver)) { | ||
1214 | printk(KERN_ERR "Unable to register davinci osd driver\n"); | ||
1215 | return -ENODEV; | ||
1216 | } | ||
1217 | |||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | static void osd_exit(void) | ||
1222 | { | ||
1223 | platform_driver_unregister(&osd_driver); | ||
1224 | } | ||
1225 | |||
1226 | module_init(osd_init); | ||
1227 | module_exit(osd_exit); | ||
1228 | |||
1229 | MODULE_LICENSE("GPL"); | ||
1230 | MODULE_DESCRIPTION("DaVinci OSD Manager Driver"); | ||
1231 | MODULE_AUTHOR("Texas Instruments"); | ||
diff --git a/drivers/media/video/davinci/vpbe_osd_regs.h b/drivers/media/video/davinci/vpbe_osd_regs.h new file mode 100644 index 00000000000..584520f3af6 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_osd_regs.h | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | */ | ||
17 | #ifndef _VPBE_OSD_REGS_H | ||
18 | #define _VPBE_OSD_REGS_H | ||
19 | |||
20 | /* VPBE Global Registers */ | ||
21 | #define VPBE_PID 0x0 | ||
22 | #define VPBE_PCR 0x4 | ||
23 | |||
24 | /* VPSS CLock Registers */ | ||
25 | #define VPSSCLK_PID 0x00 | ||
26 | #define VPSSCLK_CLKCTRL 0x04 | ||
27 | |||
28 | /* VPSS Buffer Logic Registers */ | ||
29 | #define VPSSBL_PID 0x00 | ||
30 | #define VPSSBL_PCR 0x04 | ||
31 | #define VPSSBL_BCR 0x08 | ||
32 | #define VPSSBL_INTSTAT 0x0C | ||
33 | #define VPSSBL_INTSEL 0x10 | ||
34 | #define VPSSBL_EVTSEL 0x14 | ||
35 | #define VPSSBL_MEMCTRL 0x18 | ||
36 | #define VPSSBL_CCDCMUX 0x1C | ||
37 | |||
38 | /* DM365 ISP5 system configuration */ | ||
39 | #define ISP5_PID 0x0 | ||
40 | #define ISP5_PCCR 0x4 | ||
41 | #define ISP5_BCR 0x8 | ||
42 | #define ISP5_INTSTAT 0xC | ||
43 | #define ISP5_INTSEL1 0x10 | ||
44 | #define ISP5_INTSEL2 0x14 | ||
45 | #define ISP5_INTSEL3 0x18 | ||
46 | #define ISP5_EVTSEL 0x1c | ||
47 | #define ISP5_CCDCMUX 0x20 | ||
48 | |||
49 | /* VPBE On-Screen Display Subsystem Registers (OSD) */ | ||
50 | #define OSD_MODE 0x00 | ||
51 | #define OSD_VIDWINMD 0x04 | ||
52 | #define OSD_OSDWIN0MD 0x08 | ||
53 | #define OSD_OSDWIN1MD 0x0C | ||
54 | #define OSD_OSDATRMD 0x0C | ||
55 | #define OSD_RECTCUR 0x10 | ||
56 | #define OSD_VIDWIN0OFST 0x18 | ||
57 | #define OSD_VIDWIN1OFST 0x1C | ||
58 | #define OSD_OSDWIN0OFST 0x20 | ||
59 | #define OSD_OSDWIN1OFST 0x24 | ||
60 | #define OSD_VIDWINADH 0x28 | ||
61 | #define OSD_VIDWIN0ADL 0x2C | ||
62 | #define OSD_VIDWIN0ADR 0x2C | ||
63 | #define OSD_VIDWIN1ADL 0x30 | ||
64 | #define OSD_VIDWIN1ADR 0x30 | ||
65 | #define OSD_OSDWINADH 0x34 | ||
66 | #define OSD_OSDWIN0ADL 0x38 | ||
67 | #define OSD_OSDWIN0ADR 0x38 | ||
68 | #define OSD_OSDWIN1ADL 0x3C | ||
69 | #define OSD_OSDWIN1ADR 0x3C | ||
70 | #define OSD_BASEPX 0x40 | ||
71 | #define OSD_BASEPY 0x44 | ||
72 | #define OSD_VIDWIN0XP 0x48 | ||
73 | #define OSD_VIDWIN0YP 0x4C | ||
74 | #define OSD_VIDWIN0XL 0x50 | ||
75 | #define OSD_VIDWIN0YL 0x54 | ||
76 | #define OSD_VIDWIN1XP 0x58 | ||
77 | #define OSD_VIDWIN1YP 0x5C | ||
78 | #define OSD_VIDWIN1XL 0x60 | ||
79 | #define OSD_VIDWIN1YL 0x64 | ||
80 | #define OSD_OSDWIN0XP 0x68 | ||
81 | #define OSD_OSDWIN0YP 0x6C | ||
82 | #define OSD_OSDWIN0XL 0x70 | ||
83 | #define OSD_OSDWIN0YL 0x74 | ||
84 | #define OSD_OSDWIN1XP 0x78 | ||
85 | #define OSD_OSDWIN1YP 0x7C | ||
86 | #define OSD_OSDWIN1XL 0x80 | ||
87 | #define OSD_OSDWIN1YL 0x84 | ||
88 | #define OSD_CURXP 0x88 | ||
89 | #define OSD_CURYP 0x8C | ||
90 | #define OSD_CURXL 0x90 | ||
91 | #define OSD_CURYL 0x94 | ||
92 | #define OSD_W0BMP01 0xA0 | ||
93 | #define OSD_W0BMP23 0xA4 | ||
94 | #define OSD_W0BMP45 0xA8 | ||
95 | #define OSD_W0BMP67 0xAC | ||
96 | #define OSD_W0BMP89 0xB0 | ||
97 | #define OSD_W0BMPAB 0xB4 | ||
98 | #define OSD_W0BMPCD 0xB8 | ||
99 | #define OSD_W0BMPEF 0xBC | ||
100 | #define OSD_W1BMP01 0xC0 | ||
101 | #define OSD_W1BMP23 0xC4 | ||
102 | #define OSD_W1BMP45 0xC8 | ||
103 | #define OSD_W1BMP67 0xCC | ||
104 | #define OSD_W1BMP89 0xD0 | ||
105 | #define OSD_W1BMPAB 0xD4 | ||
106 | #define OSD_W1BMPCD 0xD8 | ||
107 | #define OSD_W1BMPEF 0xDC | ||
108 | #define OSD_VBNDRY 0xE0 | ||
109 | #define OSD_EXTMODE 0xE4 | ||
110 | #define OSD_MISCCTL 0xE8 | ||
111 | #define OSD_CLUTRAMYCB 0xEC | ||
112 | #define OSD_CLUTRAMCR 0xF0 | ||
113 | #define OSD_TRANSPVAL 0xF4 | ||
114 | #define OSD_TRANSPVALL 0xF4 | ||
115 | #define OSD_TRANSPVALU 0xF8 | ||
116 | #define OSD_TRANSPBMPIDX 0xFC | ||
117 | #define OSD_PPVWIN0ADR 0xFC | ||
118 | |||
119 | /* bit definitions */ | ||
120 | #define VPBE_PCR_VENC_DIV (1 << 1) | ||
121 | #define VPBE_PCR_CLK_OFF (1 << 0) | ||
122 | |||
123 | #define VPSSBL_INTSTAT_HSSIINT (1 << 14) | ||
124 | #define VPSSBL_INTSTAT_CFALDINT (1 << 13) | ||
125 | #define VPSSBL_INTSTAT_IPIPE_INT5 (1 << 12) | ||
126 | #define VPSSBL_INTSTAT_IPIPE_INT4 (1 << 11) | ||
127 | #define VPSSBL_INTSTAT_IPIPE_INT3 (1 << 10) | ||
128 | #define VPSSBL_INTSTAT_IPIPE_INT2 (1 << 9) | ||
129 | #define VPSSBL_INTSTAT_IPIPE_INT1 (1 << 8) | ||
130 | #define VPSSBL_INTSTAT_IPIPE_INT0 (1 << 7) | ||
131 | #define VPSSBL_INTSTAT_IPIPEIFINT (1 << 6) | ||
132 | #define VPSSBL_INTSTAT_OSDINT (1 << 5) | ||
133 | #define VPSSBL_INTSTAT_VENCINT (1 << 4) | ||
134 | #define VPSSBL_INTSTAT_H3AINT (1 << 3) | ||
135 | #define VPSSBL_INTSTAT_CCDC_VDINT2 (1 << 2) | ||
136 | #define VPSSBL_INTSTAT_CCDC_VDINT1 (1 << 1) | ||
137 | #define VPSSBL_INTSTAT_CCDC_VDINT0 (1 << 0) | ||
138 | |||
139 | /* DM365 ISP5 bit definitions */ | ||
140 | #define ISP5_INTSTAT_VENCINT (1 << 21) | ||
141 | #define ISP5_INTSTAT_OSDINT (1 << 20) | ||
142 | |||
143 | /* VMOD TVTYP options for HDMD=0 */ | ||
144 | #define SDTV_NTSC 0 | ||
145 | #define SDTV_PAL 1 | ||
146 | /* VMOD TVTYP options for HDMD=1 */ | ||
147 | #define HDTV_525P 0 | ||
148 | #define HDTV_625P 1 | ||
149 | #define HDTV_1080I 2 | ||
150 | #define HDTV_720P 3 | ||
151 | |||
152 | #define OSD_MODE_CS (1 << 15) | ||
153 | #define OSD_MODE_OVRSZ (1 << 14) | ||
154 | #define OSD_MODE_OHRSZ (1 << 13) | ||
155 | #define OSD_MODE_EF (1 << 12) | ||
156 | #define OSD_MODE_VVRSZ (1 << 11) | ||
157 | #define OSD_MODE_VHRSZ (1 << 10) | ||
158 | #define OSD_MODE_FSINV (1 << 9) | ||
159 | #define OSD_MODE_BCLUT (1 << 8) | ||
160 | #define OSD_MODE_CABG_SHIFT 0 | ||
161 | #define OSD_MODE_CABG (0xff << 0) | ||
162 | |||
163 | #define OSD_VIDWINMD_VFINV (1 << 15) | ||
164 | #define OSD_VIDWINMD_V1EFC (1 << 14) | ||
165 | #define OSD_VIDWINMD_VHZ1_SHIFT 12 | ||
166 | #define OSD_VIDWINMD_VHZ1 (3 << 12) | ||
167 | #define OSD_VIDWINMD_VVZ1_SHIFT 10 | ||
168 | #define OSD_VIDWINMD_VVZ1 (3 << 10) | ||
169 | #define OSD_VIDWINMD_VFF1 (1 << 9) | ||
170 | #define OSD_VIDWINMD_ACT1 (1 << 8) | ||
171 | #define OSD_VIDWINMD_V0EFC (1 << 6) | ||
172 | #define OSD_VIDWINMD_VHZ0_SHIFT 4 | ||
173 | #define OSD_VIDWINMD_VHZ0 (3 << 4) | ||
174 | #define OSD_VIDWINMD_VVZ0_SHIFT 2 | ||
175 | #define OSD_VIDWINMD_VVZ0 (3 << 2) | ||
176 | #define OSD_VIDWINMD_VFF0 (1 << 1) | ||
177 | #define OSD_VIDWINMD_ACT0 (1 << 0) | ||
178 | |||
179 | #define OSD_OSDWIN0MD_ATN0E (1 << 14) | ||
180 | #define OSD_OSDWIN0MD_RGB0E (1 << 13) | ||
181 | #define OSD_OSDWIN0MD_BMP0MD_SHIFT 13 | ||
182 | #define OSD_OSDWIN0MD_BMP0MD (3 << 13) | ||
183 | #define OSD_OSDWIN0MD_CLUTS0 (1 << 12) | ||
184 | #define OSD_OSDWIN0MD_OHZ0_SHIFT 10 | ||
185 | #define OSD_OSDWIN0MD_OHZ0 (3 << 10) | ||
186 | #define OSD_OSDWIN0MD_OVZ0_SHIFT 8 | ||
187 | #define OSD_OSDWIN0MD_OVZ0 (3 << 8) | ||
188 | #define OSD_OSDWIN0MD_BMW0_SHIFT 6 | ||
189 | #define OSD_OSDWIN0MD_BMW0 (3 << 6) | ||
190 | #define OSD_OSDWIN0MD_BLND0_SHIFT 3 | ||
191 | #define OSD_OSDWIN0MD_BLND0 (7 << 3) | ||
192 | #define OSD_OSDWIN0MD_TE0 (1 << 2) | ||
193 | #define OSD_OSDWIN0MD_OFF0 (1 << 1) | ||
194 | #define OSD_OSDWIN0MD_OACT0 (1 << 0) | ||
195 | |||
196 | #define OSD_OSDWIN1MD_OASW (1 << 15) | ||
197 | #define OSD_OSDWIN1MD_ATN1E (1 << 14) | ||
198 | #define OSD_OSDWIN1MD_RGB1E (1 << 13) | ||
199 | #define OSD_OSDWIN1MD_BMP1MD_SHIFT 13 | ||
200 | #define OSD_OSDWIN1MD_BMP1MD (3 << 13) | ||
201 | #define OSD_OSDWIN1MD_CLUTS1 (1 << 12) | ||
202 | #define OSD_OSDWIN1MD_OHZ1_SHIFT 10 | ||
203 | #define OSD_OSDWIN1MD_OHZ1 (3 << 10) | ||
204 | #define OSD_OSDWIN1MD_OVZ1_SHIFT 8 | ||
205 | #define OSD_OSDWIN1MD_OVZ1 (3 << 8) | ||
206 | #define OSD_OSDWIN1MD_BMW1_SHIFT 6 | ||
207 | #define OSD_OSDWIN1MD_BMW1 (3 << 6) | ||
208 | #define OSD_OSDWIN1MD_BLND1_SHIFT 3 | ||
209 | #define OSD_OSDWIN1MD_BLND1 (7 << 3) | ||
210 | #define OSD_OSDWIN1MD_TE1 (1 << 2) | ||
211 | #define OSD_OSDWIN1MD_OFF1 (1 << 1) | ||
212 | #define OSD_OSDWIN1MD_OACT1 (1 << 0) | ||
213 | |||
214 | #define OSD_OSDATRMD_OASW (1 << 15) | ||
215 | #define OSD_OSDATRMD_OHZA_SHIFT 10 | ||
216 | #define OSD_OSDATRMD_OHZA (3 << 10) | ||
217 | #define OSD_OSDATRMD_OVZA_SHIFT 8 | ||
218 | #define OSD_OSDATRMD_OVZA (3 << 8) | ||
219 | #define OSD_OSDATRMD_BLNKINT_SHIFT 6 | ||
220 | #define OSD_OSDATRMD_BLNKINT (3 << 6) | ||
221 | #define OSD_OSDATRMD_OFFA (1 << 1) | ||
222 | #define OSD_OSDATRMD_BLNK (1 << 0) | ||
223 | |||
224 | #define OSD_RECTCUR_RCAD_SHIFT 8 | ||
225 | #define OSD_RECTCUR_RCAD (0xff << 8) | ||
226 | #define OSD_RECTCUR_CLUTSR (1 << 7) | ||
227 | #define OSD_RECTCUR_RCHW_SHIFT 4 | ||
228 | #define OSD_RECTCUR_RCHW (7 << 4) | ||
229 | #define OSD_RECTCUR_RCVW_SHIFT 1 | ||
230 | #define OSD_RECTCUR_RCVW (7 << 1) | ||
231 | #define OSD_RECTCUR_RCACT (1 << 0) | ||
232 | |||
233 | #define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) | ||
234 | |||
235 | #define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) | ||
236 | |||
237 | #define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) | ||
238 | |||
239 | #define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) | ||
240 | |||
241 | #define OSD_WINOFST_AH_SHIFT 9 | ||
242 | |||
243 | #define OSD_VIDWIN0OFST_V0AH (0xf << 9) | ||
244 | #define OSD_VIDWIN1OFST_V1AH (0xf << 9) | ||
245 | #define OSD_OSDWIN0OFST_O0AH (0xf << 9) | ||
246 | #define OSD_OSDWIN1OFST_O1AH (0xf << 9) | ||
247 | |||
248 | #define OSD_VIDWINADH_V1AH_SHIFT 8 | ||
249 | #define OSD_VIDWINADH_V1AH (0x7f << 8) | ||
250 | #define OSD_VIDWINADH_V0AH_SHIFT 0 | ||
251 | #define OSD_VIDWINADH_V0AH (0x7f << 0) | ||
252 | |||
253 | #define OSD_VIDWIN0ADL_V0AL (0xffff << 0) | ||
254 | |||
255 | #define OSD_VIDWIN1ADL_V1AL (0xffff << 0) | ||
256 | |||
257 | #define OSD_OSDWINADH_O1AH_SHIFT 8 | ||
258 | #define OSD_OSDWINADH_O1AH (0x7f << 8) | ||
259 | #define OSD_OSDWINADH_O0AH_SHIFT 0 | ||
260 | #define OSD_OSDWINADH_O0AH (0x7f << 0) | ||
261 | |||
262 | #define OSD_OSDWIN0ADL_O0AL (0xffff << 0) | ||
263 | |||
264 | #define OSD_OSDWIN1ADL_O1AL (0xffff << 0) | ||
265 | |||
266 | #define OSD_BASEPX_BPX (0x3ff << 0) | ||
267 | |||
268 | #define OSD_BASEPY_BPY (0x1ff << 0) | ||
269 | |||
270 | #define OSD_VIDWIN0XP_V0X (0x7ff << 0) | ||
271 | |||
272 | #define OSD_VIDWIN0YP_V0Y (0x7ff << 0) | ||
273 | |||
274 | #define OSD_VIDWIN0XL_V0W (0x7ff << 0) | ||
275 | |||
276 | #define OSD_VIDWIN0YL_V0H (0x7ff << 0) | ||
277 | |||
278 | #define OSD_VIDWIN1XP_V1X (0x7ff << 0) | ||
279 | |||
280 | #define OSD_VIDWIN1YP_V1Y (0x7ff << 0) | ||
281 | |||
282 | #define OSD_VIDWIN1XL_V1W (0x7ff << 0) | ||
283 | |||
284 | #define OSD_VIDWIN1YL_V1H (0x7ff << 0) | ||
285 | |||
286 | #define OSD_OSDWIN0XP_W0X (0x7ff << 0) | ||
287 | |||
288 | #define OSD_OSDWIN0YP_W0Y (0x7ff << 0) | ||
289 | |||
290 | #define OSD_OSDWIN0XL_W0W (0x7ff << 0) | ||
291 | |||
292 | #define OSD_OSDWIN0YL_W0H (0x7ff << 0) | ||
293 | |||
294 | #define OSD_OSDWIN1XP_W1X (0x7ff << 0) | ||
295 | |||
296 | #define OSD_OSDWIN1YP_W1Y (0x7ff << 0) | ||
297 | |||
298 | #define OSD_OSDWIN1XL_W1W (0x7ff << 0) | ||
299 | |||
300 | #define OSD_OSDWIN1YL_W1H (0x7ff << 0) | ||
301 | |||
302 | #define OSD_CURXP_RCSX (0x7ff << 0) | ||
303 | |||
304 | #define OSD_CURYP_RCSY (0x7ff << 0) | ||
305 | |||
306 | #define OSD_CURXL_RCSW (0x7ff << 0) | ||
307 | |||
308 | #define OSD_CURYL_RCSH (0x7ff << 0) | ||
309 | |||
310 | #define OSD_EXTMODE_EXPMDSEL (1 << 15) | ||
311 | #define OSD_EXTMODE_SCRNHEXP_SHIFT 13 | ||
312 | #define OSD_EXTMODE_SCRNHEXP (3 << 13) | ||
313 | #define OSD_EXTMODE_SCRNVEXP (1 << 12) | ||
314 | #define OSD_EXTMODE_OSD1BLDCHR (1 << 11) | ||
315 | #define OSD_EXTMODE_OSD0BLDCHR (1 << 10) | ||
316 | #define OSD_EXTMODE_ATNOSD1EN (1 << 9) | ||
317 | #define OSD_EXTMODE_ATNOSD0EN (1 << 8) | ||
318 | #define OSD_EXTMODE_OSDHRSZ15 (1 << 7) | ||
319 | #define OSD_EXTMODE_VIDHRSZ15 (1 << 6) | ||
320 | #define OSD_EXTMODE_ZMFILV1HEN (1 << 5) | ||
321 | #define OSD_EXTMODE_ZMFILV1VEN (1 << 4) | ||
322 | #define OSD_EXTMODE_ZMFILV0HEN (1 << 3) | ||
323 | #define OSD_EXTMODE_ZMFILV0VEN (1 << 2) | ||
324 | #define OSD_EXTMODE_EXPFILHEN (1 << 1) | ||
325 | #define OSD_EXTMODE_EXPFILVEN (1 << 0) | ||
326 | |||
327 | #define OSD_MISCCTL_BLDSEL (1 << 15) | ||
328 | #define OSD_MISCCTL_S420D (1 << 14) | ||
329 | #define OSD_MISCCTL_BMAPT (1 << 13) | ||
330 | #define OSD_MISCCTL_DM365M (1 << 12) | ||
331 | #define OSD_MISCCTL_RGBEN (1 << 7) | ||
332 | #define OSD_MISCCTL_RGBWIN (1 << 6) | ||
333 | #define OSD_MISCCTL_DMANG (1 << 6) | ||
334 | #define OSD_MISCCTL_TMON (1 << 5) | ||
335 | #define OSD_MISCCTL_RSEL (1 << 4) | ||
336 | #define OSD_MISCCTL_CPBSY (1 << 3) | ||
337 | #define OSD_MISCCTL_PPSW (1 << 2) | ||
338 | #define OSD_MISCCTL_PPRV (1 << 1) | ||
339 | |||
340 | #define OSD_CLUTRAMYCB_Y_SHIFT 8 | ||
341 | #define OSD_CLUTRAMYCB_Y (0xff << 8) | ||
342 | #define OSD_CLUTRAMYCB_CB_SHIFT 0 | ||
343 | #define OSD_CLUTRAMYCB_CB (0xff << 0) | ||
344 | |||
345 | #define OSD_CLUTRAMCR_CR_SHIFT 8 | ||
346 | #define OSD_CLUTRAMCR_CR (0xff << 8) | ||
347 | #define OSD_CLUTRAMCR_CADDR_SHIFT 0 | ||
348 | #define OSD_CLUTRAMCR_CADDR (0xff << 0) | ||
349 | |||
350 | #define OSD_TRANSPVAL_RGBTRANS (0xffff << 0) | ||
351 | |||
352 | #define OSD_TRANSPVALL_RGBL (0xffff << 0) | ||
353 | |||
354 | #define OSD_TRANSPVALU_Y_SHIFT 8 | ||
355 | #define OSD_TRANSPVALU_Y (0xff << 8) | ||
356 | #define OSD_TRANSPVALU_RGBU_SHIFT 0 | ||
357 | #define OSD_TRANSPVALU_RGBU (0xff << 0) | ||
358 | |||
359 | #define OSD_TRANSPBMPIDX_BMP1_SHIFT 8 | ||
360 | #define OSD_TRANSPBMPIDX_BMP1 (0xff << 8) | ||
361 | #define OSD_TRANSPBMPIDX_BMP0_SHIFT 0 | ||
362 | #define OSD_TRANSPBMPIDX_BMP0 0xff | ||
363 | |||
364 | #endif /* _DAVINCI_VPBE_H_ */ | ||
diff --git a/drivers/media/video/davinci/vpbe_venc.c b/drivers/media/video/davinci/vpbe_venc.c new file mode 100644 index 00000000000..03a3e5c65ee --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc.c | |||
@@ -0,0 +1,566 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | */ | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/ctype.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include <mach/hardware.h> | ||
29 | #include <mach/mux.h> | ||
30 | #include <mach/io.h> | ||
31 | #include <mach/i2c.h> | ||
32 | |||
33 | #include <linux/io.h> | ||
34 | |||
35 | #include <media/davinci/vpbe_types.h> | ||
36 | #include <media/davinci/vpbe_venc.h> | ||
37 | #include <media/davinci/vpss.h> | ||
38 | #include <media/v4l2-device.h> | ||
39 | |||
40 | #include "vpbe_venc_regs.h" | ||
41 | |||
42 | #define MODULE_NAME VPBE_VENC_SUBDEV_NAME | ||
43 | |||
44 | static int debug = 2; | ||
45 | module_param(debug, int, 0644); | ||
46 | MODULE_PARM_DESC(debug, "Debug level 0-2"); | ||
47 | |||
48 | struct venc_state { | ||
49 | struct v4l2_subdev sd; | ||
50 | struct venc_callback *callback; | ||
51 | struct venc_platform_data *pdata; | ||
52 | struct device *pdev; | ||
53 | u32 output; | ||
54 | v4l2_std_id std; | ||
55 | spinlock_t lock; | ||
56 | void __iomem *venc_base; | ||
57 | void __iomem *vdaccfg_reg; | ||
58 | }; | ||
59 | |||
60 | static inline struct venc_state *to_state(struct v4l2_subdev *sd) | ||
61 | { | ||
62 | return container_of(sd, struct venc_state, sd); | ||
63 | } | ||
64 | |||
65 | static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) | ||
66 | { | ||
67 | struct venc_state *venc = to_state(sd); | ||
68 | |||
69 | return readl(venc->venc_base + offset); | ||
70 | } | ||
71 | |||
72 | static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) | ||
73 | { | ||
74 | struct venc_state *venc = to_state(sd); | ||
75 | |||
76 | writel(val, (venc->venc_base + offset)); | ||
77 | |||
78 | return val; | ||
79 | } | ||
80 | |||
81 | static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, | ||
82 | u32 val, u32 mask) | ||
83 | { | ||
84 | u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); | ||
85 | |||
86 | venc_write(sd, offset, new_val); | ||
87 | |||
88 | return new_val; | ||
89 | } | ||
90 | |||
91 | static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) | ||
92 | { | ||
93 | struct venc_state *venc = to_state(sd); | ||
94 | |||
95 | writel(val, venc->vdaccfg_reg); | ||
96 | |||
97 | val = readl(venc->vdaccfg_reg); | ||
98 | |||
99 | return val; | ||
100 | } | ||
101 | |||
102 | /* This function sets the dac of the VPBE for various outputs | ||
103 | */ | ||
104 | static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) | ||
105 | { | ||
106 | switch (out_index) { | ||
107 | case 0: | ||
108 | v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); | ||
109 | venc_write(sd, VENC_DACSEL, 0); | ||
110 | break; | ||
111 | case 1: | ||
112 | v4l2_dbg(debug, 1, sd, "Setting output to S-Video\n"); | ||
113 | venc_write(sd, VENC_DACSEL, 0x210); | ||
114 | break; | ||
115 | case 2: | ||
116 | venc_write(sd, VENC_DACSEL, 0x543); | ||
117 | break; | ||
118 | default: | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) | ||
126 | { | ||
127 | v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); | ||
128 | |||
129 | if (benable) { | ||
130 | venc_write(sd, VENC_VMOD, 0); | ||
131 | venc_write(sd, VENC_CVBS, 0); | ||
132 | venc_write(sd, VENC_LCDOUT, 0); | ||
133 | venc_write(sd, VENC_HSPLS, 0); | ||
134 | venc_write(sd, VENC_HSTART, 0); | ||
135 | venc_write(sd, VENC_HVALID, 0); | ||
136 | venc_write(sd, VENC_HINT, 0); | ||
137 | venc_write(sd, VENC_VSPLS, 0); | ||
138 | venc_write(sd, VENC_VSTART, 0); | ||
139 | venc_write(sd, VENC_VVALID, 0); | ||
140 | venc_write(sd, VENC_VINT, 0); | ||
141 | venc_write(sd, VENC_YCCCTL, 0); | ||
142 | venc_write(sd, VENC_DACSEL, 0); | ||
143 | |||
144 | } else { | ||
145 | venc_write(sd, VENC_VMOD, 0); | ||
146 | /* disable VCLK output pin enable */ | ||
147 | venc_write(sd, VENC_VIDCTL, 0x141); | ||
148 | |||
149 | /* Disable output sync pins */ | ||
150 | venc_write(sd, VENC_SYNCCTL, 0); | ||
151 | |||
152 | /* Disable DCLOCK */ | ||
153 | venc_write(sd, VENC_DCLKCTL, 0); | ||
154 | venc_write(sd, VENC_DRGBX1, 0x0000057C); | ||
155 | |||
156 | /* Disable LCD output control (accepting default polarity) */ | ||
157 | venc_write(sd, VENC_LCDOUT, 0); | ||
158 | venc_write(sd, VENC_CMPNT, 0x100); | ||
159 | venc_write(sd, VENC_HSPLS, 0); | ||
160 | venc_write(sd, VENC_HINT, 0); | ||
161 | venc_write(sd, VENC_HSTART, 0); | ||
162 | venc_write(sd, VENC_HVALID, 0); | ||
163 | |||
164 | venc_write(sd, VENC_VSPLS, 0); | ||
165 | venc_write(sd, VENC_VINT, 0); | ||
166 | venc_write(sd, VENC_VSTART, 0); | ||
167 | venc_write(sd, VENC_VVALID, 0); | ||
168 | |||
169 | venc_write(sd, VENC_HSDLY, 0); | ||
170 | venc_write(sd, VENC_VSDLY, 0); | ||
171 | |||
172 | venc_write(sd, VENC_YCCCTL, 0); | ||
173 | venc_write(sd, VENC_VSTARTA, 0); | ||
174 | |||
175 | /* Set OSD clock and OSD Sync Adavance registers */ | ||
176 | venc_write(sd, VENC_OSDCLK0, 1); | ||
177 | venc_write(sd, VENC_OSDCLK1, 2); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * setting NTSC mode | ||
183 | */ | ||
184 | static int venc_set_ntsc(struct v4l2_subdev *sd) | ||
185 | { | ||
186 | struct venc_state *venc = to_state(sd); | ||
187 | struct venc_platform_data *pdata = venc->pdata; | ||
188 | |||
189 | v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); | ||
190 | |||
191 | /* Setup clock at VPSS & VENC for SD */ | ||
192 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); | ||
193 | if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) | ||
194 | return -EINVAL; | ||
195 | |||
196 | venc_enabledigitaloutput(sd, 0); | ||
197 | |||
198 | /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ | ||
199 | venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); | ||
200 | /* Set REC656 Mode */ | ||
201 | venc_write(sd, VENC_YCCCTL, 0x1); | ||
202 | venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); | ||
203 | venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); | ||
204 | |||
205 | venc_write(sd, VENC_VMOD, 0); | ||
206 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | ||
207 | VENC_VMOD_VIE); | ||
208 | venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); | ||
209 | venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), | ||
210 | VENC_VMOD_TVTYP); | ||
211 | venc_write(sd, VENC_DACTST, 0x0); | ||
212 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * setting PAL mode | ||
219 | */ | ||
220 | static int venc_set_pal(struct v4l2_subdev *sd) | ||
221 | { | ||
222 | struct venc_state *venc = to_state(sd); | ||
223 | |||
224 | v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); | ||
225 | |||
226 | /* Setup clock at VPSS & VENC for SD */ | ||
227 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); | ||
228 | if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) | ||
229 | return -EINVAL; | ||
230 | |||
231 | venc_enabledigitaloutput(sd, 0); | ||
232 | |||
233 | /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ | ||
234 | venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); | ||
235 | /* Set REC656 Mode */ | ||
236 | venc_write(sd, VENC_YCCCTL, 0x1); | ||
237 | |||
238 | venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, | ||
239 | VENC_SYNCCTL_OVD); | ||
240 | venc_write(sd, VENC_VMOD, 0); | ||
241 | venc_modify(sd, VENC_VMOD, | ||
242 | (1 << VENC_VMOD_VIE_SHIFT), | ||
243 | VENC_VMOD_VIE); | ||
244 | venc_modify(sd, VENC_VMOD, | ||
245 | (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); | ||
246 | venc_modify(sd, VENC_VMOD, | ||
247 | (1 << VENC_VMOD_TVTYP_SHIFT), | ||
248 | VENC_VMOD_TVTYP); | ||
249 | venc_write(sd, VENC_DACTST, 0x0); | ||
250 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * venc_set_480p59_94 | ||
257 | * | ||
258 | * This function configures the video encoder to EDTV(525p) component setting. | ||
259 | */ | ||
260 | static int venc_set_480p59_94(struct v4l2_subdev *sd) | ||
261 | { | ||
262 | struct venc_state *venc = to_state(sd); | ||
263 | struct venc_platform_data *pdata = venc->pdata; | ||
264 | |||
265 | v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); | ||
266 | |||
267 | /* Setup clock at VPSS & VENC for SD */ | ||
268 | if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) | ||
269 | return -EINVAL; | ||
270 | |||
271 | venc_enabledigitaloutput(sd, 0); | ||
272 | |||
273 | venc_write(sd, VENC_OSDCLK0, 0); | ||
274 | venc_write(sd, VENC_OSDCLK1, 1); | ||
275 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, | ||
276 | VENC_VDPRO_DAFRQ); | ||
277 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, | ||
278 | VENC_VDPRO_DAUPS); | ||
279 | venc_write(sd, VENC_VMOD, 0); | ||
280 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | ||
281 | VENC_VMOD_VIE); | ||
282 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | ||
283 | venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), | ||
284 | VENC_VMOD_TVTYP); | ||
285 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << | ||
286 | VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); | ||
287 | |||
288 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * venc_set_625p | ||
295 | * | ||
296 | * This function configures the video encoder to HDTV(625p) component setting | ||
297 | */ | ||
298 | static int venc_set_576p50(struct v4l2_subdev *sd) | ||
299 | { | ||
300 | struct venc_state *venc = to_state(sd); | ||
301 | struct venc_platform_data *pdata = venc->pdata; | ||
302 | |||
303 | v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); | ||
304 | |||
305 | /* Setup clock at VPSS & VENC for SD */ | ||
306 | if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) | ||
307 | return -EINVAL; | ||
308 | |||
309 | venc_enabledigitaloutput(sd, 0); | ||
310 | |||
311 | venc_write(sd, VENC_OSDCLK0, 0); | ||
312 | venc_write(sd, VENC_OSDCLK1, 1); | ||
313 | |||
314 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, | ||
315 | VENC_VDPRO_DAFRQ); | ||
316 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, | ||
317 | VENC_VDPRO_DAUPS); | ||
318 | |||
319 | venc_write(sd, VENC_VMOD, 0); | ||
320 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | ||
321 | VENC_VMOD_VIE); | ||
322 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | ||
323 | venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), | ||
324 | VENC_VMOD_TVTYP); | ||
325 | |||
326 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << | ||
327 | VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); | ||
328 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) | ||
334 | { | ||
335 | v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); | ||
336 | |||
337 | if (norm & V4L2_STD_525_60) | ||
338 | return venc_set_ntsc(sd); | ||
339 | else if (norm & V4L2_STD_625_50) | ||
340 | return venc_set_pal(sd); | ||
341 | |||
342 | return -EINVAL; | ||
343 | } | ||
344 | |||
345 | static int venc_s_dv_preset(struct v4l2_subdev *sd, | ||
346 | struct v4l2_dv_preset *dv_preset) | ||
347 | { | ||
348 | v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); | ||
349 | |||
350 | if (dv_preset->preset == V4L2_DV_576P50) | ||
351 | return venc_set_576p50(sd); | ||
352 | else if (dv_preset->preset == V4L2_DV_480P59_94) | ||
353 | return venc_set_480p59_94(sd); | ||
354 | |||
355 | return -EINVAL; | ||
356 | } | ||
357 | |||
358 | static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, | ||
359 | u32 config) | ||
360 | { | ||
361 | struct venc_state *venc = to_state(sd); | ||
362 | int ret; | ||
363 | |||
364 | v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); | ||
365 | |||
366 | ret = venc_set_dac(sd, output); | ||
367 | if (!ret) | ||
368 | venc->output = output; | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | static long venc_ioctl(struct v4l2_subdev *sd, | ||
374 | unsigned int cmd, | ||
375 | void *arg) | ||
376 | { | ||
377 | u32 val; | ||
378 | |||
379 | switch (cmd) { | ||
380 | case VENC_GET_FLD: | ||
381 | val = venc_read(sd, VENC_VSTAT); | ||
382 | *((int *)arg) = ((val & VENC_VSTAT_FIDST) == | ||
383 | VENC_VSTAT_FIDST); | ||
384 | break; | ||
385 | default: | ||
386 | v4l2_err(sd, "Wrong IOCTL cmd\n"); | ||
387 | break; | ||
388 | } | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static const struct v4l2_subdev_core_ops venc_core_ops = { | ||
394 | .ioctl = venc_ioctl, | ||
395 | }; | ||
396 | |||
397 | static const struct v4l2_subdev_video_ops venc_video_ops = { | ||
398 | .s_routing = venc_s_routing, | ||
399 | .s_std_output = venc_s_std_output, | ||
400 | .s_dv_preset = venc_s_dv_preset, | ||
401 | }; | ||
402 | |||
403 | static const struct v4l2_subdev_ops venc_ops = { | ||
404 | .core = &venc_core_ops, | ||
405 | .video = &venc_video_ops, | ||
406 | }; | ||
407 | |||
408 | static int venc_initialize(struct v4l2_subdev *sd) | ||
409 | { | ||
410 | struct venc_state *venc = to_state(sd); | ||
411 | int ret; | ||
412 | |||
413 | /* Set default to output to composite and std to NTSC */ | ||
414 | venc->output = 0; | ||
415 | venc->std = V4L2_STD_525_60; | ||
416 | |||
417 | ret = venc_s_routing(sd, 0, venc->output, 0); | ||
418 | if (ret < 0) { | ||
419 | v4l2_err(sd, "Error setting output during init\n"); | ||
420 | return -EINVAL; | ||
421 | } | ||
422 | |||
423 | ret = venc_s_std_output(sd, venc->std); | ||
424 | if (ret < 0) { | ||
425 | v4l2_err(sd, "Error setting std during init\n"); | ||
426 | return -EINVAL; | ||
427 | } | ||
428 | |||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | static int venc_device_get(struct device *dev, void *data) | ||
433 | { | ||
434 | struct platform_device *pdev = to_platform_device(dev); | ||
435 | struct venc_state **venc = data; | ||
436 | |||
437 | if (strcmp(MODULE_NAME, pdev->name) == 0) | ||
438 | *venc = platform_get_drvdata(pdev); | ||
439 | |||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, | ||
444 | const char *venc_name) | ||
445 | { | ||
446 | struct venc_state *venc; | ||
447 | int err; | ||
448 | |||
449 | err = bus_for_each_dev(&platform_bus_type, NULL, &venc, | ||
450 | venc_device_get); | ||
451 | if (venc == NULL) | ||
452 | return NULL; | ||
453 | |||
454 | v4l2_subdev_init(&venc->sd, &venc_ops); | ||
455 | |||
456 | strcpy(venc->sd.name, venc_name); | ||
457 | if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { | ||
458 | v4l2_err(v4l2_dev, | ||
459 | "vpbe unable to register venc sub device\n"); | ||
460 | return NULL; | ||
461 | } | ||
462 | if (venc_initialize(&venc->sd)) { | ||
463 | v4l2_err(v4l2_dev, | ||
464 | "vpbe venc initialization failed\n"); | ||
465 | return NULL; | ||
466 | } | ||
467 | |||
468 | return &venc->sd; | ||
469 | } | ||
470 | EXPORT_SYMBOL(venc_sub_dev_init); | ||
471 | |||
472 | static int venc_probe(struct platform_device *pdev) | ||
473 | { | ||
474 | struct venc_state *venc; | ||
475 | struct resource *res; | ||
476 | int ret; | ||
477 | |||
478 | venc = kzalloc(sizeof(struct venc_state), GFP_KERNEL); | ||
479 | if (venc == NULL) | ||
480 | return -ENOMEM; | ||
481 | |||
482 | venc->pdev = &pdev->dev; | ||
483 | venc->pdata = pdev->dev.platform_data; | ||
484 | if (NULL == venc->pdata) { | ||
485 | dev_err(venc->pdev, "Unable to get platform data for" | ||
486 | " VENC sub device"); | ||
487 | ret = -ENOENT; | ||
488 | goto free_mem; | ||
489 | } | ||
490 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
491 | if (!res) { | ||
492 | dev_err(venc->pdev, | ||
493 | "Unable to get VENC register address map\n"); | ||
494 | ret = -ENODEV; | ||
495 | goto free_mem; | ||
496 | } | ||
497 | |||
498 | if (!request_mem_region(res->start, resource_size(res), "venc")) { | ||
499 | dev_err(venc->pdev, "Unable to reserve VENC MMIO region\n"); | ||
500 | ret = -ENODEV; | ||
501 | goto free_mem; | ||
502 | } | ||
503 | |||
504 | venc->venc_base = ioremap_nocache(res->start, resource_size(res)); | ||
505 | if (!venc->venc_base) { | ||
506 | dev_err(venc->pdev, "Unable to map VENC IO space\n"); | ||
507 | ret = -ENODEV; | ||
508 | goto release_venc_mem_region; | ||
509 | } | ||
510 | |||
511 | spin_lock_init(&venc->lock); | ||
512 | platform_set_drvdata(pdev, venc); | ||
513 | dev_notice(venc->pdev, "VENC sub device probe success\n"); | ||
514 | return 0; | ||
515 | |||
516 | release_venc_mem_region: | ||
517 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
518 | release_mem_region(res->start, resource_size(res)); | ||
519 | free_mem: | ||
520 | kfree(venc); | ||
521 | return ret; | ||
522 | } | ||
523 | |||
524 | static int venc_remove(struct platform_device *pdev) | ||
525 | { | ||
526 | struct venc_state *venc = platform_get_drvdata(pdev); | ||
527 | struct resource *res; | ||
528 | |||
529 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
530 | iounmap((void *)venc->venc_base); | ||
531 | release_mem_region(res->start, resource_size(res)); | ||
532 | kfree(venc); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static struct platform_driver venc_driver = { | ||
538 | .probe = venc_probe, | ||
539 | .remove = venc_remove, | ||
540 | .driver = { | ||
541 | .name = MODULE_NAME, | ||
542 | .owner = THIS_MODULE, | ||
543 | }, | ||
544 | }; | ||
545 | |||
546 | static int venc_init(void) | ||
547 | { | ||
548 | if (platform_driver_register(&venc_driver)) { | ||
549 | printk(KERN_ERR "Unable to register venc driver\n"); | ||
550 | return -ENODEV; | ||
551 | } | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | static void venc_exit(void) | ||
556 | { | ||
557 | platform_driver_unregister(&venc_driver); | ||
558 | return; | ||
559 | } | ||
560 | |||
561 | module_init(venc_init); | ||
562 | module_exit(venc_exit); | ||
563 | |||
564 | MODULE_LICENSE("GPL"); | ||
565 | MODULE_DESCRIPTION("VPBE VENC Driver"); | ||
566 | MODULE_AUTHOR("Texas Instruments"); | ||
diff --git a/drivers/media/video/davinci/vpbe_venc_regs.h b/drivers/media/video/davinci/vpbe_venc_regs.h new file mode 100644 index 00000000000..947cb151077 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_venc_regs.h | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2010 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation version 2.. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
16 | */ | ||
17 | #ifndef _VPBE_VENC_REGS_H | ||
18 | #define _VPBE_VENC_REGS_H | ||
19 | |||
20 | /* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ | ||
21 | #define VENC_VMOD 0x00 | ||
22 | #define VENC_VIDCTL 0x04 | ||
23 | #define VENC_VDPRO 0x08 | ||
24 | #define VENC_SYNCCTL 0x0C | ||
25 | #define VENC_HSPLS 0x10 | ||
26 | #define VENC_VSPLS 0x14 | ||
27 | #define VENC_HINT 0x18 | ||
28 | #define VENC_HSTART 0x1C | ||
29 | #define VENC_HVALID 0x20 | ||
30 | #define VENC_VINT 0x24 | ||
31 | #define VENC_VSTART 0x28 | ||
32 | #define VENC_VVALID 0x2C | ||
33 | #define VENC_HSDLY 0x30 | ||
34 | #define VENC_VSDLY 0x34 | ||
35 | #define VENC_YCCCTL 0x38 | ||
36 | #define VENC_RGBCTL 0x3C | ||
37 | #define VENC_RGBCLP 0x40 | ||
38 | #define VENC_LINECTL 0x44 | ||
39 | #define VENC_CULLLINE 0x48 | ||
40 | #define VENC_LCDOUT 0x4C | ||
41 | #define VENC_BRTS 0x50 | ||
42 | #define VENC_BRTW 0x54 | ||
43 | #define VENC_ACCTL 0x58 | ||
44 | #define VENC_PWMP 0x5C | ||
45 | #define VENC_PWMW 0x60 | ||
46 | #define VENC_DCLKCTL 0x64 | ||
47 | #define VENC_DCLKPTN0 0x68 | ||
48 | #define VENC_DCLKPTN1 0x6C | ||
49 | #define VENC_DCLKPTN2 0x70 | ||
50 | #define VENC_DCLKPTN3 0x74 | ||
51 | #define VENC_DCLKPTN0A 0x78 | ||
52 | #define VENC_DCLKPTN1A 0x7C | ||
53 | #define VENC_DCLKPTN2A 0x80 | ||
54 | #define VENC_DCLKPTN3A 0x84 | ||
55 | #define VENC_DCLKHS 0x88 | ||
56 | #define VENC_DCLKHSA 0x8C | ||
57 | #define VENC_DCLKHR 0x90 | ||
58 | #define VENC_DCLKVS 0x94 | ||
59 | #define VENC_DCLKVR 0x98 | ||
60 | #define VENC_CAPCTL 0x9C | ||
61 | #define VENC_CAPDO 0xA0 | ||
62 | #define VENC_CAPDE 0xA4 | ||
63 | #define VENC_ATR0 0xA8 | ||
64 | #define VENC_ATR1 0xAC | ||
65 | #define VENC_ATR2 0xB0 | ||
66 | #define VENC_VSTAT 0xB8 | ||
67 | #define VENC_RAMADR 0xBC | ||
68 | #define VENC_RAMPORT 0xC0 | ||
69 | #define VENC_DACTST 0xC4 | ||
70 | #define VENC_YCOLVL 0xC8 | ||
71 | #define VENC_SCPROG 0xCC | ||
72 | #define VENC_CVBS 0xDC | ||
73 | #define VENC_CMPNT 0xE0 | ||
74 | #define VENC_ETMG0 0xE4 | ||
75 | #define VENC_ETMG1 0xE8 | ||
76 | #define VENC_ETMG2 0xEC | ||
77 | #define VENC_ETMG3 0xF0 | ||
78 | #define VENC_DACSEL 0xF4 | ||
79 | #define VENC_ARGBX0 0x100 | ||
80 | #define VENC_ARGBX1 0x104 | ||
81 | #define VENC_ARGBX2 0x108 | ||
82 | #define VENC_ARGBX3 0x10C | ||
83 | #define VENC_ARGBX4 0x110 | ||
84 | #define VENC_DRGBX0 0x114 | ||
85 | #define VENC_DRGBX1 0x118 | ||
86 | #define VENC_DRGBX2 0x11C | ||
87 | #define VENC_DRGBX3 0x120 | ||
88 | #define VENC_DRGBX4 0x124 | ||
89 | #define VENC_VSTARTA 0x128 | ||
90 | #define VENC_OSDCLK0 0x12C | ||
91 | #define VENC_OSDCLK1 0x130 | ||
92 | #define VENC_HVLDCL0 0x134 | ||
93 | #define VENC_HVLDCL1 0x138 | ||
94 | #define VENC_OSDHADV 0x13C | ||
95 | #define VENC_CLKCTL 0x140 | ||
96 | #define VENC_GAMCTL 0x144 | ||
97 | #define VENC_XHINTVL 0x174 | ||
98 | |||
99 | /* bit definitions */ | ||
100 | #define VPBE_PCR_VENC_DIV (1 << 1) | ||
101 | #define VPBE_PCR_CLK_OFF (1 << 0) | ||
102 | |||
103 | #define VENC_VMOD_VDMD_SHIFT 12 | ||
104 | #define VENC_VMOD_VDMD_YCBCR16 0 | ||
105 | #define VENC_VMOD_VDMD_YCBCR8 1 | ||
106 | #define VENC_VMOD_VDMD_RGB666 2 | ||
107 | #define VENC_VMOD_VDMD_RGB8 3 | ||
108 | #define VENC_VMOD_VDMD_EPSON 4 | ||
109 | #define VENC_VMOD_VDMD_CASIO 5 | ||
110 | #define VENC_VMOD_VDMD_UDISPQVGA 6 | ||
111 | #define VENC_VMOD_VDMD_STNLCD 7 | ||
112 | #define VENC_VMOD_VIE_SHIFT 1 | ||
113 | #define VENC_VMOD_VDMD (7 << 12) | ||
114 | #define VENC_VMOD_ITLCL (1 << 11) | ||
115 | #define VENC_VMOD_ITLC (1 << 10) | ||
116 | #define VENC_VMOD_NSIT (1 << 9) | ||
117 | #define VENC_VMOD_HDMD (1 << 8) | ||
118 | #define VENC_VMOD_TVTYP_SHIFT 6 | ||
119 | #define VENC_VMOD_TVTYP (3 << 6) | ||
120 | #define VENC_VMOD_SLAVE (1 << 5) | ||
121 | #define VENC_VMOD_VMD (1 << 4) | ||
122 | #define VENC_VMOD_BLNK (1 << 3) | ||
123 | #define VENC_VMOD_VIE (1 << 1) | ||
124 | #define VENC_VMOD_VENC (1 << 0) | ||
125 | |||
126 | /* VMOD TVTYP options for HDMD=0 */ | ||
127 | #define SDTV_NTSC 0 | ||
128 | #define SDTV_PAL 1 | ||
129 | /* VMOD TVTYP options for HDMD=1 */ | ||
130 | #define HDTV_525P 0 | ||
131 | #define HDTV_625P 1 | ||
132 | #define HDTV_1080I 2 | ||
133 | #define HDTV_720P 3 | ||
134 | |||
135 | #define VENC_VIDCTL_VCLKP (1 << 14) | ||
136 | #define VENC_VIDCTL_VCLKE_SHIFT 13 | ||
137 | #define VENC_VIDCTL_VCLKE (1 << 13) | ||
138 | #define VENC_VIDCTL_VCLKZ_SHIFT 12 | ||
139 | #define VENC_VIDCTL_VCLKZ (1 << 12) | ||
140 | #define VENC_VIDCTL_SYDIR_SHIFT 8 | ||
141 | #define VENC_VIDCTL_SYDIR (1 << 8) | ||
142 | #define VENC_VIDCTL_DOMD_SHIFT 4 | ||
143 | #define VENC_VIDCTL_DOMD (3 << 4) | ||
144 | #define VENC_VIDCTL_YCDIR_SHIFT 0 | ||
145 | #define VENC_VIDCTL_YCDIR (1 << 0) | ||
146 | |||
147 | #define VENC_VDPRO_ATYCC_SHIFT 5 | ||
148 | #define VENC_VDPRO_ATYCC (1 << 5) | ||
149 | #define VENC_VDPRO_ATCOM_SHIFT 4 | ||
150 | #define VENC_VDPRO_ATCOM (1 << 4) | ||
151 | #define VENC_VDPRO_DAFRQ (1 << 3) | ||
152 | #define VENC_VDPRO_DAUPS (1 << 2) | ||
153 | #define VENC_VDPRO_CUPS (1 << 1) | ||
154 | #define VENC_VDPRO_YUPS (1 << 0) | ||
155 | |||
156 | #define VENC_SYNCCTL_VPL_SHIFT 3 | ||
157 | #define VENC_SYNCCTL_VPL (1 << 3) | ||
158 | #define VENC_SYNCCTL_HPL_SHIFT 2 | ||
159 | #define VENC_SYNCCTL_HPL (1 << 2) | ||
160 | #define VENC_SYNCCTL_SYEV_SHIFT 1 | ||
161 | #define VENC_SYNCCTL_SYEV (1 << 1) | ||
162 | #define VENC_SYNCCTL_SYEH_SHIFT 0 | ||
163 | #define VENC_SYNCCTL_SYEH (1 << 0) | ||
164 | #define VENC_SYNCCTL_OVD_SHIFT 14 | ||
165 | #define VENC_SYNCCTL_OVD (1 << 14) | ||
166 | |||
167 | #define VENC_DCLKCTL_DCKEC_SHIFT 11 | ||
168 | #define VENC_DCLKCTL_DCKEC (1 << 11) | ||
169 | #define VENC_DCLKCTL_DCKPW_SHIFT 0 | ||
170 | #define VENC_DCLKCTL_DCKPW (0x3f << 0) | ||
171 | |||
172 | #define VENC_VSTAT_FIDST (1 << 4) | ||
173 | |||
174 | #define VENC_CMPNT_MRGB_SHIFT 14 | ||
175 | #define VENC_CMPNT_MRGB (1 << 14) | ||
176 | |||
177 | #endif /* _VPBE_VENC_REGS_H */ | ||
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c new file mode 100644 index 00000000000..5b38fc93ff2 --- /dev/null +++ b/drivers/media/video/davinci/vpfe_capture.c | |||
@@ -0,0 +1,2095 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * Driver name : VPFE Capture driver | ||
19 | * VPFE Capture driver allows applications to capture and stream video | ||
20 | * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as | ||
21 | * TVP5146 or Raw Bayer RGB image data from an image sensor | ||
22 | * such as Microns' MT9T001, MT9T031 etc. | ||
23 | * | ||
24 | * These SoCs have, in common, a Video Processing Subsystem (VPSS) that | ||
25 | * consists of a Video Processing Front End (VPFE) for capturing | ||
26 | * video/raw image data and Video Processing Back End (VPBE) for displaying | ||
27 | * YUV data through an in-built analog encoder or Digital LCD port. This | ||
28 | * driver is for capture through VPFE. A typical EVM using these SoCs have | ||
29 | * following high level configuration. | ||
30 | * | ||
31 | * | ||
32 | * decoder(TVP5146/ YUV/ | ||
33 | * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) | ||
34 | * data input | | | ||
35 | * V | | ||
36 | * SDRAM | | ||
37 | * V | ||
38 | * Image Processor | ||
39 | * | | ||
40 | * V | ||
41 | * SDRAM | ||
42 | * The data flow happens from a decoder connected to the VPFE over a | ||
43 | * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface | ||
44 | * and to the input of VPFE through an optional MUX (if more inputs are | ||
45 | * to be interfaced on the EVM). The input data is first passed through | ||
46 | * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC | ||
47 | * does very little or no processing on YUV data and does pre-process Raw | ||
48 | * Bayer RGB data through modules such as Defect Pixel Correction (DFC) | ||
49 | * Color Space Conversion (CSC), data gain/offset etc. After this, data | ||
50 | * can be written to SDRAM or can be connected to the image processing | ||
51 | * block such as IPIPE (on DM355 only). | ||
52 | * | ||
53 | * Features supported | ||
54 | * - MMAP IO | ||
55 | * - Capture using TVP5146 over BT.656 | ||
56 | * - support for interfacing decoders using sub device model | ||
57 | * - Work with DM355 or DM6446 CCDC to do Raw Bayer RGB/YUV | ||
58 | * data capture to SDRAM. | ||
59 | * TODO list | ||
60 | * - Support multiple REQBUF after open | ||
61 | * - Support for de-allocating buffers through REQBUF | ||
62 | * - Support for Raw Bayer RGB capture | ||
63 | * - Support for chaining Image Processor | ||
64 | * - Support for static allocation of buffers | ||
65 | * - Support for USERPTR IO | ||
66 | * - Support for STREAMON before QBUF | ||
67 | * - Support for control ioctls | ||
68 | */ | ||
69 | #include <linux/module.h> | ||
70 | #include <linux/slab.h> | ||
71 | #include <linux/init.h> | ||
72 | #include <linux/platform_device.h> | ||
73 | #include <linux/interrupt.h> | ||
74 | #include <media/v4l2-common.h> | ||
75 | #include <linux/io.h> | ||
76 | #include <media/davinci/vpfe_capture.h> | ||
77 | #include "ccdc_hw_device.h" | ||
78 | |||
79 | static int debug; | ||
80 | static u32 numbuffers = 3; | ||
81 | static u32 bufsize = (720 * 576 * 2); | ||
82 | |||
83 | module_param(numbuffers, uint, S_IRUGO); | ||
84 | module_param(bufsize, uint, S_IRUGO); | ||
85 | module_param(debug, int, 0644); | ||
86 | |||
87 | MODULE_PARM_DESC(numbuffers, "buffer count (default:3)"); | ||
88 | MODULE_PARM_DESC(bufsize, "buffer size in bytes (default:720 x 576 x 2)"); | ||
89 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
90 | |||
91 | MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); | ||
92 | MODULE_LICENSE("GPL"); | ||
93 | MODULE_AUTHOR("Texas Instruments"); | ||
94 | |||
95 | /* standard information */ | ||
96 | struct vpfe_standard { | ||
97 | v4l2_std_id std_id; | ||
98 | unsigned int width; | ||
99 | unsigned int height; | ||
100 | struct v4l2_fract pixelaspect; | ||
101 | /* 0 - progressive, 1 - interlaced */ | ||
102 | int frame_format; | ||
103 | }; | ||
104 | |||
105 | /* ccdc configuration */ | ||
106 | struct ccdc_config { | ||
107 | /* This make sure vpfe is probed and ready to go */ | ||
108 | int vpfe_probed; | ||
109 | /* name of ccdc device */ | ||
110 | char name[32]; | ||
111 | }; | ||
112 | |||
113 | /* data structures */ | ||
114 | static struct vpfe_config_params config_params = { | ||
115 | .min_numbuffers = 3, | ||
116 | .numbuffers = 3, | ||
117 | .min_bufsize = 720 * 480 * 2, | ||
118 | .device_bufsize = 720 * 576 * 2, | ||
119 | }; | ||
120 | |||
121 | /* ccdc device registered */ | ||
122 | static struct ccdc_hw_device *ccdc_dev; | ||
123 | /* lock for accessing ccdc information */ | ||
124 | static DEFINE_MUTEX(ccdc_lock); | ||
125 | /* ccdc configuration */ | ||
126 | static struct ccdc_config *ccdc_cfg; | ||
127 | |||
128 | const struct vpfe_standard vpfe_standards[] = { | ||
129 | {V4L2_STD_525_60, 720, 480, {11, 10}, 1}, | ||
130 | {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, | ||
131 | }; | ||
132 | |||
133 | /* Used when raw Bayer image from ccdc is directly captured to SDRAM */ | ||
134 | static const struct vpfe_pixel_format vpfe_pix_fmts[] = { | ||
135 | { | ||
136 | .fmtdesc = { | ||
137 | .index = 0, | ||
138 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
139 | .description = "Bayer GrRBGb 8bit A-Law compr.", | ||
140 | .pixelformat = V4L2_PIX_FMT_SBGGR8, | ||
141 | }, | ||
142 | .bpp = 1, | ||
143 | }, | ||
144 | { | ||
145 | .fmtdesc = { | ||
146 | .index = 1, | ||
147 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
148 | .description = "Bayer GrRBGb - 16bit", | ||
149 | .pixelformat = V4L2_PIX_FMT_SBGGR16, | ||
150 | }, | ||
151 | .bpp = 2, | ||
152 | }, | ||
153 | { | ||
154 | .fmtdesc = { | ||
155 | .index = 2, | ||
156 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
157 | .description = "Bayer GrRBGb 8bit DPCM compr.", | ||
158 | .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, | ||
159 | }, | ||
160 | .bpp = 1, | ||
161 | }, | ||
162 | { | ||
163 | .fmtdesc = { | ||
164 | .index = 3, | ||
165 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
166 | .description = "YCbCr 4:2:2 Interleaved UYVY", | ||
167 | .pixelformat = V4L2_PIX_FMT_UYVY, | ||
168 | }, | ||
169 | .bpp = 2, | ||
170 | }, | ||
171 | { | ||
172 | .fmtdesc = { | ||
173 | .index = 4, | ||
174 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
175 | .description = "YCbCr 4:2:2 Interleaved YUYV", | ||
176 | .pixelformat = V4L2_PIX_FMT_YUYV, | ||
177 | }, | ||
178 | .bpp = 2, | ||
179 | }, | ||
180 | { | ||
181 | .fmtdesc = { | ||
182 | .index = 5, | ||
183 | .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
184 | .description = "Y/CbCr 4:2:0 - Semi planar", | ||
185 | .pixelformat = V4L2_PIX_FMT_NV12, | ||
186 | }, | ||
187 | .bpp = 1, | ||
188 | }, | ||
189 | }; | ||
190 | |||
191 | /* | ||
192 | * vpfe_lookup_pix_format() | ||
193 | * lookup an entry in the vpfe pix format table based on pix_format | ||
194 | */ | ||
195 | static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) | ||
196 | { | ||
197 | int i; | ||
198 | |||
199 | for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) { | ||
200 | if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat) | ||
201 | return &vpfe_pix_fmts[i]; | ||
202 | } | ||
203 | return NULL; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * vpfe_register_ccdc_device. CCDC module calls this to | ||
208 | * register with vpfe capture | ||
209 | */ | ||
210 | int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) | ||
211 | { | ||
212 | int ret = 0; | ||
213 | printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); | ||
214 | |||
215 | BUG_ON(!dev->hw_ops.open); | ||
216 | BUG_ON(!dev->hw_ops.enable); | ||
217 | BUG_ON(!dev->hw_ops.set_hw_if_params); | ||
218 | BUG_ON(!dev->hw_ops.configure); | ||
219 | BUG_ON(!dev->hw_ops.set_buftype); | ||
220 | BUG_ON(!dev->hw_ops.get_buftype); | ||
221 | BUG_ON(!dev->hw_ops.enum_pix); | ||
222 | BUG_ON(!dev->hw_ops.set_frame_format); | ||
223 | BUG_ON(!dev->hw_ops.get_frame_format); | ||
224 | BUG_ON(!dev->hw_ops.get_pixel_format); | ||
225 | BUG_ON(!dev->hw_ops.set_pixel_format); | ||
226 | BUG_ON(!dev->hw_ops.set_image_window); | ||
227 | BUG_ON(!dev->hw_ops.get_image_window); | ||
228 | BUG_ON(!dev->hw_ops.get_line_length); | ||
229 | BUG_ON(!dev->hw_ops.getfid); | ||
230 | |||
231 | mutex_lock(&ccdc_lock); | ||
232 | if (NULL == ccdc_cfg) { | ||
233 | /* | ||
234 | * TODO. Will this ever happen? if so, we need to fix it. | ||
235 | * Proabably we need to add the request to a linked list and | ||
236 | * walk through it during vpfe probe | ||
237 | */ | ||
238 | printk(KERN_ERR "vpfe capture not initialized\n"); | ||
239 | ret = -EFAULT; | ||
240 | goto unlock; | ||
241 | } | ||
242 | |||
243 | if (strcmp(dev->name, ccdc_cfg->name)) { | ||
244 | /* ignore this ccdc */ | ||
245 | ret = -EINVAL; | ||
246 | goto unlock; | ||
247 | } | ||
248 | |||
249 | if (ccdc_dev) { | ||
250 | printk(KERN_ERR "ccdc already registered\n"); | ||
251 | ret = -EINVAL; | ||
252 | goto unlock; | ||
253 | } | ||
254 | |||
255 | ccdc_dev = dev; | ||
256 | unlock: | ||
257 | mutex_unlock(&ccdc_lock); | ||
258 | return ret; | ||
259 | } | ||
260 | EXPORT_SYMBOL(vpfe_register_ccdc_device); | ||
261 | |||
262 | /* | ||
263 | * vpfe_unregister_ccdc_device. CCDC module calls this to | ||
264 | * unregister with vpfe capture | ||
265 | */ | ||
266 | void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) | ||
267 | { | ||
268 | if (NULL == dev) { | ||
269 | printk(KERN_ERR "invalid ccdc device ptr\n"); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | printk(KERN_NOTICE "vpfe_unregister_ccdc_device, dev->name = %s\n", | ||
274 | dev->name); | ||
275 | |||
276 | if (strcmp(dev->name, ccdc_cfg->name)) { | ||
277 | /* ignore this ccdc */ | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | mutex_lock(&ccdc_lock); | ||
282 | ccdc_dev = NULL; | ||
283 | mutex_unlock(&ccdc_lock); | ||
284 | return; | ||
285 | } | ||
286 | EXPORT_SYMBOL(vpfe_unregister_ccdc_device); | ||
287 | |||
288 | /* | ||
289 | * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings | ||
290 | */ | ||
291 | static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe_dev, | ||
292 | struct v4l2_format *f) | ||
293 | { | ||
294 | struct v4l2_rect image_win; | ||
295 | enum ccdc_buftype buf_type; | ||
296 | enum ccdc_frmfmt frm_fmt; | ||
297 | |||
298 | memset(f, 0, sizeof(*f)); | ||
299 | f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
300 | ccdc_dev->hw_ops.get_image_window(&image_win); | ||
301 | f->fmt.pix.width = image_win.width; | ||
302 | f->fmt.pix.height = image_win.height; | ||
303 | f->fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); | ||
304 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * | ||
305 | f->fmt.pix.height; | ||
306 | buf_type = ccdc_dev->hw_ops.get_buftype(); | ||
307 | f->fmt.pix.pixelformat = ccdc_dev->hw_ops.get_pixel_format(); | ||
308 | frm_fmt = ccdc_dev->hw_ops.get_frame_format(); | ||
309 | if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) | ||
310 | f->fmt.pix.field = V4L2_FIELD_NONE; | ||
311 | else if (frm_fmt == CCDC_FRMFMT_INTERLACED) { | ||
312 | if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) | ||
313 | f->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
314 | else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) | ||
315 | f->fmt.pix.field = V4L2_FIELD_SEQ_TB; | ||
316 | else { | ||
317 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf_type\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | } else { | ||
321 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid frm_fmt\n"); | ||
322 | return -EINVAL; | ||
323 | } | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | * vpfe_config_ccdc_image_format() | ||
329 | * For a pix format, configure ccdc to setup the capture | ||
330 | */ | ||
331 | static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) | ||
332 | { | ||
333 | enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; | ||
334 | int ret = 0; | ||
335 | |||
336 | if (ccdc_dev->hw_ops.set_pixel_format( | ||
337 | vpfe_dev->fmt.fmt.pix.pixelformat) < 0) { | ||
338 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
339 | "couldn't set pix format in ccdc\n"); | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | /* configure the image window */ | ||
343 | ccdc_dev->hw_ops.set_image_window(&vpfe_dev->crop); | ||
344 | |||
345 | switch (vpfe_dev->fmt.fmt.pix.field) { | ||
346 | case V4L2_FIELD_INTERLACED: | ||
347 | /* do nothing, since it is default */ | ||
348 | ret = ccdc_dev->hw_ops.set_buftype( | ||
349 | CCDC_BUFTYPE_FLD_INTERLEAVED); | ||
350 | break; | ||
351 | case V4L2_FIELD_NONE: | ||
352 | frm_fmt = CCDC_FRMFMT_PROGRESSIVE; | ||
353 | /* buffer type only applicable for interlaced scan */ | ||
354 | break; | ||
355 | case V4L2_FIELD_SEQ_TB: | ||
356 | ret = ccdc_dev->hw_ops.set_buftype( | ||
357 | CCDC_BUFTYPE_FLD_SEPARATED); | ||
358 | break; | ||
359 | default: | ||
360 | return -EINVAL; | ||
361 | } | ||
362 | |||
363 | /* set the frame format */ | ||
364 | if (!ret) | ||
365 | ret = ccdc_dev->hw_ops.set_frame_format(frm_fmt); | ||
366 | return ret; | ||
367 | } | ||
368 | /* | ||
369 | * vpfe_config_image_format() | ||
370 | * For a given standard, this functions sets up the default | ||
371 | * pix format & crop values in the vpfe device and ccdc. It first | ||
372 | * starts with defaults based values from the standard table. | ||
373 | * It then checks if sub device support g_mbus_fmt and then override the | ||
374 | * values based on that.Sets crop values to match with scan resolution | ||
375 | * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the | ||
376 | * values in ccdc | ||
377 | */ | ||
378 | static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, | ||
379 | const v4l2_std_id *std_id) | ||
380 | { | ||
381 | struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; | ||
382 | struct v4l2_mbus_framefmt mbus_fmt; | ||
383 | struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; | ||
384 | int i, ret = 0; | ||
385 | |||
386 | for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { | ||
387 | if (vpfe_standards[i].std_id & *std_id) { | ||
388 | vpfe_dev->std_info.active_pixels = | ||
389 | vpfe_standards[i].width; | ||
390 | vpfe_dev->std_info.active_lines = | ||
391 | vpfe_standards[i].height; | ||
392 | vpfe_dev->std_info.frame_format = | ||
393 | vpfe_standards[i].frame_format; | ||
394 | vpfe_dev->std_index = i; | ||
395 | break; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | if (i == ARRAY_SIZE(vpfe_standards)) { | ||
400 | v4l2_err(&vpfe_dev->v4l2_dev, "standard not supported\n"); | ||
401 | return -EINVAL; | ||
402 | } | ||
403 | |||
404 | vpfe_dev->crop.top = 0; | ||
405 | vpfe_dev->crop.left = 0; | ||
406 | vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels; | ||
407 | vpfe_dev->crop.height = vpfe_dev->std_info.active_lines; | ||
408 | pix->width = vpfe_dev->crop.width; | ||
409 | pix->height = vpfe_dev->crop.height; | ||
410 | |||
411 | /* first field and frame format based on standard frame format */ | ||
412 | if (vpfe_dev->std_info.frame_format) { | ||
413 | pix->field = V4L2_FIELD_INTERLACED; | ||
414 | /* assume V4L2_PIX_FMT_UYVY as default */ | ||
415 | pix->pixelformat = V4L2_PIX_FMT_UYVY; | ||
416 | v4l2_fill_mbus_format(&mbus_fmt, pix, | ||
417 | V4L2_MBUS_FMT_YUYV10_2X10); | ||
418 | } else { | ||
419 | pix->field = V4L2_FIELD_NONE; | ||
420 | /* assume V4L2_PIX_FMT_SBGGR8 */ | ||
421 | pix->pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
422 | v4l2_fill_mbus_format(&mbus_fmt, pix, | ||
423 | V4L2_MBUS_FMT_SBGGR8_1X8); | ||
424 | } | ||
425 | |||
426 | /* if sub device supports g_mbus_fmt, override the defaults */ | ||
427 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, | ||
428 | sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt); | ||
429 | |||
430 | if (ret && ret != -ENOIOCTLCMD) { | ||
431 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
432 | "error in getting g_mbus_fmt from sub device\n"); | ||
433 | return ret; | ||
434 | } | ||
435 | v4l2_fill_pix_format(pix, &mbus_fmt); | ||
436 | pix->bytesperline = pix->width * 2; | ||
437 | pix->sizeimage = pix->bytesperline * pix->height; | ||
438 | |||
439 | /* Sets the values in CCDC */ | ||
440 | ret = vpfe_config_ccdc_image_format(vpfe_dev); | ||
441 | if (ret) | ||
442 | return ret; | ||
443 | |||
444 | /* Update the values of sizeimage and bytesperline */ | ||
445 | if (!ret) { | ||
446 | pix->bytesperline = ccdc_dev->hw_ops.get_line_length(); | ||
447 | pix->sizeimage = pix->bytesperline * pix->height; | ||
448 | } | ||
449 | return ret; | ||
450 | } | ||
451 | |||
452 | static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) | ||
453 | { | ||
454 | int ret = 0; | ||
455 | |||
456 | /* set first input of current subdevice as the current input */ | ||
457 | vpfe_dev->current_input = 0; | ||
458 | |||
459 | /* set default standard */ | ||
460 | vpfe_dev->std_index = 0; | ||
461 | |||
462 | /* Configure the default format information */ | ||
463 | ret = vpfe_config_image_format(vpfe_dev, | ||
464 | &vpfe_standards[vpfe_dev->std_index].std_id); | ||
465 | if (ret) | ||
466 | return ret; | ||
467 | |||
468 | /* now open the ccdc device to initialize it */ | ||
469 | mutex_lock(&ccdc_lock); | ||
470 | if (NULL == ccdc_dev) { | ||
471 | v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); | ||
472 | ret = -ENODEV; | ||
473 | goto unlock; | ||
474 | } | ||
475 | |||
476 | if (!try_module_get(ccdc_dev->owner)) { | ||
477 | v4l2_err(&vpfe_dev->v4l2_dev, "Couldn't lock ccdc module\n"); | ||
478 | ret = -ENODEV; | ||
479 | goto unlock; | ||
480 | } | ||
481 | ret = ccdc_dev->hw_ops.open(vpfe_dev->pdev); | ||
482 | if (!ret) | ||
483 | vpfe_dev->initialized = 1; | ||
484 | |||
485 | /* Clear all VPFE/CCDC interrupts */ | ||
486 | if (vpfe_dev->cfg->clr_intr) | ||
487 | vpfe_dev->cfg->clr_intr(-1); | ||
488 | |||
489 | unlock: | ||
490 | mutex_unlock(&ccdc_lock); | ||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | /* | ||
495 | * vpfe_open : It creates object of file handle structure and | ||
496 | * stores it in private_data member of filepointer | ||
497 | */ | ||
498 | static int vpfe_open(struct file *file) | ||
499 | { | ||
500 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
501 | struct vpfe_fh *fh; | ||
502 | |||
503 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n"); | ||
504 | |||
505 | if (!vpfe_dev->cfg->num_subdevs) { | ||
506 | v4l2_err(&vpfe_dev->v4l2_dev, "No decoder registered\n"); | ||
507 | return -ENODEV; | ||
508 | } | ||
509 | |||
510 | /* Allocate memory for the file handle object */ | ||
511 | fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); | ||
512 | if (NULL == fh) { | ||
513 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
514 | "unable to allocate memory for file handle object\n"); | ||
515 | return -ENOMEM; | ||
516 | } | ||
517 | /* store pointer to fh in private_data member of file */ | ||
518 | file->private_data = fh; | ||
519 | fh->vpfe_dev = vpfe_dev; | ||
520 | mutex_lock(&vpfe_dev->lock); | ||
521 | /* If decoder is not initialized. initialize it */ | ||
522 | if (!vpfe_dev->initialized) { | ||
523 | if (vpfe_initialize_device(vpfe_dev)) { | ||
524 | mutex_unlock(&vpfe_dev->lock); | ||
525 | return -ENODEV; | ||
526 | } | ||
527 | } | ||
528 | /* Increment device usrs counter */ | ||
529 | vpfe_dev->usrs++; | ||
530 | /* Set io_allowed member to false */ | ||
531 | fh->io_allowed = 0; | ||
532 | /* Initialize priority of this instance to default priority */ | ||
533 | fh->prio = V4L2_PRIORITY_UNSET; | ||
534 | v4l2_prio_open(&vpfe_dev->prio, &fh->prio); | ||
535 | mutex_unlock(&vpfe_dev->lock); | ||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe_dev) | ||
540 | { | ||
541 | unsigned long addr; | ||
542 | |||
543 | vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, | ||
544 | struct videobuf_buffer, queue); | ||
545 | list_del(&vpfe_dev->next_frm->queue); | ||
546 | vpfe_dev->next_frm->state = VIDEOBUF_ACTIVE; | ||
547 | addr = videobuf_to_dma_contig(vpfe_dev->next_frm); | ||
548 | |||
549 | ccdc_dev->hw_ops.setfbaddr(addr); | ||
550 | } | ||
551 | |||
552 | static void vpfe_schedule_bottom_field(struct vpfe_device *vpfe_dev) | ||
553 | { | ||
554 | unsigned long addr; | ||
555 | |||
556 | addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); | ||
557 | addr += vpfe_dev->field_off; | ||
558 | ccdc_dev->hw_ops.setfbaddr(addr); | ||
559 | } | ||
560 | |||
561 | static void vpfe_process_buffer_complete(struct vpfe_device *vpfe_dev) | ||
562 | { | ||
563 | struct timeval timevalue; | ||
564 | |||
565 | do_gettimeofday(&timevalue); | ||
566 | vpfe_dev->cur_frm->ts = timevalue; | ||
567 | vpfe_dev->cur_frm->state = VIDEOBUF_DONE; | ||
568 | vpfe_dev->cur_frm->size = vpfe_dev->fmt.fmt.pix.sizeimage; | ||
569 | wake_up_interruptible(&vpfe_dev->cur_frm->done); | ||
570 | vpfe_dev->cur_frm = vpfe_dev->next_frm; | ||
571 | } | ||
572 | |||
573 | /* ISR for VINT0*/ | ||
574 | static irqreturn_t vpfe_isr(int irq, void *dev_id) | ||
575 | { | ||
576 | struct vpfe_device *vpfe_dev = dev_id; | ||
577 | enum v4l2_field field; | ||
578 | int fid; | ||
579 | |||
580 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nStarting vpfe_isr...\n"); | ||
581 | field = vpfe_dev->fmt.fmt.pix.field; | ||
582 | |||
583 | /* if streaming not started, don't do anything */ | ||
584 | if (!vpfe_dev->started) | ||
585 | goto clear_intr; | ||
586 | |||
587 | /* only for 6446 this will be applicable */ | ||
588 | if (NULL != ccdc_dev->hw_ops.reset) | ||
589 | ccdc_dev->hw_ops.reset(); | ||
590 | |||
591 | if (field == V4L2_FIELD_NONE) { | ||
592 | /* handle progressive frame capture */ | ||
593 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
594 | "frame format is progressive...\n"); | ||
595 | if (vpfe_dev->cur_frm != vpfe_dev->next_frm) | ||
596 | vpfe_process_buffer_complete(vpfe_dev); | ||
597 | goto clear_intr; | ||
598 | } | ||
599 | |||
600 | /* interlaced or TB capture check which field we are in hardware */ | ||
601 | fid = ccdc_dev->hw_ops.getfid(); | ||
602 | |||
603 | /* switch the software maintained field id */ | ||
604 | vpfe_dev->field_id ^= 1; | ||
605 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "field id = %x:%x.\n", | ||
606 | fid, vpfe_dev->field_id); | ||
607 | if (fid == vpfe_dev->field_id) { | ||
608 | /* we are in-sync here,continue */ | ||
609 | if (fid == 0) { | ||
610 | /* | ||
611 | * One frame is just being captured. If the next frame | ||
612 | * is available, release the current frame and move on | ||
613 | */ | ||
614 | if (vpfe_dev->cur_frm != vpfe_dev->next_frm) | ||
615 | vpfe_process_buffer_complete(vpfe_dev); | ||
616 | /* | ||
617 | * based on whether the two fields are stored | ||
618 | * interleavely or separately in memory, reconfigure | ||
619 | * the CCDC memory address | ||
620 | */ | ||
621 | if (field == V4L2_FIELD_SEQ_TB) { | ||
622 | vpfe_schedule_bottom_field(vpfe_dev); | ||
623 | } | ||
624 | goto clear_intr; | ||
625 | } | ||
626 | /* | ||
627 | * if one field is just being captured configure | ||
628 | * the next frame get the next frame from the empty | ||
629 | * queue if no frame is available hold on to the | ||
630 | * current buffer | ||
631 | */ | ||
632 | spin_lock(&vpfe_dev->dma_queue_lock); | ||
633 | if (!list_empty(&vpfe_dev->dma_queue) && | ||
634 | vpfe_dev->cur_frm == vpfe_dev->next_frm) | ||
635 | vpfe_schedule_next_buffer(vpfe_dev); | ||
636 | spin_unlock(&vpfe_dev->dma_queue_lock); | ||
637 | } else if (fid == 0) { | ||
638 | /* | ||
639 | * out of sync. Recover from any hardware out-of-sync. | ||
640 | * May loose one frame | ||
641 | */ | ||
642 | vpfe_dev->field_id = fid; | ||
643 | } | ||
644 | clear_intr: | ||
645 | if (vpfe_dev->cfg->clr_intr) | ||
646 | vpfe_dev->cfg->clr_intr(irq); | ||
647 | |||
648 | return IRQ_HANDLED; | ||
649 | } | ||
650 | |||
651 | /* vdint1_isr - isr handler for VINT1 interrupt */ | ||
652 | static irqreturn_t vdint1_isr(int irq, void *dev_id) | ||
653 | { | ||
654 | struct vpfe_device *vpfe_dev = dev_id; | ||
655 | |||
656 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "\nInside vdint1_isr...\n"); | ||
657 | |||
658 | /* if streaming not started, don't do anything */ | ||
659 | if (!vpfe_dev->started) { | ||
660 | if (vpfe_dev->cfg->clr_intr) | ||
661 | vpfe_dev->cfg->clr_intr(irq); | ||
662 | return IRQ_HANDLED; | ||
663 | } | ||
664 | |||
665 | spin_lock(&vpfe_dev->dma_queue_lock); | ||
666 | if ((vpfe_dev->fmt.fmt.pix.field == V4L2_FIELD_NONE) && | ||
667 | !list_empty(&vpfe_dev->dma_queue) && | ||
668 | vpfe_dev->cur_frm == vpfe_dev->next_frm) | ||
669 | vpfe_schedule_next_buffer(vpfe_dev); | ||
670 | spin_unlock(&vpfe_dev->dma_queue_lock); | ||
671 | |||
672 | if (vpfe_dev->cfg->clr_intr) | ||
673 | vpfe_dev->cfg->clr_intr(irq); | ||
674 | |||
675 | return IRQ_HANDLED; | ||
676 | } | ||
677 | |||
678 | static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) | ||
679 | { | ||
680 | enum ccdc_frmfmt frame_format; | ||
681 | |||
682 | frame_format = ccdc_dev->hw_ops.get_frame_format(); | ||
683 | if (frame_format == CCDC_FRMFMT_PROGRESSIVE) | ||
684 | free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); | ||
685 | } | ||
686 | |||
687 | static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) | ||
688 | { | ||
689 | enum ccdc_frmfmt frame_format; | ||
690 | |||
691 | frame_format = ccdc_dev->hw_ops.get_frame_format(); | ||
692 | if (frame_format == CCDC_FRMFMT_PROGRESSIVE) { | ||
693 | return request_irq(vpfe_dev->ccdc_irq1, vdint1_isr, | ||
694 | IRQF_DISABLED, "vpfe_capture1", | ||
695 | vpfe_dev); | ||
696 | } | ||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | /* vpfe_stop_ccdc_capture: stop streaming in ccdc/isif */ | ||
701 | static void vpfe_stop_ccdc_capture(struct vpfe_device *vpfe_dev) | ||
702 | { | ||
703 | vpfe_dev->started = 0; | ||
704 | ccdc_dev->hw_ops.enable(0); | ||
705 | if (ccdc_dev->hw_ops.enable_out_to_sdram) | ||
706 | ccdc_dev->hw_ops.enable_out_to_sdram(0); | ||
707 | } | ||
708 | |||
709 | /* | ||
710 | * vpfe_release : This function deletes buffer queue, frees the | ||
711 | * buffers and the vpfe file handle | ||
712 | */ | ||
713 | static int vpfe_release(struct file *file) | ||
714 | { | ||
715 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
716 | struct vpfe_fh *fh = file->private_data; | ||
717 | struct vpfe_subdev_info *sdinfo; | ||
718 | int ret; | ||
719 | |||
720 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); | ||
721 | |||
722 | /* Get the device lock */ | ||
723 | mutex_lock(&vpfe_dev->lock); | ||
724 | /* if this instance is doing IO */ | ||
725 | if (fh->io_allowed) { | ||
726 | if (vpfe_dev->started) { | ||
727 | sdinfo = vpfe_dev->current_subdev; | ||
728 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, | ||
729 | sdinfo->grp_id, | ||
730 | video, s_stream, 0); | ||
731 | if (ret && (ret != -ENOIOCTLCMD)) | ||
732 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
733 | "stream off failed in subdev\n"); | ||
734 | vpfe_stop_ccdc_capture(vpfe_dev); | ||
735 | vpfe_detach_irq(vpfe_dev); | ||
736 | videobuf_streamoff(&vpfe_dev->buffer_queue); | ||
737 | } | ||
738 | vpfe_dev->io_usrs = 0; | ||
739 | vpfe_dev->numbuffers = config_params.numbuffers; | ||
740 | } | ||
741 | |||
742 | /* Decrement device usrs counter */ | ||
743 | vpfe_dev->usrs--; | ||
744 | /* Close the priority */ | ||
745 | v4l2_prio_close(&vpfe_dev->prio, fh->prio); | ||
746 | /* If this is the last file handle */ | ||
747 | if (!vpfe_dev->usrs) { | ||
748 | vpfe_dev->initialized = 0; | ||
749 | if (ccdc_dev->hw_ops.close) | ||
750 | ccdc_dev->hw_ops.close(vpfe_dev->pdev); | ||
751 | module_put(ccdc_dev->owner); | ||
752 | } | ||
753 | mutex_unlock(&vpfe_dev->lock); | ||
754 | file->private_data = NULL; | ||
755 | /* Free memory allocated to file handle object */ | ||
756 | kfree(fh); | ||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | /* | ||
761 | * vpfe_mmap : It is used to map kernel space buffers | ||
762 | * into user spaces | ||
763 | */ | ||
764 | static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) | ||
765 | { | ||
766 | /* Get the device object and file handle object */ | ||
767 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
768 | |||
769 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); | ||
770 | |||
771 | return videobuf_mmap_mapper(&vpfe_dev->buffer_queue, vma); | ||
772 | } | ||
773 | |||
774 | /* | ||
775 | * vpfe_poll: It is used for select/poll system call | ||
776 | */ | ||
777 | static unsigned int vpfe_poll(struct file *file, poll_table *wait) | ||
778 | { | ||
779 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
780 | |||
781 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); | ||
782 | |||
783 | if (vpfe_dev->started) | ||
784 | return videobuf_poll_stream(file, | ||
785 | &vpfe_dev->buffer_queue, wait); | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | /* vpfe capture driver file operations */ | ||
790 | static const struct v4l2_file_operations vpfe_fops = { | ||
791 | .owner = THIS_MODULE, | ||
792 | .open = vpfe_open, | ||
793 | .release = vpfe_release, | ||
794 | .unlocked_ioctl = video_ioctl2, | ||
795 | .mmap = vpfe_mmap, | ||
796 | .poll = vpfe_poll | ||
797 | }; | ||
798 | |||
799 | /* | ||
800 | * vpfe_check_format() | ||
801 | * This function adjust the input pixel format as per hardware | ||
802 | * capabilities and update the same in pixfmt. | ||
803 | * Following algorithm used :- | ||
804 | * | ||
805 | * If given pixformat is not in the vpfe list of pix formats or not | ||
806 | * supported by the hardware, current value of pixformat in the device | ||
807 | * is used | ||
808 | * If given field is not supported, then current field is used. If field | ||
809 | * is different from current, then it is matched with that from sub device. | ||
810 | * Minimum height is 2 lines for interlaced or tb field and 1 line for | ||
811 | * progressive. Maximum height is clamped to active active lines of scan | ||
812 | * Minimum width is 32 bytes in memory and width is clamped to active | ||
813 | * pixels of scan. | ||
814 | * bytesperline is a multiple of 32. | ||
815 | */ | ||
816 | static const struct vpfe_pixel_format * | ||
817 | vpfe_check_format(struct vpfe_device *vpfe_dev, | ||
818 | struct v4l2_pix_format *pixfmt) | ||
819 | { | ||
820 | u32 min_height = 1, min_width = 32, max_width, max_height; | ||
821 | const struct vpfe_pixel_format *vpfe_pix_fmt; | ||
822 | u32 pix; | ||
823 | int temp, found; | ||
824 | |||
825 | vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); | ||
826 | if (NULL == vpfe_pix_fmt) { | ||
827 | /* | ||
828 | * use current pixel format in the vpfe device. We | ||
829 | * will find this pix format in the table | ||
830 | */ | ||
831 | pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; | ||
832 | vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); | ||
833 | } | ||
834 | |||
835 | /* check if hw supports it */ | ||
836 | temp = 0; | ||
837 | found = 0; | ||
838 | while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) { | ||
839 | if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) { | ||
840 | found = 1; | ||
841 | break; | ||
842 | } | ||
843 | temp++; | ||
844 | } | ||
845 | |||
846 | if (!found) { | ||
847 | /* use current pixel format */ | ||
848 | pixfmt->pixelformat = vpfe_dev->fmt.fmt.pix.pixelformat; | ||
849 | /* | ||
850 | * Since this is currently used in the vpfe device, we | ||
851 | * will find this pix format in the table | ||
852 | */ | ||
853 | vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); | ||
854 | } | ||
855 | |||
856 | /* check what field format is supported */ | ||
857 | if (pixfmt->field == V4L2_FIELD_ANY) { | ||
858 | /* if field is any, use current value as default */ | ||
859 | pixfmt->field = vpfe_dev->fmt.fmt.pix.field; | ||
860 | } | ||
861 | |||
862 | /* | ||
863 | * if field is not same as current field in the vpfe device | ||
864 | * try matching the field with the sub device field | ||
865 | */ | ||
866 | if (vpfe_dev->fmt.fmt.pix.field != pixfmt->field) { | ||
867 | /* | ||
868 | * If field value is not in the supported fields, use current | ||
869 | * field used in the device as default | ||
870 | */ | ||
871 | switch (pixfmt->field) { | ||
872 | case V4L2_FIELD_INTERLACED: | ||
873 | case V4L2_FIELD_SEQ_TB: | ||
874 | /* if sub device is supporting progressive, use that */ | ||
875 | if (!vpfe_dev->std_info.frame_format) | ||
876 | pixfmt->field = V4L2_FIELD_NONE; | ||
877 | break; | ||
878 | case V4L2_FIELD_NONE: | ||
879 | if (vpfe_dev->std_info.frame_format) | ||
880 | pixfmt->field = V4L2_FIELD_INTERLACED; | ||
881 | break; | ||
882 | |||
883 | default: | ||
884 | /* use current field as default */ | ||
885 | pixfmt->field = vpfe_dev->fmt.fmt.pix.field; | ||
886 | break; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | /* Now adjust image resolutions supported */ | ||
891 | if (pixfmt->field == V4L2_FIELD_INTERLACED || | ||
892 | pixfmt->field == V4L2_FIELD_SEQ_TB) | ||
893 | min_height = 2; | ||
894 | |||
895 | max_width = vpfe_dev->std_info.active_pixels; | ||
896 | max_height = vpfe_dev->std_info.active_lines; | ||
897 | min_width /= vpfe_pix_fmt->bpp; | ||
898 | |||
899 | v4l2_info(&vpfe_dev->v4l2_dev, "width = %d, height = %d, bpp = %d\n", | ||
900 | pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp); | ||
901 | |||
902 | pixfmt->width = clamp((pixfmt->width), min_width, max_width); | ||
903 | pixfmt->height = clamp((pixfmt->height), min_height, max_height); | ||
904 | |||
905 | /* If interlaced, adjust height to be a multiple of 2 */ | ||
906 | if (pixfmt->field == V4L2_FIELD_INTERLACED) | ||
907 | pixfmt->height &= (~1); | ||
908 | /* | ||
909 | * recalculate bytesperline and sizeimage since width | ||
910 | * and height might have changed | ||
911 | */ | ||
912 | pixfmt->bytesperline = (((pixfmt->width * vpfe_pix_fmt->bpp) + 31) | ||
913 | & ~31); | ||
914 | if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) | ||
915 | pixfmt->sizeimage = | ||
916 | pixfmt->bytesperline * pixfmt->height + | ||
917 | ((pixfmt->bytesperline * pixfmt->height) >> 1); | ||
918 | else | ||
919 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
920 | |||
921 | v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height =" | ||
922 | " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", | ||
923 | pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, | ||
924 | pixfmt->bytesperline, pixfmt->sizeimage); | ||
925 | return vpfe_pix_fmt; | ||
926 | } | ||
927 | |||
928 | static int vpfe_querycap(struct file *file, void *priv, | ||
929 | struct v4l2_capability *cap) | ||
930 | { | ||
931 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
932 | |||
933 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); | ||
934 | |||
935 | cap->version = VPFE_CAPTURE_VERSION_CODE; | ||
936 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
937 | strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); | ||
938 | strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); | ||
939 | strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static int vpfe_g_fmt_vid_cap(struct file *file, void *priv, | ||
944 | struct v4l2_format *fmt) | ||
945 | { | ||
946 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
947 | int ret = 0; | ||
948 | |||
949 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt_vid_cap\n"); | ||
950 | /* Fill in the information about format */ | ||
951 | *fmt = vpfe_dev->fmt; | ||
952 | return ret; | ||
953 | } | ||
954 | |||
955 | static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, | ||
956 | struct v4l2_fmtdesc *fmt) | ||
957 | { | ||
958 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
959 | const struct vpfe_pixel_format *pix_fmt; | ||
960 | int temp_index; | ||
961 | u32 pix; | ||
962 | |||
963 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n"); | ||
964 | |||
965 | if (ccdc_dev->hw_ops.enum_pix(&pix, fmt->index) < 0) | ||
966 | return -EINVAL; | ||
967 | |||
968 | /* Fill in the information about format */ | ||
969 | pix_fmt = vpfe_lookup_pix_format(pix); | ||
970 | if (NULL != pix_fmt) { | ||
971 | temp_index = fmt->index; | ||
972 | *fmt = pix_fmt->fmtdesc; | ||
973 | fmt->index = temp_index; | ||
974 | return 0; | ||
975 | } | ||
976 | return -EINVAL; | ||
977 | } | ||
978 | |||
979 | static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, | ||
980 | struct v4l2_format *fmt) | ||
981 | { | ||
982 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
983 | const struct vpfe_pixel_format *pix_fmts; | ||
984 | int ret = 0; | ||
985 | |||
986 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); | ||
987 | |||
988 | /* If streaming is started, return error */ | ||
989 | if (vpfe_dev->started) { | ||
990 | v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); | ||
991 | return -EBUSY; | ||
992 | } | ||
993 | |||
994 | /* Check for valid frame format */ | ||
995 | pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); | ||
996 | |||
997 | if (NULL == pix_fmts) | ||
998 | return -EINVAL; | ||
999 | |||
1000 | /* store the pixel format in the device object */ | ||
1001 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1002 | if (ret) | ||
1003 | return ret; | ||
1004 | |||
1005 | /* First detach any IRQ if currently attached */ | ||
1006 | vpfe_detach_irq(vpfe_dev); | ||
1007 | vpfe_dev->fmt = *fmt; | ||
1008 | /* set image capture parameters in the ccdc */ | ||
1009 | ret = vpfe_config_ccdc_image_format(vpfe_dev); | ||
1010 | mutex_unlock(&vpfe_dev->lock); | ||
1011 | return ret; | ||
1012 | } | ||
1013 | |||
1014 | static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, | ||
1015 | struct v4l2_format *f) | ||
1016 | { | ||
1017 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1018 | const struct vpfe_pixel_format *pix_fmts; | ||
1019 | |||
1020 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); | ||
1021 | |||
1022 | pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); | ||
1023 | if (NULL == pix_fmts) | ||
1024 | return -EINVAL; | ||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | /* | ||
1029 | * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a | ||
1030 | * given app input index | ||
1031 | */ | ||
1032 | static int vpfe_get_subdev_input_index(struct vpfe_device *vpfe_dev, | ||
1033 | int *subdev_index, | ||
1034 | int *subdev_input_index, | ||
1035 | int app_input_index) | ||
1036 | { | ||
1037 | struct vpfe_config *cfg = vpfe_dev->cfg; | ||
1038 | struct vpfe_subdev_info *sdinfo; | ||
1039 | int i, j = 0; | ||
1040 | |||
1041 | for (i = 0; i < cfg->num_subdevs; i++) { | ||
1042 | sdinfo = &cfg->sub_devs[i]; | ||
1043 | if (app_input_index < (j + sdinfo->num_inputs)) { | ||
1044 | *subdev_index = i; | ||
1045 | *subdev_input_index = app_input_index - j; | ||
1046 | return 0; | ||
1047 | } | ||
1048 | j += sdinfo->num_inputs; | ||
1049 | } | ||
1050 | return -EINVAL; | ||
1051 | } | ||
1052 | |||
1053 | /* | ||
1054 | * vpfe_get_app_input - Get app input index for a given subdev input index | ||
1055 | * driver stores the input index of the current sub device and translate it | ||
1056 | * when application request the current input | ||
1057 | */ | ||
1058 | static int vpfe_get_app_input_index(struct vpfe_device *vpfe_dev, | ||
1059 | int *app_input_index) | ||
1060 | { | ||
1061 | struct vpfe_config *cfg = vpfe_dev->cfg; | ||
1062 | struct vpfe_subdev_info *sdinfo; | ||
1063 | int i, j = 0; | ||
1064 | |||
1065 | for (i = 0; i < cfg->num_subdevs; i++) { | ||
1066 | sdinfo = &cfg->sub_devs[i]; | ||
1067 | if (!strcmp(sdinfo->name, vpfe_dev->current_subdev->name)) { | ||
1068 | if (vpfe_dev->current_input >= sdinfo->num_inputs) | ||
1069 | return -1; | ||
1070 | *app_input_index = j + vpfe_dev->current_input; | ||
1071 | return 0; | ||
1072 | } | ||
1073 | j += sdinfo->num_inputs; | ||
1074 | } | ||
1075 | return -EINVAL; | ||
1076 | } | ||
1077 | |||
1078 | static int vpfe_enum_input(struct file *file, void *priv, | ||
1079 | struct v4l2_input *inp) | ||
1080 | { | ||
1081 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1082 | struct vpfe_subdev_info *sdinfo; | ||
1083 | int subdev, index ; | ||
1084 | |||
1085 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); | ||
1086 | |||
1087 | if (vpfe_get_subdev_input_index(vpfe_dev, | ||
1088 | &subdev, | ||
1089 | &index, | ||
1090 | inp->index) < 0) { | ||
1091 | v4l2_err(&vpfe_dev->v4l2_dev, "input information not found" | ||
1092 | " for the subdev\n"); | ||
1093 | return -EINVAL; | ||
1094 | } | ||
1095 | sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; | ||
1096 | memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); | ||
1097 | return 0; | ||
1098 | } | ||
1099 | |||
1100 | static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) | ||
1101 | { | ||
1102 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1103 | |||
1104 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); | ||
1105 | |||
1106 | return vpfe_get_app_input_index(vpfe_dev, index); | ||
1107 | } | ||
1108 | |||
1109 | |||
1110 | static int vpfe_s_input(struct file *file, void *priv, unsigned int index) | ||
1111 | { | ||
1112 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1113 | struct vpfe_subdev_info *sdinfo; | ||
1114 | int subdev_index, inp_index; | ||
1115 | struct vpfe_route *route; | ||
1116 | u32 input = 0, output = 0; | ||
1117 | int ret = -EINVAL; | ||
1118 | |||
1119 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); | ||
1120 | |||
1121 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1122 | if (ret) | ||
1123 | return ret; | ||
1124 | |||
1125 | /* | ||
1126 | * If streaming is started return device busy | ||
1127 | * error | ||
1128 | */ | ||
1129 | if (vpfe_dev->started) { | ||
1130 | v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); | ||
1131 | ret = -EBUSY; | ||
1132 | goto unlock_out; | ||
1133 | } | ||
1134 | |||
1135 | if (vpfe_get_subdev_input_index(vpfe_dev, | ||
1136 | &subdev_index, | ||
1137 | &inp_index, | ||
1138 | index) < 0) { | ||
1139 | v4l2_err(&vpfe_dev->v4l2_dev, "invalid input index\n"); | ||
1140 | goto unlock_out; | ||
1141 | } | ||
1142 | |||
1143 | sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; | ||
1144 | route = &sdinfo->routes[inp_index]; | ||
1145 | if (route && sdinfo->can_route) { | ||
1146 | input = route->input; | ||
1147 | output = route->output; | ||
1148 | } | ||
1149 | |||
1150 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1151 | video, s_routing, input, output, 0); | ||
1152 | |||
1153 | if (ret) { | ||
1154 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1155 | "vpfe_doioctl:error in setting input in decoder\n"); | ||
1156 | ret = -EINVAL; | ||
1157 | goto unlock_out; | ||
1158 | } | ||
1159 | vpfe_dev->current_subdev = sdinfo; | ||
1160 | vpfe_dev->current_input = index; | ||
1161 | vpfe_dev->std_index = 0; | ||
1162 | |||
1163 | /* set the bus/interface parameter for the sub device in ccdc */ | ||
1164 | ret = ccdc_dev->hw_ops.set_hw_if_params(&sdinfo->ccdc_if_params); | ||
1165 | if (ret) | ||
1166 | goto unlock_out; | ||
1167 | |||
1168 | /* set the default image parameters in the device */ | ||
1169 | ret = vpfe_config_image_format(vpfe_dev, | ||
1170 | &vpfe_standards[vpfe_dev->std_index].std_id); | ||
1171 | unlock_out: | ||
1172 | mutex_unlock(&vpfe_dev->lock); | ||
1173 | return ret; | ||
1174 | } | ||
1175 | |||
1176 | static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1177 | { | ||
1178 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1179 | struct vpfe_subdev_info *sdinfo; | ||
1180 | int ret = 0; | ||
1181 | |||
1182 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); | ||
1183 | |||
1184 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1185 | sdinfo = vpfe_dev->current_subdev; | ||
1186 | if (ret) | ||
1187 | return ret; | ||
1188 | /* Call querystd function of decoder device */ | ||
1189 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1190 | video, querystd, std_id); | ||
1191 | mutex_unlock(&vpfe_dev->lock); | ||
1192 | return ret; | ||
1193 | } | ||
1194 | |||
1195 | static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1196 | { | ||
1197 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1198 | struct vpfe_subdev_info *sdinfo; | ||
1199 | int ret = 0; | ||
1200 | |||
1201 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); | ||
1202 | |||
1203 | /* Call decoder driver function to set the standard */ | ||
1204 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1205 | if (ret) | ||
1206 | return ret; | ||
1207 | |||
1208 | sdinfo = vpfe_dev->current_subdev; | ||
1209 | /* If streaming is started, return device busy error */ | ||
1210 | if (vpfe_dev->started) { | ||
1211 | v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); | ||
1212 | ret = -EBUSY; | ||
1213 | goto unlock_out; | ||
1214 | } | ||
1215 | |||
1216 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1217 | core, s_std, *std_id); | ||
1218 | if (ret < 0) { | ||
1219 | v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); | ||
1220 | goto unlock_out; | ||
1221 | } | ||
1222 | ret = vpfe_config_image_format(vpfe_dev, std_id); | ||
1223 | |||
1224 | unlock_out: | ||
1225 | mutex_unlock(&vpfe_dev->lock); | ||
1226 | return ret; | ||
1227 | } | ||
1228 | |||
1229 | static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1230 | { | ||
1231 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1232 | |||
1233 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); | ||
1234 | |||
1235 | *std_id = vpfe_standards[vpfe_dev->std_index].std_id; | ||
1236 | return 0; | ||
1237 | } | ||
1238 | /* | ||
1239 | * Videobuf operations | ||
1240 | */ | ||
1241 | static int vpfe_videobuf_setup(struct videobuf_queue *vq, | ||
1242 | unsigned int *count, | ||
1243 | unsigned int *size) | ||
1244 | { | ||
1245 | struct vpfe_fh *fh = vq->priv_data; | ||
1246 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1247 | |||
1248 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_setup\n"); | ||
1249 | *size = vpfe_dev->fmt.fmt.pix.sizeimage; | ||
1250 | if (vpfe_dev->memory == V4L2_MEMORY_MMAP && | ||
1251 | vpfe_dev->fmt.fmt.pix.sizeimage > config_params.device_bufsize) | ||
1252 | *size = config_params.device_bufsize; | ||
1253 | |||
1254 | if (*count < config_params.min_numbuffers) | ||
1255 | *count = config_params.min_numbuffers; | ||
1256 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1257 | "count=%d, size=%d\n", *count, *size); | ||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | static int vpfe_videobuf_prepare(struct videobuf_queue *vq, | ||
1262 | struct videobuf_buffer *vb, | ||
1263 | enum v4l2_field field) | ||
1264 | { | ||
1265 | struct vpfe_fh *fh = vq->priv_data; | ||
1266 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1267 | unsigned long addr; | ||
1268 | int ret; | ||
1269 | |||
1270 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); | ||
1271 | |||
1272 | /* If buffer is not initialized, initialize it */ | ||
1273 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
1274 | vb->width = vpfe_dev->fmt.fmt.pix.width; | ||
1275 | vb->height = vpfe_dev->fmt.fmt.pix.height; | ||
1276 | vb->size = vpfe_dev->fmt.fmt.pix.sizeimage; | ||
1277 | vb->field = field; | ||
1278 | |||
1279 | ret = videobuf_iolock(vq, vb, NULL); | ||
1280 | if (ret < 0) | ||
1281 | return ret; | ||
1282 | |||
1283 | addr = videobuf_to_dma_contig(vb); | ||
1284 | /* Make sure user addresses are aligned to 32 bytes */ | ||
1285 | if (!ALIGN(addr, 32)) | ||
1286 | return -EINVAL; | ||
1287 | |||
1288 | vb->state = VIDEOBUF_PREPARED; | ||
1289 | } | ||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | static void vpfe_videobuf_queue(struct videobuf_queue *vq, | ||
1294 | struct videobuf_buffer *vb) | ||
1295 | { | ||
1296 | /* Get the file handle object and device object */ | ||
1297 | struct vpfe_fh *fh = vq->priv_data; | ||
1298 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1299 | unsigned long flags; | ||
1300 | |||
1301 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue\n"); | ||
1302 | |||
1303 | /* add the buffer to the DMA queue */ | ||
1304 | spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); | ||
1305 | list_add_tail(&vb->queue, &vpfe_dev->dma_queue); | ||
1306 | spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); | ||
1307 | |||
1308 | /* Change state of the buffer */ | ||
1309 | vb->state = VIDEOBUF_QUEUED; | ||
1310 | } | ||
1311 | |||
1312 | static void vpfe_videobuf_release(struct videobuf_queue *vq, | ||
1313 | struct videobuf_buffer *vb) | ||
1314 | { | ||
1315 | struct vpfe_fh *fh = vq->priv_data; | ||
1316 | struct vpfe_device *vpfe_dev = fh->vpfe_dev; | ||
1317 | unsigned long flags; | ||
1318 | |||
1319 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_videobuf_release\n"); | ||
1320 | |||
1321 | /* | ||
1322 | * We need to flush the buffer from the dma queue since | ||
1323 | * they are de-allocated | ||
1324 | */ | ||
1325 | spin_lock_irqsave(&vpfe_dev->dma_queue_lock, flags); | ||
1326 | INIT_LIST_HEAD(&vpfe_dev->dma_queue); | ||
1327 | spin_unlock_irqrestore(&vpfe_dev->dma_queue_lock, flags); | ||
1328 | videobuf_dma_contig_free(vq, vb); | ||
1329 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
1330 | } | ||
1331 | |||
1332 | static struct videobuf_queue_ops vpfe_videobuf_qops = { | ||
1333 | .buf_setup = vpfe_videobuf_setup, | ||
1334 | .buf_prepare = vpfe_videobuf_prepare, | ||
1335 | .buf_queue = vpfe_videobuf_queue, | ||
1336 | .buf_release = vpfe_videobuf_release, | ||
1337 | }; | ||
1338 | |||
1339 | /* | ||
1340 | * vpfe_reqbufs. currently support REQBUF only once opening | ||
1341 | * the device. | ||
1342 | */ | ||
1343 | static int vpfe_reqbufs(struct file *file, void *priv, | ||
1344 | struct v4l2_requestbuffers *req_buf) | ||
1345 | { | ||
1346 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1347 | struct vpfe_fh *fh = file->private_data; | ||
1348 | int ret = 0; | ||
1349 | |||
1350 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); | ||
1351 | |||
1352 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type) { | ||
1353 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1354 | return -EINVAL; | ||
1355 | } | ||
1356 | |||
1357 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1358 | if (ret) | ||
1359 | return ret; | ||
1360 | |||
1361 | if (vpfe_dev->io_usrs != 0) { | ||
1362 | v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); | ||
1363 | ret = -EBUSY; | ||
1364 | goto unlock_out; | ||
1365 | } | ||
1366 | |||
1367 | vpfe_dev->memory = req_buf->memory; | ||
1368 | videobuf_queue_dma_contig_init(&vpfe_dev->buffer_queue, | ||
1369 | &vpfe_videobuf_qops, | ||
1370 | vpfe_dev->pdev, | ||
1371 | &vpfe_dev->irqlock, | ||
1372 | req_buf->type, | ||
1373 | vpfe_dev->fmt.fmt.pix.field, | ||
1374 | sizeof(struct videobuf_buffer), | ||
1375 | fh, NULL); | ||
1376 | |||
1377 | fh->io_allowed = 1; | ||
1378 | vpfe_dev->io_usrs = 1; | ||
1379 | INIT_LIST_HEAD(&vpfe_dev->dma_queue); | ||
1380 | ret = videobuf_reqbufs(&vpfe_dev->buffer_queue, req_buf); | ||
1381 | unlock_out: | ||
1382 | mutex_unlock(&vpfe_dev->lock); | ||
1383 | return ret; | ||
1384 | } | ||
1385 | |||
1386 | static int vpfe_querybuf(struct file *file, void *priv, | ||
1387 | struct v4l2_buffer *buf) | ||
1388 | { | ||
1389 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1390 | |||
1391 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); | ||
1392 | |||
1393 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { | ||
1394 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1395 | return -EINVAL; | ||
1396 | } | ||
1397 | |||
1398 | if (vpfe_dev->memory != V4L2_MEMORY_MMAP) { | ||
1399 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); | ||
1400 | return -EINVAL; | ||
1401 | } | ||
1402 | /* Call videobuf_querybuf to get information */ | ||
1403 | return videobuf_querybuf(&vpfe_dev->buffer_queue, buf); | ||
1404 | } | ||
1405 | |||
1406 | static int vpfe_qbuf(struct file *file, void *priv, | ||
1407 | struct v4l2_buffer *p) | ||
1408 | { | ||
1409 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1410 | struct vpfe_fh *fh = file->private_data; | ||
1411 | |||
1412 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); | ||
1413 | |||
1414 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type) { | ||
1415 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1416 | return -EINVAL; | ||
1417 | } | ||
1418 | |||
1419 | /* | ||
1420 | * If this file handle is not allowed to do IO, | ||
1421 | * return error | ||
1422 | */ | ||
1423 | if (!fh->io_allowed) { | ||
1424 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | ||
1425 | return -EACCES; | ||
1426 | } | ||
1427 | return videobuf_qbuf(&vpfe_dev->buffer_queue, p); | ||
1428 | } | ||
1429 | |||
1430 | static int vpfe_dqbuf(struct file *file, void *priv, | ||
1431 | struct v4l2_buffer *buf) | ||
1432 | { | ||
1433 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1434 | |||
1435 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); | ||
1436 | |||
1437 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type) { | ||
1438 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1439 | return -EINVAL; | ||
1440 | } | ||
1441 | return videobuf_dqbuf(&vpfe_dev->buffer_queue, | ||
1442 | buf, file->f_flags & O_NONBLOCK); | ||
1443 | } | ||
1444 | |||
1445 | static int vpfe_queryctrl(struct file *file, void *priv, | ||
1446 | struct v4l2_queryctrl *qctrl) | ||
1447 | { | ||
1448 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1449 | struct vpfe_subdev_info *sdinfo; | ||
1450 | |||
1451 | sdinfo = vpfe_dev->current_subdev; | ||
1452 | |||
1453 | return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1454 | core, queryctrl, qctrl); | ||
1455 | |||
1456 | } | ||
1457 | |||
1458 | static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) | ||
1459 | { | ||
1460 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1461 | struct vpfe_subdev_info *sdinfo; | ||
1462 | |||
1463 | sdinfo = vpfe_dev->current_subdev; | ||
1464 | |||
1465 | return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1466 | core, g_ctrl, ctrl); | ||
1467 | } | ||
1468 | |||
1469 | static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) | ||
1470 | { | ||
1471 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1472 | struct vpfe_subdev_info *sdinfo; | ||
1473 | |||
1474 | sdinfo = vpfe_dev->current_subdev; | ||
1475 | |||
1476 | return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1477 | core, s_ctrl, ctrl); | ||
1478 | } | ||
1479 | |||
1480 | /* | ||
1481 | * vpfe_calculate_offsets : This function calculates buffers offset | ||
1482 | * for top and bottom field | ||
1483 | */ | ||
1484 | static void vpfe_calculate_offsets(struct vpfe_device *vpfe_dev) | ||
1485 | { | ||
1486 | struct v4l2_rect image_win; | ||
1487 | |||
1488 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_calculate_offsets\n"); | ||
1489 | |||
1490 | ccdc_dev->hw_ops.get_image_window(&image_win); | ||
1491 | vpfe_dev->field_off = image_win.height * image_win.width; | ||
1492 | } | ||
1493 | |||
1494 | /* vpfe_start_ccdc_capture: start streaming in ccdc/isif */ | ||
1495 | static void vpfe_start_ccdc_capture(struct vpfe_device *vpfe_dev) | ||
1496 | { | ||
1497 | ccdc_dev->hw_ops.enable(1); | ||
1498 | if (ccdc_dev->hw_ops.enable_out_to_sdram) | ||
1499 | ccdc_dev->hw_ops.enable_out_to_sdram(1); | ||
1500 | vpfe_dev->started = 1; | ||
1501 | } | ||
1502 | |||
1503 | /* | ||
1504 | * vpfe_streamon. Assume the DMA queue is not empty. | ||
1505 | * application is expected to call QBUF before calling | ||
1506 | * this ioctl. If not, driver returns error | ||
1507 | */ | ||
1508 | static int vpfe_streamon(struct file *file, void *priv, | ||
1509 | enum v4l2_buf_type buf_type) | ||
1510 | { | ||
1511 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1512 | struct vpfe_fh *fh = file->private_data; | ||
1513 | struct vpfe_subdev_info *sdinfo; | ||
1514 | unsigned long addr; | ||
1515 | int ret = 0; | ||
1516 | |||
1517 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); | ||
1518 | |||
1519 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { | ||
1520 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1521 | return -EINVAL; | ||
1522 | } | ||
1523 | |||
1524 | /* If file handle is not allowed IO, return error */ | ||
1525 | if (!fh->io_allowed) { | ||
1526 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | ||
1527 | return -EACCES; | ||
1528 | } | ||
1529 | |||
1530 | sdinfo = vpfe_dev->current_subdev; | ||
1531 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1532 | video, s_stream, 1); | ||
1533 | |||
1534 | if (ret && (ret != -ENOIOCTLCMD)) { | ||
1535 | v4l2_err(&vpfe_dev->v4l2_dev, "stream on failed in subdev\n"); | ||
1536 | return -EINVAL; | ||
1537 | } | ||
1538 | |||
1539 | /* If buffer queue is empty, return error */ | ||
1540 | if (list_empty(&vpfe_dev->buffer_queue.stream)) { | ||
1541 | v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); | ||
1542 | return -EIO; | ||
1543 | } | ||
1544 | |||
1545 | /* Call videobuf_streamon to start streaming * in videobuf */ | ||
1546 | ret = videobuf_streamon(&vpfe_dev->buffer_queue); | ||
1547 | if (ret) | ||
1548 | return ret; | ||
1549 | |||
1550 | |||
1551 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1552 | if (ret) | ||
1553 | goto streamoff; | ||
1554 | /* Get the next frame from the buffer queue */ | ||
1555 | vpfe_dev->next_frm = list_entry(vpfe_dev->dma_queue.next, | ||
1556 | struct videobuf_buffer, queue); | ||
1557 | vpfe_dev->cur_frm = vpfe_dev->next_frm; | ||
1558 | /* Remove buffer from the buffer queue */ | ||
1559 | list_del(&vpfe_dev->cur_frm->queue); | ||
1560 | /* Mark state of the current frame to active */ | ||
1561 | vpfe_dev->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1562 | /* Initialize field_id and started member */ | ||
1563 | vpfe_dev->field_id = 0; | ||
1564 | addr = videobuf_to_dma_contig(vpfe_dev->cur_frm); | ||
1565 | |||
1566 | /* Calculate field offset */ | ||
1567 | vpfe_calculate_offsets(vpfe_dev); | ||
1568 | |||
1569 | if (vpfe_attach_irq(vpfe_dev) < 0) { | ||
1570 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1571 | "Error in attaching interrupt handle\n"); | ||
1572 | ret = -EFAULT; | ||
1573 | goto unlock_out; | ||
1574 | } | ||
1575 | if (ccdc_dev->hw_ops.configure() < 0) { | ||
1576 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1577 | "Error in configuring ccdc\n"); | ||
1578 | ret = -EINVAL; | ||
1579 | goto unlock_out; | ||
1580 | } | ||
1581 | ccdc_dev->hw_ops.setfbaddr((unsigned long)(addr)); | ||
1582 | vpfe_start_ccdc_capture(vpfe_dev); | ||
1583 | mutex_unlock(&vpfe_dev->lock); | ||
1584 | return ret; | ||
1585 | unlock_out: | ||
1586 | mutex_unlock(&vpfe_dev->lock); | ||
1587 | streamoff: | ||
1588 | ret = videobuf_streamoff(&vpfe_dev->buffer_queue); | ||
1589 | return ret; | ||
1590 | } | ||
1591 | |||
1592 | static int vpfe_streamoff(struct file *file, void *priv, | ||
1593 | enum v4l2_buf_type buf_type) | ||
1594 | { | ||
1595 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1596 | struct vpfe_fh *fh = file->private_data; | ||
1597 | struct vpfe_subdev_info *sdinfo; | ||
1598 | int ret = 0; | ||
1599 | |||
1600 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); | ||
1601 | |||
1602 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type) { | ||
1603 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | ||
1604 | return -EINVAL; | ||
1605 | } | ||
1606 | |||
1607 | /* If io is allowed for this file handle, return error */ | ||
1608 | if (!fh->io_allowed) { | ||
1609 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | ||
1610 | return -EACCES; | ||
1611 | } | ||
1612 | |||
1613 | /* If streaming is not started, return error */ | ||
1614 | if (!vpfe_dev->started) { | ||
1615 | v4l2_err(&vpfe_dev->v4l2_dev, "device started\n"); | ||
1616 | return -EINVAL; | ||
1617 | } | ||
1618 | |||
1619 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1620 | if (ret) | ||
1621 | return ret; | ||
1622 | |||
1623 | vpfe_stop_ccdc_capture(vpfe_dev); | ||
1624 | vpfe_detach_irq(vpfe_dev); | ||
1625 | |||
1626 | sdinfo = vpfe_dev->current_subdev; | ||
1627 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | ||
1628 | video, s_stream, 0); | ||
1629 | |||
1630 | if (ret && (ret != -ENOIOCTLCMD)) | ||
1631 | v4l2_err(&vpfe_dev->v4l2_dev, "stream off failed in subdev\n"); | ||
1632 | ret = videobuf_streamoff(&vpfe_dev->buffer_queue); | ||
1633 | mutex_unlock(&vpfe_dev->lock); | ||
1634 | return ret; | ||
1635 | } | ||
1636 | |||
1637 | static int vpfe_cropcap(struct file *file, void *priv, | ||
1638 | struct v4l2_cropcap *crop) | ||
1639 | { | ||
1640 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1641 | |||
1642 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n"); | ||
1643 | |||
1644 | if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards)) | ||
1645 | return -EINVAL; | ||
1646 | |||
1647 | memset(crop, 0, sizeof(struct v4l2_cropcap)); | ||
1648 | crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1649 | crop->bounds.width = crop->defrect.width = | ||
1650 | vpfe_standards[vpfe_dev->std_index].width; | ||
1651 | crop->bounds.height = crop->defrect.height = | ||
1652 | vpfe_standards[vpfe_dev->std_index].height; | ||
1653 | crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect; | ||
1654 | return 0; | ||
1655 | } | ||
1656 | |||
1657 | static int vpfe_g_crop(struct file *file, void *priv, | ||
1658 | struct v4l2_crop *crop) | ||
1659 | { | ||
1660 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1661 | |||
1662 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_crop\n"); | ||
1663 | |||
1664 | crop->c = vpfe_dev->crop; | ||
1665 | return 0; | ||
1666 | } | ||
1667 | |||
1668 | static int vpfe_s_crop(struct file *file, void *priv, | ||
1669 | struct v4l2_crop *crop) | ||
1670 | { | ||
1671 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1672 | int ret = 0; | ||
1673 | |||
1674 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); | ||
1675 | |||
1676 | if (vpfe_dev->started) { | ||
1677 | /* make sure streaming is not started */ | ||
1678 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1679 | "Cannot change crop when streaming is ON\n"); | ||
1680 | return -EBUSY; | ||
1681 | } | ||
1682 | |||
1683 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1684 | if (ret) | ||
1685 | return ret; | ||
1686 | |||
1687 | if (crop->c.top < 0 || crop->c.left < 0) { | ||
1688 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1689 | "doesn't support negative values for top & left\n"); | ||
1690 | ret = -EINVAL; | ||
1691 | goto unlock_out; | ||
1692 | } | ||
1693 | |||
1694 | /* adjust the width to 16 pixel boundary */ | ||
1695 | crop->c.width = ((crop->c.width + 15) & ~0xf); | ||
1696 | |||
1697 | /* make sure parameters are valid */ | ||
1698 | if ((crop->c.left + crop->c.width > | ||
1699 | vpfe_dev->std_info.active_pixels) || | ||
1700 | (crop->c.top + crop->c.height > | ||
1701 | vpfe_dev->std_info.active_lines)) { | ||
1702 | v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); | ||
1703 | ret = -EINVAL; | ||
1704 | goto unlock_out; | ||
1705 | } | ||
1706 | ccdc_dev->hw_ops.set_image_window(&crop->c); | ||
1707 | vpfe_dev->fmt.fmt.pix.width = crop->c.width; | ||
1708 | vpfe_dev->fmt.fmt.pix.height = crop->c.height; | ||
1709 | vpfe_dev->fmt.fmt.pix.bytesperline = | ||
1710 | ccdc_dev->hw_ops.get_line_length(); | ||
1711 | vpfe_dev->fmt.fmt.pix.sizeimage = | ||
1712 | vpfe_dev->fmt.fmt.pix.bytesperline * | ||
1713 | vpfe_dev->fmt.fmt.pix.height; | ||
1714 | vpfe_dev->crop = crop->c; | ||
1715 | unlock_out: | ||
1716 | mutex_unlock(&vpfe_dev->lock); | ||
1717 | return ret; | ||
1718 | } | ||
1719 | |||
1720 | |||
1721 | static long vpfe_param_handler(struct file *file, void *priv, | ||
1722 | bool valid_prio, int cmd, void *param) | ||
1723 | { | ||
1724 | struct vpfe_device *vpfe_dev = video_drvdata(file); | ||
1725 | int ret = 0; | ||
1726 | |||
1727 | v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); | ||
1728 | |||
1729 | if (vpfe_dev->started) { | ||
1730 | /* only allowed if streaming is not started */ | ||
1731 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1732 | "device already started\n"); | ||
1733 | return -EBUSY; | ||
1734 | } | ||
1735 | |||
1736 | ret = mutex_lock_interruptible(&vpfe_dev->lock); | ||
1737 | if (ret) | ||
1738 | return ret; | ||
1739 | |||
1740 | switch (cmd) { | ||
1741 | case VPFE_CMD_S_CCDC_RAW_PARAMS: | ||
1742 | v4l2_warn(&vpfe_dev->v4l2_dev, | ||
1743 | "VPFE_CMD_S_CCDC_RAW_PARAMS: experimental ioctl\n"); | ||
1744 | if (ccdc_dev->hw_ops.set_params) { | ||
1745 | ret = ccdc_dev->hw_ops.set_params(param); | ||
1746 | if (ret) { | ||
1747 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1748 | "Error setting parameters in CCDC\n"); | ||
1749 | goto unlock_out; | ||
1750 | } | ||
1751 | if (vpfe_get_ccdc_image_format(vpfe_dev, | ||
1752 | &vpfe_dev->fmt) < 0) { | ||
1753 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1754 | "Invalid image format at CCDC\n"); | ||
1755 | goto unlock_out; | ||
1756 | } | ||
1757 | } else { | ||
1758 | ret = -EINVAL; | ||
1759 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1760 | "VPFE_CMD_S_CCDC_RAW_PARAMS not supported\n"); | ||
1761 | } | ||
1762 | break; | ||
1763 | default: | ||
1764 | ret = -EINVAL; | ||
1765 | } | ||
1766 | unlock_out: | ||
1767 | mutex_unlock(&vpfe_dev->lock); | ||
1768 | return ret; | ||
1769 | } | ||
1770 | |||
1771 | |||
1772 | /* vpfe capture ioctl operations */ | ||
1773 | static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { | ||
1774 | .vidioc_querycap = vpfe_querycap, | ||
1775 | .vidioc_g_fmt_vid_cap = vpfe_g_fmt_vid_cap, | ||
1776 | .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt_vid_cap, | ||
1777 | .vidioc_s_fmt_vid_cap = vpfe_s_fmt_vid_cap, | ||
1778 | .vidioc_try_fmt_vid_cap = vpfe_try_fmt_vid_cap, | ||
1779 | .vidioc_enum_input = vpfe_enum_input, | ||
1780 | .vidioc_g_input = vpfe_g_input, | ||
1781 | .vidioc_s_input = vpfe_s_input, | ||
1782 | .vidioc_querystd = vpfe_querystd, | ||
1783 | .vidioc_s_std = vpfe_s_std, | ||
1784 | .vidioc_g_std = vpfe_g_std, | ||
1785 | .vidioc_queryctrl = vpfe_queryctrl, | ||
1786 | .vidioc_g_ctrl = vpfe_g_ctrl, | ||
1787 | .vidioc_s_ctrl = vpfe_s_ctrl, | ||
1788 | .vidioc_reqbufs = vpfe_reqbufs, | ||
1789 | .vidioc_querybuf = vpfe_querybuf, | ||
1790 | .vidioc_qbuf = vpfe_qbuf, | ||
1791 | .vidioc_dqbuf = vpfe_dqbuf, | ||
1792 | .vidioc_streamon = vpfe_streamon, | ||
1793 | .vidioc_streamoff = vpfe_streamoff, | ||
1794 | .vidioc_cropcap = vpfe_cropcap, | ||
1795 | .vidioc_g_crop = vpfe_g_crop, | ||
1796 | .vidioc_s_crop = vpfe_s_crop, | ||
1797 | .vidioc_default = vpfe_param_handler, | ||
1798 | }; | ||
1799 | |||
1800 | static struct vpfe_device *vpfe_initialize(void) | ||
1801 | { | ||
1802 | struct vpfe_device *vpfe_dev; | ||
1803 | |||
1804 | /* Default number of buffers should be 3 */ | ||
1805 | if ((numbuffers > 0) && | ||
1806 | (numbuffers < config_params.min_numbuffers)) | ||
1807 | numbuffers = config_params.min_numbuffers; | ||
1808 | |||
1809 | /* | ||
1810 | * Set buffer size to min buffers size if invalid buffer size is | ||
1811 | * given | ||
1812 | */ | ||
1813 | if (bufsize < config_params.min_bufsize) | ||
1814 | bufsize = config_params.min_bufsize; | ||
1815 | |||
1816 | config_params.numbuffers = numbuffers; | ||
1817 | |||
1818 | if (numbuffers) | ||
1819 | config_params.device_bufsize = bufsize; | ||
1820 | |||
1821 | /* Allocate memory for device objects */ | ||
1822 | vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); | ||
1823 | |||
1824 | return vpfe_dev; | ||
1825 | } | ||
1826 | |||
1827 | /* | ||
1828 | * vpfe_probe : This function creates device entries by register | ||
1829 | * itself to the V4L2 driver and initializes fields of each | ||
1830 | * device objects | ||
1831 | */ | ||
1832 | static __init int vpfe_probe(struct platform_device *pdev) | ||
1833 | { | ||
1834 | struct vpfe_subdev_info *sdinfo; | ||
1835 | struct vpfe_config *vpfe_cfg; | ||
1836 | struct resource *res1; | ||
1837 | struct vpfe_device *vpfe_dev; | ||
1838 | struct i2c_adapter *i2c_adap; | ||
1839 | struct video_device *vfd; | ||
1840 | int ret = -ENOMEM, i, j; | ||
1841 | int num_subdevs = 0; | ||
1842 | |||
1843 | /* Get the pointer to the device object */ | ||
1844 | vpfe_dev = vpfe_initialize(); | ||
1845 | |||
1846 | if (!vpfe_dev) { | ||
1847 | v4l2_err(pdev->dev.driver, | ||
1848 | "Failed to allocate memory for vpfe_dev\n"); | ||
1849 | return ret; | ||
1850 | } | ||
1851 | |||
1852 | vpfe_dev->pdev = &pdev->dev; | ||
1853 | |||
1854 | if (NULL == pdev->dev.platform_data) { | ||
1855 | v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); | ||
1856 | ret = -ENODEV; | ||
1857 | goto probe_free_dev_mem; | ||
1858 | } | ||
1859 | |||
1860 | vpfe_cfg = pdev->dev.platform_data; | ||
1861 | vpfe_dev->cfg = vpfe_cfg; | ||
1862 | if (NULL == vpfe_cfg->ccdc || | ||
1863 | NULL == vpfe_cfg->card_name || | ||
1864 | NULL == vpfe_cfg->sub_devs) { | ||
1865 | v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); | ||
1866 | ret = -ENOENT; | ||
1867 | goto probe_free_dev_mem; | ||
1868 | } | ||
1869 | |||
1870 | /* Allocate memory for ccdc configuration */ | ||
1871 | ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); | ||
1872 | if (NULL == ccdc_cfg) { | ||
1873 | v4l2_err(pdev->dev.driver, | ||
1874 | "Memory allocation failed for ccdc_cfg\n"); | ||
1875 | goto probe_free_lock; | ||
1876 | } | ||
1877 | |||
1878 | mutex_lock(&ccdc_lock); | ||
1879 | |||
1880 | strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); | ||
1881 | /* Get VINT0 irq resource */ | ||
1882 | res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1883 | if (!res1) { | ||
1884 | v4l2_err(pdev->dev.driver, | ||
1885 | "Unable to get interrupt for VINT0\n"); | ||
1886 | ret = -ENODEV; | ||
1887 | goto probe_free_ccdc_cfg_mem; | ||
1888 | } | ||
1889 | vpfe_dev->ccdc_irq0 = res1->start; | ||
1890 | |||
1891 | /* Get VINT1 irq resource */ | ||
1892 | res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); | ||
1893 | if (!res1) { | ||
1894 | v4l2_err(pdev->dev.driver, | ||
1895 | "Unable to get interrupt for VINT1\n"); | ||
1896 | ret = -ENODEV; | ||
1897 | goto probe_free_ccdc_cfg_mem; | ||
1898 | } | ||
1899 | vpfe_dev->ccdc_irq1 = res1->start; | ||
1900 | |||
1901 | ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, IRQF_DISABLED, | ||
1902 | "vpfe_capture0", vpfe_dev); | ||
1903 | |||
1904 | if (0 != ret) { | ||
1905 | v4l2_err(pdev->dev.driver, "Unable to request interrupt\n"); | ||
1906 | goto probe_free_ccdc_cfg_mem; | ||
1907 | } | ||
1908 | |||
1909 | /* Allocate memory for video device */ | ||
1910 | vfd = video_device_alloc(); | ||
1911 | if (NULL == vfd) { | ||
1912 | ret = -ENOMEM; | ||
1913 | v4l2_err(pdev->dev.driver, "Unable to alloc video device\n"); | ||
1914 | goto probe_out_release_irq; | ||
1915 | } | ||
1916 | |||
1917 | /* Initialize field of video device */ | ||
1918 | vfd->release = video_device_release; | ||
1919 | vfd->fops = &vpfe_fops; | ||
1920 | vfd->ioctl_ops = &vpfe_ioctl_ops; | ||
1921 | vfd->tvnorms = 0; | ||
1922 | vfd->current_norm = V4L2_STD_PAL; | ||
1923 | vfd->v4l2_dev = &vpfe_dev->v4l2_dev; | ||
1924 | snprintf(vfd->name, sizeof(vfd->name), | ||
1925 | "%s_V%d.%d.%d", | ||
1926 | CAPTURE_DRV_NAME, | ||
1927 | (VPFE_CAPTURE_VERSION_CODE >> 16) & 0xff, | ||
1928 | (VPFE_CAPTURE_VERSION_CODE >> 8) & 0xff, | ||
1929 | (VPFE_CAPTURE_VERSION_CODE) & 0xff); | ||
1930 | /* Set video_dev to the video device */ | ||
1931 | vpfe_dev->video_dev = vfd; | ||
1932 | |||
1933 | ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); | ||
1934 | if (ret) { | ||
1935 | v4l2_err(pdev->dev.driver, | ||
1936 | "Unable to register v4l2 device.\n"); | ||
1937 | goto probe_out_video_release; | ||
1938 | } | ||
1939 | v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); | ||
1940 | spin_lock_init(&vpfe_dev->irqlock); | ||
1941 | spin_lock_init(&vpfe_dev->dma_queue_lock); | ||
1942 | mutex_init(&vpfe_dev->lock); | ||
1943 | |||
1944 | /* Initialize field of the device objects */ | ||
1945 | vpfe_dev->numbuffers = config_params.numbuffers; | ||
1946 | |||
1947 | /* Initialize prio member of device object */ | ||
1948 | v4l2_prio_init(&vpfe_dev->prio); | ||
1949 | /* register video device */ | ||
1950 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1951 | "trying to register vpfe device.\n"); | ||
1952 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | ||
1953 | "video_dev=%x\n", (int)&vpfe_dev->video_dev); | ||
1954 | vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1955 | ret = video_register_device(vpfe_dev->video_dev, | ||
1956 | VFL_TYPE_GRABBER, -1); | ||
1957 | |||
1958 | if (ret) { | ||
1959 | v4l2_err(pdev->dev.driver, | ||
1960 | "Unable to register video device.\n"); | ||
1961 | goto probe_out_v4l2_unregister; | ||
1962 | } | ||
1963 | |||
1964 | v4l2_info(&vpfe_dev->v4l2_dev, "video device registered\n"); | ||
1965 | /* set the driver data in platform device */ | ||
1966 | platform_set_drvdata(pdev, vpfe_dev); | ||
1967 | /* set driver private data */ | ||
1968 | video_set_drvdata(vpfe_dev->video_dev, vpfe_dev); | ||
1969 | i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); | ||
1970 | num_subdevs = vpfe_cfg->num_subdevs; | ||
1971 | vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, | ||
1972 | GFP_KERNEL); | ||
1973 | if (NULL == vpfe_dev->sd) { | ||
1974 | v4l2_err(&vpfe_dev->v4l2_dev, | ||
1975 | "unable to allocate memory for subdevice pointers\n"); | ||
1976 | ret = -ENOMEM; | ||
1977 | goto probe_out_video_unregister; | ||
1978 | } | ||
1979 | |||
1980 | for (i = 0; i < num_subdevs; i++) { | ||
1981 | struct v4l2_input *inps; | ||
1982 | |||
1983 | sdinfo = &vpfe_cfg->sub_devs[i]; | ||
1984 | |||
1985 | /* Load up the subdevice */ | ||
1986 | vpfe_dev->sd[i] = | ||
1987 | v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, | ||
1988 | i2c_adap, | ||
1989 | &sdinfo->board_info, | ||
1990 | NULL); | ||
1991 | if (vpfe_dev->sd[i]) { | ||
1992 | v4l2_info(&vpfe_dev->v4l2_dev, | ||
1993 | "v4l2 sub device %s registered\n", | ||
1994 | sdinfo->name); | ||
1995 | vpfe_dev->sd[i]->grp_id = sdinfo->grp_id; | ||
1996 | /* update tvnorms from the sub devices */ | ||
1997 | for (j = 0; j < sdinfo->num_inputs; j++) { | ||
1998 | inps = &sdinfo->inputs[j]; | ||
1999 | vfd->tvnorms |= inps->std; | ||
2000 | } | ||
2001 | } else { | ||
2002 | v4l2_info(&vpfe_dev->v4l2_dev, | ||
2003 | "v4l2 sub device %s register fails\n", | ||
2004 | sdinfo->name); | ||
2005 | goto probe_sd_out; | ||
2006 | } | ||
2007 | } | ||
2008 | |||
2009 | /* set first sub device as current one */ | ||
2010 | vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; | ||
2011 | |||
2012 | /* We have at least one sub device to work with */ | ||
2013 | mutex_unlock(&ccdc_lock); | ||
2014 | return 0; | ||
2015 | |||
2016 | probe_sd_out: | ||
2017 | kfree(vpfe_dev->sd); | ||
2018 | probe_out_video_unregister: | ||
2019 | video_unregister_device(vpfe_dev->video_dev); | ||
2020 | probe_out_v4l2_unregister: | ||
2021 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); | ||
2022 | probe_out_video_release: | ||
2023 | if (!video_is_registered(vpfe_dev->video_dev)) | ||
2024 | video_device_release(vpfe_dev->video_dev); | ||
2025 | probe_out_release_irq: | ||
2026 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); | ||
2027 | probe_free_ccdc_cfg_mem: | ||
2028 | kfree(ccdc_cfg); | ||
2029 | probe_free_lock: | ||
2030 | mutex_unlock(&ccdc_lock); | ||
2031 | probe_free_dev_mem: | ||
2032 | kfree(vpfe_dev); | ||
2033 | return ret; | ||
2034 | } | ||
2035 | |||
2036 | /* | ||
2037 | * vpfe_remove : It un-register device from V4L2 driver | ||
2038 | */ | ||
2039 | static int __devexit vpfe_remove(struct platform_device *pdev) | ||
2040 | { | ||
2041 | struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); | ||
2042 | |||
2043 | v4l2_info(pdev->dev.driver, "vpfe_remove\n"); | ||
2044 | |||
2045 | free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); | ||
2046 | kfree(vpfe_dev->sd); | ||
2047 | v4l2_device_unregister(&vpfe_dev->v4l2_dev); | ||
2048 | video_unregister_device(vpfe_dev->video_dev); | ||
2049 | kfree(vpfe_dev); | ||
2050 | kfree(ccdc_cfg); | ||
2051 | return 0; | ||
2052 | } | ||
2053 | |||
2054 | static int vpfe_suspend(struct device *dev) | ||
2055 | { | ||
2056 | return 0; | ||
2057 | } | ||
2058 | |||
2059 | static int vpfe_resume(struct device *dev) | ||
2060 | { | ||
2061 | return 0; | ||
2062 | } | ||
2063 | |||
2064 | static const struct dev_pm_ops vpfe_dev_pm_ops = { | ||
2065 | .suspend = vpfe_suspend, | ||
2066 | .resume = vpfe_resume, | ||
2067 | }; | ||
2068 | |||
2069 | static struct platform_driver vpfe_driver = { | ||
2070 | .driver = { | ||
2071 | .name = CAPTURE_DRV_NAME, | ||
2072 | .owner = THIS_MODULE, | ||
2073 | .pm = &vpfe_dev_pm_ops, | ||
2074 | }, | ||
2075 | .probe = vpfe_probe, | ||
2076 | .remove = __devexit_p(vpfe_remove), | ||
2077 | }; | ||
2078 | |||
2079 | static __init int vpfe_init(void) | ||
2080 | { | ||
2081 | printk(KERN_NOTICE "vpfe_init\n"); | ||
2082 | /* Register driver to the kernel */ | ||
2083 | return platform_driver_register(&vpfe_driver); | ||
2084 | } | ||
2085 | |||
2086 | /* | ||
2087 | * vpfe_cleanup : This function un-registers device driver | ||
2088 | */ | ||
2089 | static void vpfe_cleanup(void) | ||
2090 | { | ||
2091 | platform_driver_unregister(&vpfe_driver); | ||
2092 | } | ||
2093 | |||
2094 | module_init(vpfe_init); | ||
2095 | module_exit(vpfe_cleanup); | ||
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c new file mode 100644 index 00000000000..af9680273ff --- /dev/null +++ b/drivers/media/video/davinci/vpif.c | |||
@@ -0,0 +1,473 @@ | |||
1 | /* | ||
2 | * vpif - DM646x Video Port Interface driver | ||
3 | * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) | ||
4 | * that receiveing video byte stream and two channels(2, 3) for video output. | ||
5 | * The hardware supports SDTV, HDTV formats, raw data capture. | ||
6 | * Currently, the driver supports NTSC and PAL standards. | ||
7 | * | ||
8 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation version 2. | ||
13 | * | ||
14 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
15 | * kind, whether express or implied; without even the implied warranty | ||
16 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <mach/hardware.h> | ||
27 | |||
28 | #include "vpif.h" | ||
29 | |||
30 | MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver"); | ||
31 | MODULE_LICENSE("GPL"); | ||
32 | |||
33 | #define VPIF_CH0_MAX_MODES (22) | ||
34 | #define VPIF_CH1_MAX_MODES (02) | ||
35 | #define VPIF_CH2_MAX_MODES (15) | ||
36 | #define VPIF_CH3_MAX_MODES (02) | ||
37 | |||
38 | static resource_size_t res_len; | ||
39 | static struct resource *res; | ||
40 | spinlock_t vpif_lock; | ||
41 | |||
42 | void __iomem *vpif_base; | ||
43 | |||
44 | /** | ||
45 | * ch_params: video standard configuration parameters for vpif | ||
46 | * The table must include all presets from supported subdevices. | ||
47 | */ | ||
48 | const struct vpif_channel_config_params ch_params[] = { | ||
49 | /* HDTV formats */ | ||
50 | { | ||
51 | .name = "480p59_94", | ||
52 | .width = 720, | ||
53 | .height = 480, | ||
54 | .frm_fmt = 1, | ||
55 | .ycmux_mode = 0, | ||
56 | .eav2sav = 138-8, | ||
57 | .sav2eav = 720, | ||
58 | .l1 = 1, | ||
59 | .l3 = 43, | ||
60 | .l5 = 523, | ||
61 | .vsize = 525, | ||
62 | .capture_format = 0, | ||
63 | .vbi_supported = 0, | ||
64 | .hd_sd = 1, | ||
65 | .dv_preset = V4L2_DV_480P59_94, | ||
66 | }, | ||
67 | { | ||
68 | .name = "576p50", | ||
69 | .width = 720, | ||
70 | .height = 576, | ||
71 | .frm_fmt = 1, | ||
72 | .ycmux_mode = 0, | ||
73 | .eav2sav = 144-8, | ||
74 | .sav2eav = 720, | ||
75 | .l1 = 1, | ||
76 | .l3 = 45, | ||
77 | .l5 = 621, | ||
78 | .vsize = 625, | ||
79 | .capture_format = 0, | ||
80 | .vbi_supported = 0, | ||
81 | .hd_sd = 1, | ||
82 | .dv_preset = V4L2_DV_576P50, | ||
83 | }, | ||
84 | { | ||
85 | .name = "720p50", | ||
86 | .width = 1280, | ||
87 | .height = 720, | ||
88 | .frm_fmt = 1, | ||
89 | .ycmux_mode = 0, | ||
90 | .eav2sav = 700-8, | ||
91 | .sav2eav = 1280, | ||
92 | .l1 = 1, | ||
93 | .l3 = 26, | ||
94 | .l5 = 746, | ||
95 | .vsize = 750, | ||
96 | .capture_format = 0, | ||
97 | .vbi_supported = 0, | ||
98 | .hd_sd = 1, | ||
99 | .dv_preset = V4L2_DV_720P50, | ||
100 | }, | ||
101 | { | ||
102 | .name = "720p60", | ||
103 | .width = 1280, | ||
104 | .height = 720, | ||
105 | .frm_fmt = 1, | ||
106 | .ycmux_mode = 0, | ||
107 | .eav2sav = 370 - 8, | ||
108 | .sav2eav = 1280, | ||
109 | .l1 = 1, | ||
110 | .l3 = 26, | ||
111 | .l5 = 746, | ||
112 | .vsize = 750, | ||
113 | .capture_format = 0, | ||
114 | .vbi_supported = 0, | ||
115 | .hd_sd = 1, | ||
116 | .dv_preset = V4L2_DV_720P60, | ||
117 | }, | ||
118 | { | ||
119 | .name = "1080I50", | ||
120 | .width = 1920, | ||
121 | .height = 1080, | ||
122 | .frm_fmt = 0, | ||
123 | .ycmux_mode = 0, | ||
124 | .eav2sav = 720 - 8, | ||
125 | .sav2eav = 1920, | ||
126 | .l1 = 1, | ||
127 | .l3 = 21, | ||
128 | .l5 = 561, | ||
129 | .l7 = 563, | ||
130 | .l9 = 584, | ||
131 | .l11 = 1124, | ||
132 | .vsize = 1125, | ||
133 | .capture_format = 0, | ||
134 | .vbi_supported = 0, | ||
135 | .hd_sd = 1, | ||
136 | .dv_preset = V4L2_DV_1080I50, | ||
137 | }, | ||
138 | { | ||
139 | .name = "1080I60", | ||
140 | .width = 1920, | ||
141 | .height = 1080, | ||
142 | .frm_fmt = 0, | ||
143 | .ycmux_mode = 0, | ||
144 | .eav2sav = 280 - 8, | ||
145 | .sav2eav = 1920, | ||
146 | .l1 = 1, | ||
147 | .l3 = 21, | ||
148 | .l5 = 561, | ||
149 | .l7 = 563, | ||
150 | .l9 = 584, | ||
151 | .l11 = 1124, | ||
152 | .vsize = 1125, | ||
153 | .capture_format = 0, | ||
154 | .vbi_supported = 0, | ||
155 | .hd_sd = 1, | ||
156 | .dv_preset = V4L2_DV_1080I60, | ||
157 | }, | ||
158 | { | ||
159 | .name = "1080p60", | ||
160 | .width = 1920, | ||
161 | .height = 1080, | ||
162 | .frm_fmt = 1, | ||
163 | .ycmux_mode = 0, | ||
164 | .eav2sav = 280 - 8, | ||
165 | .sav2eav = 1920, | ||
166 | .l1 = 1, | ||
167 | .l3 = 42, | ||
168 | .l5 = 1122, | ||
169 | .vsize = 1125, | ||
170 | .capture_format = 0, | ||
171 | .vbi_supported = 0, | ||
172 | .hd_sd = 1, | ||
173 | .dv_preset = V4L2_DV_1080P60, | ||
174 | }, | ||
175 | |||
176 | /* SDTV formats */ | ||
177 | { | ||
178 | .name = "NTSC_M", | ||
179 | .width = 720, | ||
180 | .height = 480, | ||
181 | .frm_fmt = 0, | ||
182 | .ycmux_mode = 1, | ||
183 | .eav2sav = 268, | ||
184 | .sav2eav = 1440, | ||
185 | .l1 = 1, | ||
186 | .l3 = 23, | ||
187 | .l5 = 263, | ||
188 | .l7 = 266, | ||
189 | .l9 = 286, | ||
190 | .l11 = 525, | ||
191 | .vsize = 525, | ||
192 | .capture_format = 0, | ||
193 | .vbi_supported = 1, | ||
194 | .hd_sd = 0, | ||
195 | .stdid = V4L2_STD_525_60, | ||
196 | }, | ||
197 | { | ||
198 | .name = "PAL_BDGHIK", | ||
199 | .width = 720, | ||
200 | .height = 576, | ||
201 | .frm_fmt = 0, | ||
202 | .ycmux_mode = 1, | ||
203 | .eav2sav = 280, | ||
204 | .sav2eav = 1440, | ||
205 | .l1 = 1, | ||
206 | .l3 = 23, | ||
207 | .l5 = 311, | ||
208 | .l7 = 313, | ||
209 | .l9 = 336, | ||
210 | .l11 = 624, | ||
211 | .vsize = 625, | ||
212 | .capture_format = 0, | ||
213 | .vbi_supported = 1, | ||
214 | .hd_sd = 0, | ||
215 | .stdid = V4L2_STD_625_50, | ||
216 | }, | ||
217 | }; | ||
218 | |||
219 | const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params); | ||
220 | |||
221 | static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) | ||
222 | { | ||
223 | if (val) | ||
224 | vpif_set_bit(reg, bit); | ||
225 | else | ||
226 | vpif_clr_bit(reg, bit); | ||
227 | } | ||
228 | |||
229 | /* This structure is used to keep track of VPIF size register's offsets */ | ||
230 | struct vpif_registers { | ||
231 | u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl; | ||
232 | u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt; | ||
233 | u32 vanc1_size, width_mask, len_mask; | ||
234 | u8 max_modes; | ||
235 | }; | ||
236 | |||
237 | static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = { | ||
238 | /* Channel0 */ | ||
239 | { | ||
240 | VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01, | ||
241 | VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL, | ||
242 | VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, | ||
243 | VPIF_CH0_MAX_MODES, | ||
244 | }, | ||
245 | /* Channel1 */ | ||
246 | { | ||
247 | VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01, | ||
248 | VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL, | ||
249 | VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF, | ||
250 | VPIF_CH1_MAX_MODES, | ||
251 | }, | ||
252 | /* Channel2 */ | ||
253 | { | ||
254 | VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01, | ||
255 | VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL, | ||
256 | VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE, | ||
257 | VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF, | ||
258 | VPIF_CH2_MAX_MODES | ||
259 | }, | ||
260 | /* Channel3 */ | ||
261 | { | ||
262 | VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01, | ||
263 | VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL, | ||
264 | VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE, | ||
265 | VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF, | ||
266 | VPIF_CH3_MAX_MODES | ||
267 | }, | ||
268 | }; | ||
269 | |||
270 | /* vpif_set_mode_info: | ||
271 | * This function is used to set horizontal and vertical config parameters | ||
272 | * As per the standard in the channel, configure the values of L1, L3, | ||
273 | * L5, L7 L9, L11 in VPIF Register , also write width and height | ||
274 | */ | ||
275 | static void vpif_set_mode_info(const struct vpif_channel_config_params *config, | ||
276 | u8 channel_id, u8 config_channel_id) | ||
277 | { | ||
278 | u32 value; | ||
279 | |||
280 | value = (config->eav2sav & vpifregs[config_channel_id].width_mask); | ||
281 | value <<= VPIF_CH_LEN_SHIFT; | ||
282 | value |= (config->sav2eav & vpifregs[config_channel_id].width_mask); | ||
283 | regw(value, vpifregs[channel_id].h_cfg); | ||
284 | |||
285 | value = (config->l1 & vpifregs[config_channel_id].len_mask); | ||
286 | value <<= VPIF_CH_LEN_SHIFT; | ||
287 | value |= (config->l3 & vpifregs[config_channel_id].len_mask); | ||
288 | regw(value, vpifregs[channel_id].v_cfg_00); | ||
289 | |||
290 | value = (config->l5 & vpifregs[config_channel_id].len_mask); | ||
291 | value <<= VPIF_CH_LEN_SHIFT; | ||
292 | value |= (config->l7 & vpifregs[config_channel_id].len_mask); | ||
293 | regw(value, vpifregs[channel_id].v_cfg_01); | ||
294 | |||
295 | value = (config->l9 & vpifregs[config_channel_id].len_mask); | ||
296 | value <<= VPIF_CH_LEN_SHIFT; | ||
297 | value |= (config->l11 & vpifregs[config_channel_id].len_mask); | ||
298 | regw(value, vpifregs[channel_id].v_cfg_02); | ||
299 | |||
300 | value = (config->vsize & vpifregs[config_channel_id].len_mask); | ||
301 | regw(value, vpifregs[channel_id].v_cfg); | ||
302 | } | ||
303 | |||
304 | /* config_vpif_params | ||
305 | * Function to set the parameters of a channel | ||
306 | * Mainly modifies the channel ciontrol register | ||
307 | * It sets frame format, yc mux mode | ||
308 | */ | ||
309 | static void config_vpif_params(struct vpif_params *vpifparams, | ||
310 | u8 channel_id, u8 found) | ||
311 | { | ||
312 | const struct vpif_channel_config_params *config = &vpifparams->std_info; | ||
313 | u32 value, ch_nip, reg; | ||
314 | u8 start, end; | ||
315 | int i; | ||
316 | |||
317 | start = channel_id; | ||
318 | end = channel_id + found; | ||
319 | |||
320 | for (i = start; i < end; i++) { | ||
321 | reg = vpifregs[i].ch_ctrl; | ||
322 | if (channel_id < 2) | ||
323 | ch_nip = VPIF_CAPTURE_CH_NIP; | ||
324 | else | ||
325 | ch_nip = VPIF_DISPLAY_CH_NIP; | ||
326 | |||
327 | vpif_wr_bit(reg, ch_nip, config->frm_fmt); | ||
328 | vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode); | ||
329 | vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT, | ||
330 | vpifparams->video_params.storage_mode); | ||
331 | |||
332 | /* Set raster scanning SDR Format */ | ||
333 | vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT); | ||
334 | vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format); | ||
335 | |||
336 | if (channel_id > 1) /* Set the Pixel enable bit */ | ||
337 | vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT); | ||
338 | else if (config->capture_format) { | ||
339 | /* Set the polarity of various pins */ | ||
340 | vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT, | ||
341 | vpifparams->iface.fid_pol); | ||
342 | vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT, | ||
343 | vpifparams->iface.vd_pol); | ||
344 | vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT, | ||
345 | vpifparams->iface.hd_pol); | ||
346 | |||
347 | value = regr(reg); | ||
348 | /* Set data width */ | ||
349 | value &= ((~(unsigned int)(0x3)) << | ||
350 | VPIF_CH_DATA_WIDTH_BIT); | ||
351 | value |= ((vpifparams->params.data_sz) << | ||
352 | VPIF_CH_DATA_WIDTH_BIT); | ||
353 | regw(value, reg); | ||
354 | } | ||
355 | |||
356 | /* Write the pitch in the driver */ | ||
357 | regw((vpifparams->video_params.hpitch), | ||
358 | vpifregs[i].line_offset); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | /* vpif_set_video_params | ||
363 | * This function is used to set video parameters in VPIF register | ||
364 | */ | ||
365 | int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id) | ||
366 | { | ||
367 | const struct vpif_channel_config_params *config = &vpifparams->std_info; | ||
368 | int found = 1; | ||
369 | |||
370 | vpif_set_mode_info(config, channel_id, channel_id); | ||
371 | if (!config->ycmux_mode) { | ||
372 | /* YC are on separate channels (HDTV formats) */ | ||
373 | vpif_set_mode_info(config, channel_id + 1, channel_id); | ||
374 | found = 2; | ||
375 | } | ||
376 | |||
377 | config_vpif_params(vpifparams, channel_id, found); | ||
378 | |||
379 | regw(0x80, VPIF_REQ_SIZE); | ||
380 | regw(0x01, VPIF_EMULATION_CTRL); | ||
381 | |||
382 | return found; | ||
383 | } | ||
384 | EXPORT_SYMBOL(vpif_set_video_params); | ||
385 | |||
386 | void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, | ||
387 | u8 channel_id) | ||
388 | { | ||
389 | u32 value; | ||
390 | |||
391 | value = 0x3F8 & (vbiparams->hstart0); | ||
392 | value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16); | ||
393 | regw(value, vpifregs[channel_id].vanc0_strt); | ||
394 | |||
395 | value = 0x3F8 & (vbiparams->hstart1); | ||
396 | value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16); | ||
397 | regw(value, vpifregs[channel_id].vanc1_strt); | ||
398 | |||
399 | value = 0x3F8 & (vbiparams->hsize0); | ||
400 | value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16); | ||
401 | regw(value, vpifregs[channel_id].vanc0_size); | ||
402 | |||
403 | value = 0x3F8 & (vbiparams->hsize1); | ||
404 | value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16); | ||
405 | regw(value, vpifregs[channel_id].vanc1_size); | ||
406 | |||
407 | } | ||
408 | EXPORT_SYMBOL(vpif_set_vbi_display_params); | ||
409 | |||
410 | int vpif_channel_getfid(u8 channel_id) | ||
411 | { | ||
412 | return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK) | ||
413 | >> VPIF_CH_FID_SHIFT; | ||
414 | } | ||
415 | EXPORT_SYMBOL(vpif_channel_getfid); | ||
416 | |||
417 | static int __init vpif_probe(struct platform_device *pdev) | ||
418 | { | ||
419 | int status = 0; | ||
420 | |||
421 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
422 | if (!res) | ||
423 | return -ENOENT; | ||
424 | |||
425 | res_len = resource_size(res); | ||
426 | |||
427 | res = request_mem_region(res->start, res_len, res->name); | ||
428 | if (!res) | ||
429 | return -EBUSY; | ||
430 | |||
431 | vpif_base = ioremap(res->start, res_len); | ||
432 | if (!vpif_base) { | ||
433 | status = -EBUSY; | ||
434 | goto fail; | ||
435 | } | ||
436 | |||
437 | spin_lock_init(&vpif_lock); | ||
438 | dev_info(&pdev->dev, "vpif probe success\n"); | ||
439 | return 0; | ||
440 | |||
441 | fail: | ||
442 | release_mem_region(res->start, res_len); | ||
443 | return status; | ||
444 | } | ||
445 | |||
446 | static int __devexit vpif_remove(struct platform_device *pdev) | ||
447 | { | ||
448 | iounmap(vpif_base); | ||
449 | release_mem_region(res->start, res_len); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static struct platform_driver vpif_driver = { | ||
454 | .driver = { | ||
455 | .name = "vpif", | ||
456 | .owner = THIS_MODULE, | ||
457 | }, | ||
458 | .remove = __devexit_p(vpif_remove), | ||
459 | .probe = vpif_probe, | ||
460 | }; | ||
461 | |||
462 | static void vpif_exit(void) | ||
463 | { | ||
464 | platform_driver_unregister(&vpif_driver); | ||
465 | } | ||
466 | |||
467 | static int __init vpif_init(void) | ||
468 | { | ||
469 | return platform_driver_register(&vpif_driver); | ||
470 | } | ||
471 | subsys_initcall(vpif_init); | ||
472 | module_exit(vpif_exit); | ||
473 | |||
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h new file mode 100644 index 00000000000..10550bd93b0 --- /dev/null +++ b/drivers/media/video/davinci/vpif.h | |||
@@ -0,0 +1,644 @@ | |||
1 | /* | ||
2 | * VPIF header file | ||
3 | * | ||
4 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef VPIF_H | ||
17 | #define VPIF_H | ||
18 | |||
19 | #include <linux/io.h> | ||
20 | #include <linux/videodev2.h> | ||
21 | #include <mach/hardware.h> | ||
22 | #include <mach/dm646x.h> | ||
23 | |||
24 | /* Maximum channel allowed */ | ||
25 | #define VPIF_NUM_CHANNELS (4) | ||
26 | #define VPIF_CAPTURE_NUM_CHANNELS (2) | ||
27 | #define VPIF_DISPLAY_NUM_CHANNELS (2) | ||
28 | |||
29 | /* Macros to read/write registers */ | ||
30 | extern void __iomem *vpif_base; | ||
31 | extern spinlock_t vpif_lock; | ||
32 | |||
33 | #define regr(reg) readl((reg) + vpif_base) | ||
34 | #define regw(value, reg) writel(value, (reg + vpif_base)) | ||
35 | |||
36 | /* Register Address Offsets */ | ||
37 | #define VPIF_PID (0x0000) | ||
38 | #define VPIF_CH0_CTRL (0x0004) | ||
39 | #define VPIF_CH1_CTRL (0x0008) | ||
40 | #define VPIF_CH2_CTRL (0x000C) | ||
41 | #define VPIF_CH3_CTRL (0x0010) | ||
42 | |||
43 | #define VPIF_INTEN (0x0020) | ||
44 | #define VPIF_INTEN_SET (0x0024) | ||
45 | #define VPIF_INTEN_CLR (0x0028) | ||
46 | #define VPIF_STATUS (0x002C) | ||
47 | #define VPIF_STATUS_CLR (0x0030) | ||
48 | #define VPIF_EMULATION_CTRL (0x0034) | ||
49 | #define VPIF_REQ_SIZE (0x0038) | ||
50 | |||
51 | #define VPIF_CH0_TOP_STRT_ADD_LUMA (0x0040) | ||
52 | #define VPIF_CH0_BTM_STRT_ADD_LUMA (0x0044) | ||
53 | #define VPIF_CH0_TOP_STRT_ADD_CHROMA (0x0048) | ||
54 | #define VPIF_CH0_BTM_STRT_ADD_CHROMA (0x004c) | ||
55 | #define VPIF_CH0_TOP_STRT_ADD_HANC (0x0050) | ||
56 | #define VPIF_CH0_BTM_STRT_ADD_HANC (0x0054) | ||
57 | #define VPIF_CH0_TOP_STRT_ADD_VANC (0x0058) | ||
58 | #define VPIF_CH0_BTM_STRT_ADD_VANC (0x005c) | ||
59 | #define VPIF_CH0_SP_CFG (0x0060) | ||
60 | #define VPIF_CH0_IMG_ADD_OFST (0x0064) | ||
61 | #define VPIF_CH0_HANC_ADD_OFST (0x0068) | ||
62 | #define VPIF_CH0_H_CFG (0x006c) | ||
63 | #define VPIF_CH0_V_CFG_00 (0x0070) | ||
64 | #define VPIF_CH0_V_CFG_01 (0x0074) | ||
65 | #define VPIF_CH0_V_CFG_02 (0x0078) | ||
66 | #define VPIF_CH0_V_CFG_03 (0x007c) | ||
67 | |||
68 | #define VPIF_CH1_TOP_STRT_ADD_LUMA (0x0080) | ||
69 | #define VPIF_CH1_BTM_STRT_ADD_LUMA (0x0084) | ||
70 | #define VPIF_CH1_TOP_STRT_ADD_CHROMA (0x0088) | ||
71 | #define VPIF_CH1_BTM_STRT_ADD_CHROMA (0x008c) | ||
72 | #define VPIF_CH1_TOP_STRT_ADD_HANC (0x0090) | ||
73 | #define VPIF_CH1_BTM_STRT_ADD_HANC (0x0094) | ||
74 | #define VPIF_CH1_TOP_STRT_ADD_VANC (0x0098) | ||
75 | #define VPIF_CH1_BTM_STRT_ADD_VANC (0x009c) | ||
76 | #define VPIF_CH1_SP_CFG (0x00a0) | ||
77 | #define VPIF_CH1_IMG_ADD_OFST (0x00a4) | ||
78 | #define VPIF_CH1_HANC_ADD_OFST (0x00a8) | ||
79 | #define VPIF_CH1_H_CFG (0x00ac) | ||
80 | #define VPIF_CH1_V_CFG_00 (0x00b0) | ||
81 | #define VPIF_CH1_V_CFG_01 (0x00b4) | ||
82 | #define VPIF_CH1_V_CFG_02 (0x00b8) | ||
83 | #define VPIF_CH1_V_CFG_03 (0x00bc) | ||
84 | |||
85 | #define VPIF_CH2_TOP_STRT_ADD_LUMA (0x00c0) | ||
86 | #define VPIF_CH2_BTM_STRT_ADD_LUMA (0x00c4) | ||
87 | #define VPIF_CH2_TOP_STRT_ADD_CHROMA (0x00c8) | ||
88 | #define VPIF_CH2_BTM_STRT_ADD_CHROMA (0x00cc) | ||
89 | #define VPIF_CH2_TOP_STRT_ADD_HANC (0x00d0) | ||
90 | #define VPIF_CH2_BTM_STRT_ADD_HANC (0x00d4) | ||
91 | #define VPIF_CH2_TOP_STRT_ADD_VANC (0x00d8) | ||
92 | #define VPIF_CH2_BTM_STRT_ADD_VANC (0x00dc) | ||
93 | #define VPIF_CH2_SP_CFG (0x00e0) | ||
94 | #define VPIF_CH2_IMG_ADD_OFST (0x00e4) | ||
95 | #define VPIF_CH2_HANC_ADD_OFST (0x00e8) | ||
96 | #define VPIF_CH2_H_CFG (0x00ec) | ||
97 | #define VPIF_CH2_V_CFG_00 (0x00f0) | ||
98 | #define VPIF_CH2_V_CFG_01 (0x00f4) | ||
99 | #define VPIF_CH2_V_CFG_02 (0x00f8) | ||
100 | #define VPIF_CH2_V_CFG_03 (0x00fc) | ||
101 | #define VPIF_CH2_HANC0_STRT (0x0100) | ||
102 | #define VPIF_CH2_HANC0_SIZE (0x0104) | ||
103 | #define VPIF_CH2_HANC1_STRT (0x0108) | ||
104 | #define VPIF_CH2_HANC1_SIZE (0x010c) | ||
105 | #define VPIF_CH2_VANC0_STRT (0x0110) | ||
106 | #define VPIF_CH2_VANC0_SIZE (0x0114) | ||
107 | #define VPIF_CH2_VANC1_STRT (0x0118) | ||
108 | #define VPIF_CH2_VANC1_SIZE (0x011c) | ||
109 | |||
110 | #define VPIF_CH3_TOP_STRT_ADD_LUMA (0x0140) | ||
111 | #define VPIF_CH3_BTM_STRT_ADD_LUMA (0x0144) | ||
112 | #define VPIF_CH3_TOP_STRT_ADD_CHROMA (0x0148) | ||
113 | #define VPIF_CH3_BTM_STRT_ADD_CHROMA (0x014c) | ||
114 | #define VPIF_CH3_TOP_STRT_ADD_HANC (0x0150) | ||
115 | #define VPIF_CH3_BTM_STRT_ADD_HANC (0x0154) | ||
116 | #define VPIF_CH3_TOP_STRT_ADD_VANC (0x0158) | ||
117 | #define VPIF_CH3_BTM_STRT_ADD_VANC (0x015c) | ||
118 | #define VPIF_CH3_SP_CFG (0x0160) | ||
119 | #define VPIF_CH3_IMG_ADD_OFST (0x0164) | ||
120 | #define VPIF_CH3_HANC_ADD_OFST (0x0168) | ||
121 | #define VPIF_CH3_H_CFG (0x016c) | ||
122 | #define VPIF_CH3_V_CFG_00 (0x0170) | ||
123 | #define VPIF_CH3_V_CFG_01 (0x0174) | ||
124 | #define VPIF_CH3_V_CFG_02 (0x0178) | ||
125 | #define VPIF_CH3_V_CFG_03 (0x017c) | ||
126 | #define VPIF_CH3_HANC0_STRT (0x0180) | ||
127 | #define VPIF_CH3_HANC0_SIZE (0x0184) | ||
128 | #define VPIF_CH3_HANC1_STRT (0x0188) | ||
129 | #define VPIF_CH3_HANC1_SIZE (0x018c) | ||
130 | #define VPIF_CH3_VANC0_STRT (0x0190) | ||
131 | #define VPIF_CH3_VANC0_SIZE (0x0194) | ||
132 | #define VPIF_CH3_VANC1_STRT (0x0198) | ||
133 | #define VPIF_CH3_VANC1_SIZE (0x019c) | ||
134 | |||
135 | #define VPIF_IODFT_CTRL (0x01c0) | ||
136 | |||
137 | /* Functions for bit Manipulation */ | ||
138 | static inline void vpif_set_bit(u32 reg, u32 bit) | ||
139 | { | ||
140 | regw((regr(reg)) | (0x01 << bit), reg); | ||
141 | } | ||
142 | |||
143 | static inline void vpif_clr_bit(u32 reg, u32 bit) | ||
144 | { | ||
145 | regw(((regr(reg)) & ~(0x01 << bit)), reg); | ||
146 | } | ||
147 | |||
148 | /* Macro for Generating mask */ | ||
149 | #ifdef GENERATE_MASK | ||
150 | #undef GENERATE_MASK | ||
151 | #endif | ||
152 | |||
153 | #define GENERATE_MASK(bits, pos) \ | ||
154 | ((((0xFFFFFFFF) << (32 - bits)) >> (32 - bits)) << pos) | ||
155 | |||
156 | /* Bit positions in the channel control registers */ | ||
157 | #define VPIF_CH_DATA_MODE_BIT (2) | ||
158 | #define VPIF_CH_YC_MUX_BIT (3) | ||
159 | #define VPIF_CH_SDR_FMT_BIT (4) | ||
160 | #define VPIF_CH_HANC_EN_BIT (8) | ||
161 | #define VPIF_CH_VANC_EN_BIT (9) | ||
162 | |||
163 | #define VPIF_CAPTURE_CH_NIP (10) | ||
164 | #define VPIF_DISPLAY_CH_NIP (11) | ||
165 | |||
166 | #define VPIF_DISPLAY_PIX_EN_BIT (10) | ||
167 | |||
168 | #define VPIF_CH_INPUT_FIELD_FRAME_BIT (12) | ||
169 | |||
170 | #define VPIF_CH_FID_POLARITY_BIT (15) | ||
171 | #define VPIF_CH_V_VALID_POLARITY_BIT (14) | ||
172 | #define VPIF_CH_H_VALID_POLARITY_BIT (13) | ||
173 | #define VPIF_CH_DATA_WIDTH_BIT (28) | ||
174 | |||
175 | #define VPIF_CH_CLK_EDGE_CTRL_BIT (31) | ||
176 | |||
177 | /* Mask various length */ | ||
178 | #define VPIF_CH_EAVSAV_MASK GENERATE_MASK(13, 0) | ||
179 | #define VPIF_CH_LEN_MASK GENERATE_MASK(12, 0) | ||
180 | #define VPIF_CH_WIDTH_MASK GENERATE_MASK(13, 0) | ||
181 | #define VPIF_CH_LEN_SHIFT (16) | ||
182 | |||
183 | /* VPIF masks for registers */ | ||
184 | #define VPIF_REQ_SIZE_MASK (0x1ff) | ||
185 | |||
186 | /* bit posotion of interrupt vpif_ch_intr register */ | ||
187 | #define VPIF_INTEN_FRAME_CH0 (0x00000001) | ||
188 | #define VPIF_INTEN_FRAME_CH1 (0x00000002) | ||
189 | #define VPIF_INTEN_FRAME_CH2 (0x00000004) | ||
190 | #define VPIF_INTEN_FRAME_CH3 (0x00000008) | ||
191 | |||
192 | /* bit position of clock and channel enable in vpif_chn_ctrl register */ | ||
193 | |||
194 | #define VPIF_CH0_CLK_EN (0x00000002) | ||
195 | #define VPIF_CH0_EN (0x00000001) | ||
196 | #define VPIF_CH1_CLK_EN (0x00000002) | ||
197 | #define VPIF_CH1_EN (0x00000001) | ||
198 | #define VPIF_CH2_CLK_EN (0x00000002) | ||
199 | #define VPIF_CH2_EN (0x00000001) | ||
200 | #define VPIF_CH3_CLK_EN (0x00000002) | ||
201 | #define VPIF_CH3_EN (0x00000001) | ||
202 | #define VPIF_CH_CLK_EN (0x00000002) | ||
203 | #define VPIF_CH_EN (0x00000001) | ||
204 | |||
205 | #define VPIF_INT_TOP (0x00) | ||
206 | #define VPIF_INT_BOTTOM (0x01) | ||
207 | #define VPIF_INT_BOTH (0x02) | ||
208 | |||
209 | #define VPIF_CH0_INT_CTRL_SHIFT (6) | ||
210 | #define VPIF_CH1_INT_CTRL_SHIFT (6) | ||
211 | #define VPIF_CH2_INT_CTRL_SHIFT (6) | ||
212 | #define VPIF_CH3_INT_CTRL_SHIFT (6) | ||
213 | #define VPIF_CH_INT_CTRL_SHIFT (6) | ||
214 | |||
215 | /* enabled interrupt on both the fields on vpid_ch0_ctrl register */ | ||
216 | #define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ | ||
217 | (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) | ||
218 | |||
219 | /* enabled interrupt on both the fields on vpid_ch1_ctrl register */ | ||
220 | #define channel1_intr_assert() (regw((regr(VPIF_CH1_CTRL)|\ | ||
221 | (VPIF_INT_BOTH << VPIF_CH1_INT_CTRL_SHIFT)), VPIF_CH1_CTRL)) | ||
222 | |||
223 | /* enabled interrupt on both the fields on vpid_ch0_ctrl register */ | ||
224 | #define channel2_intr_assert() (regw((regr(VPIF_CH2_CTRL)|\ | ||
225 | (VPIF_INT_BOTH << VPIF_CH2_INT_CTRL_SHIFT)), VPIF_CH2_CTRL)) | ||
226 | |||
227 | /* enabled interrupt on both the fields on vpid_ch1_ctrl register */ | ||
228 | #define channel3_intr_assert() (regw((regr(VPIF_CH3_CTRL)|\ | ||
229 | (VPIF_INT_BOTH << VPIF_CH3_INT_CTRL_SHIFT)), VPIF_CH3_CTRL)) | ||
230 | |||
231 | #define VPIF_CH_FID_MASK (0x20) | ||
232 | #define VPIF_CH_FID_SHIFT (5) | ||
233 | |||
234 | #define VPIF_NTSC_VBI_START_FIELD0 (1) | ||
235 | #define VPIF_NTSC_VBI_START_FIELD1 (263) | ||
236 | #define VPIF_PAL_VBI_START_FIELD0 (624) | ||
237 | #define VPIF_PAL_VBI_START_FIELD1 (311) | ||
238 | |||
239 | #define VPIF_NTSC_HBI_START_FIELD0 (1) | ||
240 | #define VPIF_NTSC_HBI_START_FIELD1 (263) | ||
241 | #define VPIF_PAL_HBI_START_FIELD0 (624) | ||
242 | #define VPIF_PAL_HBI_START_FIELD1 (311) | ||
243 | |||
244 | #define VPIF_NTSC_VBI_COUNT_FIELD0 (20) | ||
245 | #define VPIF_NTSC_VBI_COUNT_FIELD1 (19) | ||
246 | #define VPIF_PAL_VBI_COUNT_FIELD0 (24) | ||
247 | #define VPIF_PAL_VBI_COUNT_FIELD1 (25) | ||
248 | |||
249 | #define VPIF_NTSC_HBI_COUNT_FIELD0 (263) | ||
250 | #define VPIF_NTSC_HBI_COUNT_FIELD1 (262) | ||
251 | #define VPIF_PAL_HBI_COUNT_FIELD0 (312) | ||
252 | #define VPIF_PAL_HBI_COUNT_FIELD1 (313) | ||
253 | |||
254 | #define VPIF_NTSC_VBI_SAMPLES_PER_LINE (720) | ||
255 | #define VPIF_PAL_VBI_SAMPLES_PER_LINE (720) | ||
256 | #define VPIF_NTSC_HBI_SAMPLES_PER_LINE (268) | ||
257 | #define VPIF_PAL_HBI_SAMPLES_PER_LINE (280) | ||
258 | |||
259 | #define VPIF_CH_VANC_EN (0x20) | ||
260 | #define VPIF_DMA_REQ_SIZE (0x080) | ||
261 | #define VPIF_EMULATION_DISABLE (0x01) | ||
262 | |||
263 | extern u8 irq_vpif_capture_channel[VPIF_NUM_CHANNELS]; | ||
264 | |||
265 | /* inline function to enable/disable channel0 */ | ||
266 | static inline void enable_channel0(int enable) | ||
267 | { | ||
268 | if (enable) | ||
269 | regw((regr(VPIF_CH0_CTRL) | (VPIF_CH0_EN)), VPIF_CH0_CTRL); | ||
270 | else | ||
271 | regw((regr(VPIF_CH0_CTRL) & (~VPIF_CH0_EN)), VPIF_CH0_CTRL); | ||
272 | } | ||
273 | |||
274 | /* inline function to enable/disable channel1 */ | ||
275 | static inline void enable_channel1(int enable) | ||
276 | { | ||
277 | if (enable) | ||
278 | regw((regr(VPIF_CH1_CTRL) | (VPIF_CH1_EN)), VPIF_CH1_CTRL); | ||
279 | else | ||
280 | regw((regr(VPIF_CH1_CTRL) & (~VPIF_CH1_EN)), VPIF_CH1_CTRL); | ||
281 | } | ||
282 | |||
283 | /* inline function to enable interrupt for channel0 */ | ||
284 | static inline void channel0_intr_enable(int enable) | ||
285 | { | ||
286 | unsigned long flags; | ||
287 | |||
288 | spin_lock_irqsave(&vpif_lock, flags); | ||
289 | |||
290 | if (enable) { | ||
291 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
292 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
293 | |||
294 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH0), VPIF_INTEN); | ||
295 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), | ||
296 | VPIF_INTEN_SET); | ||
297 | } else { | ||
298 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH0)), VPIF_INTEN); | ||
299 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH0), | ||
300 | VPIF_INTEN_SET); | ||
301 | } | ||
302 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
303 | } | ||
304 | |||
305 | /* inline function to enable interrupt for channel1 */ | ||
306 | static inline void channel1_intr_enable(int enable) | ||
307 | { | ||
308 | unsigned long flags; | ||
309 | |||
310 | spin_lock_irqsave(&vpif_lock, flags); | ||
311 | |||
312 | if (enable) { | ||
313 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
314 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
315 | |||
316 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH1), VPIF_INTEN); | ||
317 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), | ||
318 | VPIF_INTEN_SET); | ||
319 | } else { | ||
320 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH1)), VPIF_INTEN); | ||
321 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH1), | ||
322 | VPIF_INTEN_SET); | ||
323 | } | ||
324 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
325 | } | ||
326 | |||
327 | /* inline function to set buffer addresses in case of Y/C non mux mode */ | ||
328 | static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, | ||
329 | unsigned long btm_strt_luma, | ||
330 | unsigned long top_strt_chroma, | ||
331 | unsigned long btm_strt_chroma) | ||
332 | { | ||
333 | regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); | ||
334 | regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); | ||
335 | regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); | ||
336 | regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); | ||
337 | } | ||
338 | |||
339 | /* inline function to set buffer addresses in VPIF registers for video data */ | ||
340 | static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, | ||
341 | unsigned long btm_strt_luma, | ||
342 | unsigned long top_strt_chroma, | ||
343 | unsigned long btm_strt_chroma) | ||
344 | { | ||
345 | regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); | ||
346 | regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); | ||
347 | regw(top_strt_chroma, VPIF_CH0_TOP_STRT_ADD_CHROMA); | ||
348 | regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA); | ||
349 | } | ||
350 | |||
351 | static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma, | ||
352 | unsigned long btm_strt_luma, | ||
353 | unsigned long top_strt_chroma, | ||
354 | unsigned long btm_strt_chroma) | ||
355 | { | ||
356 | |||
357 | regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA); | ||
358 | regw(btm_strt_luma, VPIF_CH1_BTM_STRT_ADD_LUMA); | ||
359 | regw(top_strt_chroma, VPIF_CH1_TOP_STRT_ADD_CHROMA); | ||
360 | regw(btm_strt_chroma, VPIF_CH1_BTM_STRT_ADD_CHROMA); | ||
361 | } | ||
362 | |||
363 | static inline void ch0_set_vbi_addr(unsigned long top_vbi, | ||
364 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
365 | { | ||
366 | regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_VANC); | ||
367 | regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_VANC); | ||
368 | } | ||
369 | |||
370 | static inline void ch0_set_hbi_addr(unsigned long top_vbi, | ||
371 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
372 | { | ||
373 | regw(top_vbi, VPIF_CH0_TOP_STRT_ADD_HANC); | ||
374 | regw(btm_vbi, VPIF_CH0_BTM_STRT_ADD_HANC); | ||
375 | } | ||
376 | |||
377 | static inline void ch1_set_vbi_addr(unsigned long top_vbi, | ||
378 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
379 | { | ||
380 | regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_VANC); | ||
381 | regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_VANC); | ||
382 | } | ||
383 | |||
384 | static inline void ch1_set_hbi_addr(unsigned long top_vbi, | ||
385 | unsigned long btm_vbi, unsigned long a, unsigned long b) | ||
386 | { | ||
387 | regw(top_vbi, VPIF_CH1_TOP_STRT_ADD_HANC); | ||
388 | regw(btm_vbi, VPIF_CH1_BTM_STRT_ADD_HANC); | ||
389 | } | ||
390 | |||
391 | /* Inline function to enable raw vbi in the given channel */ | ||
392 | static inline void disable_raw_feature(u8 channel_id, u8 index) | ||
393 | { | ||
394 | u32 ctrl_reg; | ||
395 | if (0 == channel_id) | ||
396 | ctrl_reg = VPIF_CH0_CTRL; | ||
397 | else | ||
398 | ctrl_reg = VPIF_CH1_CTRL; | ||
399 | |||
400 | if (1 == index) | ||
401 | vpif_clr_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); | ||
402 | else | ||
403 | vpif_clr_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); | ||
404 | } | ||
405 | |||
406 | static inline void enable_raw_feature(u8 channel_id, u8 index) | ||
407 | { | ||
408 | u32 ctrl_reg; | ||
409 | if (0 == channel_id) | ||
410 | ctrl_reg = VPIF_CH0_CTRL; | ||
411 | else | ||
412 | ctrl_reg = VPIF_CH1_CTRL; | ||
413 | |||
414 | if (1 == index) | ||
415 | vpif_set_bit(ctrl_reg, VPIF_CH_VANC_EN_BIT); | ||
416 | else | ||
417 | vpif_set_bit(ctrl_reg, VPIF_CH_HANC_EN_BIT); | ||
418 | } | ||
419 | |||
420 | /* inline function to enable/disable channel2 */ | ||
421 | static inline void enable_channel2(int enable) | ||
422 | { | ||
423 | if (enable) { | ||
424 | regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); | ||
425 | regw((regr(VPIF_CH2_CTRL) | (VPIF_CH2_EN)), VPIF_CH2_CTRL); | ||
426 | } else { | ||
427 | regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_CLK_EN)), VPIF_CH2_CTRL); | ||
428 | regw((regr(VPIF_CH2_CTRL) & (~VPIF_CH2_EN)), VPIF_CH2_CTRL); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | /* inline function to enable/disable channel3 */ | ||
433 | static inline void enable_channel3(int enable) | ||
434 | { | ||
435 | if (enable) { | ||
436 | regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); | ||
437 | regw((regr(VPIF_CH3_CTRL) | (VPIF_CH3_EN)), VPIF_CH3_CTRL); | ||
438 | } else { | ||
439 | regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_CLK_EN)), VPIF_CH3_CTRL); | ||
440 | regw((regr(VPIF_CH3_CTRL) & (~VPIF_CH3_EN)), VPIF_CH3_CTRL); | ||
441 | } | ||
442 | } | ||
443 | |||
444 | /* inline function to enable interrupt for channel2 */ | ||
445 | static inline void channel2_intr_enable(int enable) | ||
446 | { | ||
447 | unsigned long flags; | ||
448 | |||
449 | spin_lock_irqsave(&vpif_lock, flags); | ||
450 | |||
451 | if (enable) { | ||
452 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
453 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
454 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH2), VPIF_INTEN); | ||
455 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), | ||
456 | VPIF_INTEN_SET); | ||
457 | } else { | ||
458 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH2)), VPIF_INTEN); | ||
459 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH2), | ||
460 | VPIF_INTEN_SET); | ||
461 | } | ||
462 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
463 | } | ||
464 | |||
465 | /* inline function to enable interrupt for channel3 */ | ||
466 | static inline void channel3_intr_enable(int enable) | ||
467 | { | ||
468 | unsigned long flags; | ||
469 | |||
470 | spin_lock_irqsave(&vpif_lock, flags); | ||
471 | |||
472 | if (enable) { | ||
473 | regw((regr(VPIF_INTEN) | 0x10), VPIF_INTEN); | ||
474 | regw((regr(VPIF_INTEN_SET) | 0x10), VPIF_INTEN_SET); | ||
475 | |||
476 | regw((regr(VPIF_INTEN) | VPIF_INTEN_FRAME_CH3), VPIF_INTEN); | ||
477 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), | ||
478 | VPIF_INTEN_SET); | ||
479 | } else { | ||
480 | regw((regr(VPIF_INTEN) & (~VPIF_INTEN_FRAME_CH3)), VPIF_INTEN); | ||
481 | regw((regr(VPIF_INTEN_SET) | VPIF_INTEN_FRAME_CH3), | ||
482 | VPIF_INTEN_SET); | ||
483 | } | ||
484 | spin_unlock_irqrestore(&vpif_lock, flags); | ||
485 | } | ||
486 | |||
487 | /* inline function to enable raw vbi data for channel2 */ | ||
488 | static inline void channel2_raw_enable(int enable, u8 index) | ||
489 | { | ||
490 | u32 mask; | ||
491 | |||
492 | if (1 == index) | ||
493 | mask = VPIF_CH_VANC_EN_BIT; | ||
494 | else | ||
495 | mask = VPIF_CH_HANC_EN_BIT; | ||
496 | |||
497 | if (enable) | ||
498 | vpif_set_bit(VPIF_CH2_CTRL, mask); | ||
499 | else | ||
500 | vpif_clr_bit(VPIF_CH2_CTRL, mask); | ||
501 | } | ||
502 | |||
503 | /* inline function to enable raw vbi data for channel3*/ | ||
504 | static inline void channel3_raw_enable(int enable, u8 index) | ||
505 | { | ||
506 | u32 mask; | ||
507 | |||
508 | if (1 == index) | ||
509 | mask = VPIF_CH_VANC_EN_BIT; | ||
510 | else | ||
511 | mask = VPIF_CH_HANC_EN_BIT; | ||
512 | |||
513 | if (enable) | ||
514 | vpif_set_bit(VPIF_CH3_CTRL, mask); | ||
515 | else | ||
516 | vpif_clr_bit(VPIF_CH3_CTRL, mask); | ||
517 | } | ||
518 | |||
519 | /* inline function to set buffer addresses in case of Y/C non mux mode */ | ||
520 | static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, | ||
521 | unsigned long btm_strt_luma, | ||
522 | unsigned long top_strt_chroma, | ||
523 | unsigned long btm_strt_chroma) | ||
524 | { | ||
525 | regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); | ||
526 | regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); | ||
527 | regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); | ||
528 | regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); | ||
529 | } | ||
530 | |||
531 | /* inline function to set buffer addresses in VPIF registers for video data */ | ||
532 | static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, | ||
533 | unsigned long btm_strt_luma, | ||
534 | unsigned long top_strt_chroma, | ||
535 | unsigned long btm_strt_chroma) | ||
536 | { | ||
537 | regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); | ||
538 | regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); | ||
539 | regw(top_strt_chroma, VPIF_CH2_TOP_STRT_ADD_CHROMA); | ||
540 | regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA); | ||
541 | } | ||
542 | |||
543 | static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, | ||
544 | unsigned long btm_strt_luma, | ||
545 | unsigned long top_strt_chroma, | ||
546 | unsigned long btm_strt_chroma) | ||
547 | { | ||
548 | regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA); | ||
549 | regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA); | ||
550 | regw(top_strt_chroma, VPIF_CH3_TOP_STRT_ADD_CHROMA); | ||
551 | regw(btm_strt_chroma, VPIF_CH3_BTM_STRT_ADD_CHROMA); | ||
552 | } | ||
553 | |||
554 | /* inline function to set buffer addresses in VPIF registers for vbi data */ | ||
555 | static inline void ch2_set_vbi_addr(unsigned long top_strt_luma, | ||
556 | unsigned long btm_strt_luma, | ||
557 | unsigned long top_strt_chroma, | ||
558 | unsigned long btm_strt_chroma) | ||
559 | { | ||
560 | regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC); | ||
561 | regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC); | ||
562 | } | ||
563 | |||
564 | static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, | ||
565 | unsigned long btm_strt_luma, | ||
566 | unsigned long top_strt_chroma, | ||
567 | unsigned long btm_strt_chroma) | ||
568 | { | ||
569 | regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC); | ||
570 | regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); | ||
571 | } | ||
572 | |||
573 | #define VPIF_MAX_NAME (30) | ||
574 | |||
575 | /* This structure will store size parameters as per the mode selected by user */ | ||
576 | struct vpif_channel_config_params { | ||
577 | char name[VPIF_MAX_NAME]; /* Name of the mode */ | ||
578 | u16 width; /* Indicates width of the image */ | ||
579 | u16 height; /* Indicates height of the image */ | ||
580 | u8 frm_fmt; /* Interlaced (0) or progressive (1) */ | ||
581 | u8 ycmux_mode; /* This mode requires one (0) or two (1) | ||
582 | channels */ | ||
583 | u16 eav2sav; /* length of eav 2 sav */ | ||
584 | u16 sav2eav; /* length of sav 2 eav */ | ||
585 | u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */ | ||
586 | u16 vsize; /* Vertical size of the image */ | ||
587 | u8 capture_format; /* Indicates whether capture format | ||
588 | * is in BT or in CCD/CMOS */ | ||
589 | u8 vbi_supported; /* Indicates whether this mode | ||
590 | * supports capturing vbi or not */ | ||
591 | u8 hd_sd; /* HDTV (1) or SDTV (0) format */ | ||
592 | v4l2_std_id stdid; /* SDTV format */ | ||
593 | u32 dv_preset; /* HDTV format */ | ||
594 | }; | ||
595 | |||
596 | extern const unsigned int vpif_ch_params_count; | ||
597 | extern const struct vpif_channel_config_params ch_params[]; | ||
598 | |||
599 | struct vpif_video_params; | ||
600 | struct vpif_params; | ||
601 | struct vpif_vbi_params; | ||
602 | |||
603 | int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id); | ||
604 | void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams, | ||
605 | u8 channel_id); | ||
606 | int vpif_channel_getfid(u8 channel_id); | ||
607 | |||
608 | enum data_size { | ||
609 | _8BITS = 0, | ||
610 | _10BITS, | ||
611 | _12BITS, | ||
612 | }; | ||
613 | |||
614 | /* Structure for vpif parameters for raw vbi data */ | ||
615 | struct vpif_vbi_params { | ||
616 | __u32 hstart0; /* Horizontal start of raw vbi data for first field */ | ||
617 | __u32 vstart0; /* Vertical start of raw vbi data for first field */ | ||
618 | __u32 hsize0; /* Horizontal size of raw vbi data for first field */ | ||
619 | __u32 vsize0; /* Vertical size of raw vbi data for first field */ | ||
620 | __u32 hstart1; /* Horizontal start of raw vbi data for second field */ | ||
621 | __u32 vstart1; /* Vertical start of raw vbi data for second field */ | ||
622 | __u32 hsize1; /* Horizontal size of raw vbi data for second field */ | ||
623 | __u32 vsize1; /* Vertical size of raw vbi data for second field */ | ||
624 | }; | ||
625 | |||
626 | /* structure for vpif parameters */ | ||
627 | struct vpif_video_params { | ||
628 | __u8 storage_mode; /* Indicates field or frame mode */ | ||
629 | unsigned long hpitch; | ||
630 | v4l2_std_id stdid; | ||
631 | }; | ||
632 | |||
633 | struct vpif_params { | ||
634 | struct vpif_interface iface; | ||
635 | struct vpif_video_params video_params; | ||
636 | struct vpif_channel_config_params std_info; | ||
637 | union param { | ||
638 | struct vpif_vbi_params vbi_params; | ||
639 | enum data_size data_sz; | ||
640 | } params; | ||
641 | }; | ||
642 | |||
643 | #endif /* End of #ifndef VPIF_H */ | ||
644 | |||
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c new file mode 100644 index 00000000000..49e4deb5004 --- /dev/null +++ b/drivers/media/video/davinci/vpif_capture.c | |||
@@ -0,0 +1,2412 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * TODO : add support for VBI & HBI data service | ||
19 | * add static buffer allocation | ||
20 | */ | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/workqueue.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/videodev2.h> | ||
31 | #include <linux/wait.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <linux/i2c.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/io.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <media/v4l2-device.h> | ||
38 | #include <media/v4l2-ioctl.h> | ||
39 | #include <media/v4l2-chip-ident.h> | ||
40 | |||
41 | #include "vpif_capture.h" | ||
42 | #include "vpif.h" | ||
43 | |||
44 | MODULE_DESCRIPTION("TI DaVinci VPIF Capture driver"); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | MODULE_VERSION(VPIF_CAPTURE_VERSION); | ||
47 | |||
48 | #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) | ||
49 | #define vpif_dbg(level, debug, fmt, arg...) \ | ||
50 | v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) | ||
51 | |||
52 | static int debug = 1; | ||
53 | static u32 ch0_numbuffers = 3; | ||
54 | static u32 ch1_numbuffers = 3; | ||
55 | static u32 ch0_bufsize = 1920 * 1080 * 2; | ||
56 | static u32 ch1_bufsize = 720 * 576 * 2; | ||
57 | |||
58 | module_param(debug, int, 0644); | ||
59 | module_param(ch0_numbuffers, uint, S_IRUGO); | ||
60 | module_param(ch1_numbuffers, uint, S_IRUGO); | ||
61 | module_param(ch0_bufsize, uint, S_IRUGO); | ||
62 | module_param(ch1_bufsize, uint, S_IRUGO); | ||
63 | |||
64 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
65 | MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)"); | ||
66 | MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)"); | ||
67 | MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)"); | ||
68 | MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)"); | ||
69 | |||
70 | static struct vpif_config_params config_params = { | ||
71 | .min_numbuffers = 3, | ||
72 | .numbuffers[0] = 3, | ||
73 | .numbuffers[1] = 3, | ||
74 | .min_bufsize[0] = 720 * 480 * 2, | ||
75 | .min_bufsize[1] = 720 * 480 * 2, | ||
76 | .channel_bufsize[0] = 1920 * 1080 * 2, | ||
77 | .channel_bufsize[1] = 720 * 576 * 2, | ||
78 | }; | ||
79 | |||
80 | /* global variables */ | ||
81 | static struct vpif_device vpif_obj = { {NULL} }; | ||
82 | static struct device *vpif_dev; | ||
83 | |||
84 | /** | ||
85 | * vpif_uservirt_to_phys : translate user/virtual address to phy address | ||
86 | * @virtp: user/virtual address | ||
87 | * | ||
88 | * This inline function is used to convert user space virtual address to | ||
89 | * physical address. | ||
90 | */ | ||
91 | static inline u32 vpif_uservirt_to_phys(u32 virtp) | ||
92 | { | ||
93 | unsigned long physp = 0; | ||
94 | struct mm_struct *mm = current->mm; | ||
95 | struct vm_area_struct *vma; | ||
96 | |||
97 | vma = find_vma(mm, virtp); | ||
98 | |||
99 | /* For kernel direct-mapped memory, take the easy way */ | ||
100 | if (virtp >= PAGE_OFFSET) | ||
101 | physp = virt_to_phys((void *)virtp); | ||
102 | else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) | ||
103 | /** | ||
104 | * this will catch, kernel-allocated, mmaped-to-usermode | ||
105 | * addresses | ||
106 | */ | ||
107 | physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); | ||
108 | else { | ||
109 | /* otherwise, use get_user_pages() for general userland pages */ | ||
110 | int res, nr_pages = 1; | ||
111 | struct page *pages; | ||
112 | |||
113 | down_read(¤t->mm->mmap_sem); | ||
114 | |||
115 | res = get_user_pages(current, current->mm, | ||
116 | virtp, nr_pages, 1, 0, &pages, NULL); | ||
117 | up_read(¤t->mm->mmap_sem); | ||
118 | |||
119 | if (res == nr_pages) | ||
120 | physp = __pa(page_address(&pages[0]) + | ||
121 | (virtp & ~PAGE_MASK)); | ||
122 | else { | ||
123 | vpif_err("get_user_pages failed\n"); | ||
124 | return 0; | ||
125 | } | ||
126 | } | ||
127 | return physp; | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * buffer_prepare : callback function for buffer prepare | ||
132 | * @q : buffer queue ptr | ||
133 | * @vb: ptr to video buffer | ||
134 | * @field: field info | ||
135 | * | ||
136 | * This is the callback function for buffer prepare when videobuf_qbuf() | ||
137 | * function is called. The buffer is prepared and user space virtual address | ||
138 | * or user address is converted into physical address | ||
139 | */ | ||
140 | static int vpif_buffer_prepare(struct videobuf_queue *q, | ||
141 | struct videobuf_buffer *vb, | ||
142 | enum v4l2_field field) | ||
143 | { | ||
144 | /* Get the file handle object and channel object */ | ||
145 | struct vpif_fh *fh = q->priv_data; | ||
146 | struct channel_obj *ch = fh->channel; | ||
147 | struct common_obj *common; | ||
148 | unsigned long addr; | ||
149 | |||
150 | |||
151 | vpif_dbg(2, debug, "vpif_buffer_prepare\n"); | ||
152 | |||
153 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
154 | |||
155 | /* If buffer is not initialized, initialize it */ | ||
156 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
157 | vb->width = common->width; | ||
158 | vb->height = common->height; | ||
159 | vb->size = vb->width * vb->height; | ||
160 | vb->field = field; | ||
161 | } | ||
162 | vb->state = VIDEOBUF_PREPARED; | ||
163 | /** | ||
164 | * if user pointer memory mechanism is used, get the physical | ||
165 | * address of the buffer | ||
166 | */ | ||
167 | if (V4L2_MEMORY_USERPTR == common->memory) { | ||
168 | if (0 == vb->baddr) { | ||
169 | vpif_dbg(1, debug, "buffer address is 0\n"); | ||
170 | return -EINVAL; | ||
171 | |||
172 | } | ||
173 | vb->boff = vpif_uservirt_to_phys(vb->baddr); | ||
174 | if (!IS_ALIGNED(vb->boff, 8)) | ||
175 | goto exit; | ||
176 | } | ||
177 | |||
178 | addr = vb->boff; | ||
179 | if (q->streaming) { | ||
180 | if (!IS_ALIGNED((addr + common->ytop_off), 8) || | ||
181 | !IS_ALIGNED((addr + common->ybtm_off), 8) || | ||
182 | !IS_ALIGNED((addr + common->ctop_off), 8) || | ||
183 | !IS_ALIGNED((addr + common->cbtm_off), 8)) | ||
184 | goto exit; | ||
185 | } | ||
186 | return 0; | ||
187 | exit: | ||
188 | vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n"); | ||
189 | return -EINVAL; | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * vpif_buffer_setup : Callback function for buffer setup. | ||
194 | * @q: buffer queue ptr | ||
195 | * @count: number of buffers | ||
196 | * @size: size of the buffer | ||
197 | * | ||
198 | * This callback function is called when reqbuf() is called to adjust | ||
199 | * the buffer count and buffer size | ||
200 | */ | ||
201 | static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
202 | unsigned int *size) | ||
203 | { | ||
204 | /* Get the file handle object and channel object */ | ||
205 | struct vpif_fh *fh = q->priv_data; | ||
206 | struct channel_obj *ch = fh->channel; | ||
207 | struct common_obj *common; | ||
208 | |||
209 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
210 | |||
211 | vpif_dbg(2, debug, "vpif_buffer_setup\n"); | ||
212 | |||
213 | /* If memory type is not mmap, return */ | ||
214 | if (V4L2_MEMORY_MMAP != common->memory) | ||
215 | return 0; | ||
216 | |||
217 | /* Calculate the size of the buffer */ | ||
218 | *size = config_params.channel_bufsize[ch->channel_id]; | ||
219 | |||
220 | if (*count < config_params.min_numbuffers) | ||
221 | *count = config_params.min_numbuffers; | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * vpif_buffer_queue : Callback function to add buffer to DMA queue | ||
227 | * @q: ptr to videobuf_queue | ||
228 | * @vb: ptr to videobuf_buffer | ||
229 | */ | ||
230 | static void vpif_buffer_queue(struct videobuf_queue *q, | ||
231 | struct videobuf_buffer *vb) | ||
232 | { | ||
233 | /* Get the file handle object and channel object */ | ||
234 | struct vpif_fh *fh = q->priv_data; | ||
235 | struct channel_obj *ch = fh->channel; | ||
236 | struct common_obj *common; | ||
237 | |||
238 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
239 | |||
240 | vpif_dbg(2, debug, "vpif_buffer_queue\n"); | ||
241 | |||
242 | /* add the buffer to the DMA queue */ | ||
243 | list_add_tail(&vb->queue, &common->dma_queue); | ||
244 | /* Change state of the buffer */ | ||
245 | vb->state = VIDEOBUF_QUEUED; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * vpif_buffer_release : Callback function to free buffer | ||
250 | * @q: buffer queue ptr | ||
251 | * @vb: ptr to video buffer | ||
252 | * | ||
253 | * This function is called from the videobuf layer to free memory | ||
254 | * allocated to the buffers | ||
255 | */ | ||
256 | static void vpif_buffer_release(struct videobuf_queue *q, | ||
257 | struct videobuf_buffer *vb) | ||
258 | { | ||
259 | /* Get the file handle object and channel object */ | ||
260 | struct vpif_fh *fh = q->priv_data; | ||
261 | struct channel_obj *ch = fh->channel; | ||
262 | struct common_obj *common; | ||
263 | |||
264 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
265 | |||
266 | videobuf_dma_contig_free(q, vb); | ||
267 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
268 | } | ||
269 | |||
270 | static struct videobuf_queue_ops video_qops = { | ||
271 | .buf_setup = vpif_buffer_setup, | ||
272 | .buf_prepare = vpif_buffer_prepare, | ||
273 | .buf_queue = vpif_buffer_queue, | ||
274 | .buf_release = vpif_buffer_release, | ||
275 | }; | ||
276 | |||
277 | static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = | ||
278 | { {1, 1} }; | ||
279 | |||
280 | /** | ||
281 | * vpif_process_buffer_complete: process a completed buffer | ||
282 | * @common: ptr to common channel object | ||
283 | * | ||
284 | * This function time stamp the buffer and mark it as DONE. It also | ||
285 | * wake up any process waiting on the QUEUE and set the next buffer | ||
286 | * as current | ||
287 | */ | ||
288 | static void vpif_process_buffer_complete(struct common_obj *common) | ||
289 | { | ||
290 | do_gettimeofday(&common->cur_frm->ts); | ||
291 | common->cur_frm->state = VIDEOBUF_DONE; | ||
292 | wake_up_interruptible(&common->cur_frm->done); | ||
293 | /* Make curFrm pointing to nextFrm */ | ||
294 | common->cur_frm = common->next_frm; | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * vpif_schedule_next_buffer: set next buffer address for capture | ||
299 | * @common : ptr to common channel object | ||
300 | * | ||
301 | * This function will get next buffer from the dma queue and | ||
302 | * set the buffer address in the vpif register for capture. | ||
303 | * the buffer is marked active | ||
304 | */ | ||
305 | static void vpif_schedule_next_buffer(struct common_obj *common) | ||
306 | { | ||
307 | unsigned long addr = 0; | ||
308 | |||
309 | common->next_frm = list_entry(common->dma_queue.next, | ||
310 | struct videobuf_buffer, queue); | ||
311 | /* Remove that buffer from the buffer queue */ | ||
312 | list_del(&common->next_frm->queue); | ||
313 | common->next_frm->state = VIDEOBUF_ACTIVE; | ||
314 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
315 | addr = common->next_frm->boff; | ||
316 | else | ||
317 | addr = videobuf_to_dma_contig(common->next_frm); | ||
318 | |||
319 | /* Set top and bottom field addresses in VPIF registers */ | ||
320 | common->set_addr(addr + common->ytop_off, | ||
321 | addr + common->ybtm_off, | ||
322 | addr + common->ctop_off, | ||
323 | addr + common->cbtm_off); | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * vpif_channel_isr : ISR handler for vpif capture | ||
328 | * @irq: irq number | ||
329 | * @dev_id: dev_id ptr | ||
330 | * | ||
331 | * It changes status of the captured buffer, takes next buffer from the queue | ||
332 | * and sets its address in VPIF registers | ||
333 | */ | ||
334 | static irqreturn_t vpif_channel_isr(int irq, void *dev_id) | ||
335 | { | ||
336 | struct vpif_device *dev = &vpif_obj; | ||
337 | struct common_obj *common; | ||
338 | struct channel_obj *ch; | ||
339 | enum v4l2_field field; | ||
340 | int channel_id = 0; | ||
341 | int fid = -1, i; | ||
342 | |||
343 | channel_id = *(int *)(dev_id); | ||
344 | ch = dev->dev[channel_id]; | ||
345 | |||
346 | field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; | ||
347 | |||
348 | for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) { | ||
349 | common = &ch->common[i]; | ||
350 | /* skip If streaming is not started in this channel */ | ||
351 | if (0 == common->started) | ||
352 | continue; | ||
353 | |||
354 | /* Check the field format */ | ||
355 | if (1 == ch->vpifparams.std_info.frm_fmt) { | ||
356 | /* Progressive mode */ | ||
357 | if (list_empty(&common->dma_queue)) | ||
358 | continue; | ||
359 | |||
360 | if (!channel_first_int[i][channel_id]) | ||
361 | vpif_process_buffer_complete(common); | ||
362 | |||
363 | channel_first_int[i][channel_id] = 0; | ||
364 | |||
365 | vpif_schedule_next_buffer(common); | ||
366 | |||
367 | |||
368 | channel_first_int[i][channel_id] = 0; | ||
369 | } else { | ||
370 | /** | ||
371 | * Interlaced mode. If it is first interrupt, ignore | ||
372 | * it | ||
373 | */ | ||
374 | if (channel_first_int[i][channel_id]) { | ||
375 | channel_first_int[i][channel_id] = 0; | ||
376 | continue; | ||
377 | } | ||
378 | if (0 == i) { | ||
379 | ch->field_id ^= 1; | ||
380 | /* Get field id from VPIF registers */ | ||
381 | fid = vpif_channel_getfid(ch->channel_id); | ||
382 | if (fid != ch->field_id) { | ||
383 | /** | ||
384 | * If field id does not match stored | ||
385 | * field id, make them in sync | ||
386 | */ | ||
387 | if (0 == fid) | ||
388 | ch->field_id = fid; | ||
389 | return IRQ_HANDLED; | ||
390 | } | ||
391 | } | ||
392 | /* device field id and local field id are in sync */ | ||
393 | if (0 == fid) { | ||
394 | /* this is even field */ | ||
395 | if (common->cur_frm == common->next_frm) | ||
396 | continue; | ||
397 | |||
398 | /* mark the current buffer as done */ | ||
399 | vpif_process_buffer_complete(common); | ||
400 | } else if (1 == fid) { | ||
401 | /* odd field */ | ||
402 | if (list_empty(&common->dma_queue) || | ||
403 | (common->cur_frm != common->next_frm)) | ||
404 | continue; | ||
405 | |||
406 | vpif_schedule_next_buffer(common); | ||
407 | } | ||
408 | } | ||
409 | } | ||
410 | return IRQ_HANDLED; | ||
411 | } | ||
412 | |||
413 | /** | ||
414 | * vpif_update_std_info() - update standard related info | ||
415 | * @ch: ptr to channel object | ||
416 | * | ||
417 | * For a given standard selected by application, update values | ||
418 | * in the device data structures | ||
419 | */ | ||
420 | static int vpif_update_std_info(struct channel_obj *ch) | ||
421 | { | ||
422 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
423 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
424 | const struct vpif_channel_config_params *config; | ||
425 | struct vpif_channel_config_params *std_info = &vpifparams->std_info; | ||
426 | struct video_obj *vid_ch = &ch->video; | ||
427 | int index; | ||
428 | |||
429 | vpif_dbg(2, debug, "vpif_update_std_info\n"); | ||
430 | |||
431 | for (index = 0; index < vpif_ch_params_count; index++) { | ||
432 | config = &ch_params[index]; | ||
433 | if (config->hd_sd == 0) { | ||
434 | vpif_dbg(2, debug, "SD format\n"); | ||
435 | if (config->stdid & vid_ch->stdid) { | ||
436 | memcpy(std_info, config, sizeof(*config)); | ||
437 | break; | ||
438 | } | ||
439 | } else { | ||
440 | vpif_dbg(2, debug, "HD format\n"); | ||
441 | if (config->dv_preset == vid_ch->dv_preset) { | ||
442 | memcpy(std_info, config, sizeof(*config)); | ||
443 | break; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | /* standard not found */ | ||
449 | if (index == vpif_ch_params_count) | ||
450 | return -EINVAL; | ||
451 | |||
452 | common->fmt.fmt.pix.width = std_info->width; | ||
453 | common->width = std_info->width; | ||
454 | common->fmt.fmt.pix.height = std_info->height; | ||
455 | common->height = std_info->height; | ||
456 | common->fmt.fmt.pix.bytesperline = std_info->width; | ||
457 | vpifparams->video_params.hpitch = std_info->width; | ||
458 | vpifparams->video_params.storage_mode = std_info->frm_fmt; | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | /** | ||
464 | * vpif_calculate_offsets : This function calculates buffers offsets | ||
465 | * @ch : ptr to channel object | ||
466 | * | ||
467 | * This function calculates buffer offsets for Y and C in the top and | ||
468 | * bottom field | ||
469 | */ | ||
470 | static void vpif_calculate_offsets(struct channel_obj *ch) | ||
471 | { | ||
472 | unsigned int hpitch, vpitch, sizeimage; | ||
473 | struct video_obj *vid_ch = &(ch->video); | ||
474 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
475 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
476 | enum v4l2_field field = common->fmt.fmt.pix.field; | ||
477 | |||
478 | vpif_dbg(2, debug, "vpif_calculate_offsets\n"); | ||
479 | |||
480 | if (V4L2_FIELD_ANY == field) { | ||
481 | if (vpifparams->std_info.frm_fmt) | ||
482 | vid_ch->buf_field = V4L2_FIELD_NONE; | ||
483 | else | ||
484 | vid_ch->buf_field = V4L2_FIELD_INTERLACED; | ||
485 | } else | ||
486 | vid_ch->buf_field = common->fmt.fmt.pix.field; | ||
487 | |||
488 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
489 | sizeimage = common->fmt.fmt.pix.sizeimage; | ||
490 | else | ||
491 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
492 | |||
493 | hpitch = common->fmt.fmt.pix.bytesperline; | ||
494 | vpitch = sizeimage / (hpitch * 2); | ||
495 | |||
496 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
497 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { | ||
498 | /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ | ||
499 | common->ytop_off = 0; | ||
500 | common->ybtm_off = hpitch; | ||
501 | common->ctop_off = sizeimage / 2; | ||
502 | common->cbtm_off = sizeimage / 2 + hpitch; | ||
503 | } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { | ||
504 | /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ | ||
505 | common->ytop_off = 0; | ||
506 | common->ybtm_off = sizeimage / 4; | ||
507 | common->ctop_off = sizeimage / 2; | ||
508 | common->cbtm_off = common->ctop_off + sizeimage / 4; | ||
509 | } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { | ||
510 | /* Calculate offsets for Y top, Y Bottom, C top and C Bottom */ | ||
511 | common->ybtm_off = 0; | ||
512 | common->ytop_off = sizeimage / 4; | ||
513 | common->cbtm_off = sizeimage / 2; | ||
514 | common->ctop_off = common->cbtm_off + sizeimage / 4; | ||
515 | } | ||
516 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
517 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) | ||
518 | vpifparams->video_params.storage_mode = 1; | ||
519 | else | ||
520 | vpifparams->video_params.storage_mode = 0; | ||
521 | |||
522 | if (1 == vpifparams->std_info.frm_fmt) | ||
523 | vpifparams->video_params.hpitch = | ||
524 | common->fmt.fmt.pix.bytesperline; | ||
525 | else { | ||
526 | if ((field == V4L2_FIELD_ANY) | ||
527 | || (field == V4L2_FIELD_INTERLACED)) | ||
528 | vpifparams->video_params.hpitch = | ||
529 | common->fmt.fmt.pix.bytesperline * 2; | ||
530 | else | ||
531 | vpifparams->video_params.hpitch = | ||
532 | common->fmt.fmt.pix.bytesperline; | ||
533 | } | ||
534 | |||
535 | ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid; | ||
536 | } | ||
537 | |||
538 | /** | ||
539 | * vpif_config_format: configure default frame format in the device | ||
540 | * ch : ptr to channel object | ||
541 | */ | ||
542 | static void vpif_config_format(struct channel_obj *ch) | ||
543 | { | ||
544 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
545 | |||
546 | vpif_dbg(2, debug, "vpif_config_format\n"); | ||
547 | |||
548 | common->fmt.fmt.pix.field = V4L2_FIELD_ANY; | ||
549 | if (config_params.numbuffers[ch->channel_id] == 0) | ||
550 | common->memory = V4L2_MEMORY_USERPTR; | ||
551 | else | ||
552 | common->memory = V4L2_MEMORY_MMAP; | ||
553 | |||
554 | common->fmt.fmt.pix.sizeimage | ||
555 | = config_params.channel_bufsize[ch->channel_id]; | ||
556 | |||
557 | if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) | ||
558 | common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
559 | else | ||
560 | common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; | ||
561 | common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
562 | } | ||
563 | |||
564 | /** | ||
565 | * vpif_get_default_field() - Get default field type based on interface | ||
566 | * @vpif_params - ptr to vpif params | ||
567 | */ | ||
568 | static inline enum v4l2_field vpif_get_default_field( | ||
569 | struct vpif_interface *iface) | ||
570 | { | ||
571 | return (iface->if_type == VPIF_IF_RAW_BAYER) ? V4L2_FIELD_NONE : | ||
572 | V4L2_FIELD_INTERLACED; | ||
573 | } | ||
574 | |||
575 | /** | ||
576 | * vpif_check_format() - check given pixel format for compatibility | ||
577 | * @ch - channel ptr | ||
578 | * @pixfmt - Given pixel format | ||
579 | * @update - update the values as per hardware requirement | ||
580 | * | ||
581 | * Check the application pixel format for S_FMT and update the input | ||
582 | * values as per hardware limits for TRY_FMT. The default pixel and | ||
583 | * field format is selected based on interface type. | ||
584 | */ | ||
585 | static int vpif_check_format(struct channel_obj *ch, | ||
586 | struct v4l2_pix_format *pixfmt, | ||
587 | int update) | ||
588 | { | ||
589 | struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
590 | struct vpif_params *vpif_params = &ch->vpifparams; | ||
591 | enum v4l2_field field = pixfmt->field; | ||
592 | u32 sizeimage, hpitch, vpitch; | ||
593 | int ret = -EINVAL; | ||
594 | |||
595 | vpif_dbg(2, debug, "vpif_check_format\n"); | ||
596 | /** | ||
597 | * first check for the pixel format. If if_type is Raw bayer, | ||
598 | * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only | ||
599 | * V4L2_PIX_FMT_YUV422P is supported | ||
600 | */ | ||
601 | if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) { | ||
602 | if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) { | ||
603 | if (!update) { | ||
604 | vpif_dbg(2, debug, "invalid pix format\n"); | ||
605 | goto exit; | ||
606 | } | ||
607 | pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
608 | } | ||
609 | } else { | ||
610 | if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) { | ||
611 | if (!update) { | ||
612 | vpif_dbg(2, debug, "invalid pixel format\n"); | ||
613 | goto exit; | ||
614 | } | ||
615 | pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | if (!(VPIF_VALID_FIELD(field))) { | ||
620 | if (!update) { | ||
621 | vpif_dbg(2, debug, "invalid field format\n"); | ||
622 | goto exit; | ||
623 | } | ||
624 | /** | ||
625 | * By default use FIELD_NONE for RAW Bayer capture | ||
626 | * and FIELD_INTERLACED for other interfaces | ||
627 | */ | ||
628 | field = vpif_get_default_field(&vpif_params->iface); | ||
629 | } else if (field == V4L2_FIELD_ANY) | ||
630 | /* unsupported field. Use default */ | ||
631 | field = vpif_get_default_field(&vpif_params->iface); | ||
632 | |||
633 | /* validate the hpitch */ | ||
634 | hpitch = pixfmt->bytesperline; | ||
635 | if (hpitch < vpif_params->std_info.width) { | ||
636 | if (!update) { | ||
637 | vpif_dbg(2, debug, "invalid hpitch\n"); | ||
638 | goto exit; | ||
639 | } | ||
640 | hpitch = vpif_params->std_info.width; | ||
641 | } | ||
642 | |||
643 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
644 | sizeimage = pixfmt->sizeimage; | ||
645 | else | ||
646 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
647 | |||
648 | vpitch = sizeimage / (hpitch * 2); | ||
649 | |||
650 | /* validate the vpitch */ | ||
651 | if (vpitch < vpif_params->std_info.height) { | ||
652 | if (!update) { | ||
653 | vpif_dbg(2, debug, "Invalid vpitch\n"); | ||
654 | goto exit; | ||
655 | } | ||
656 | vpitch = vpif_params->std_info.height; | ||
657 | } | ||
658 | |||
659 | /* Check for 8 byte alignment */ | ||
660 | if (!ALIGN(hpitch, 8)) { | ||
661 | if (!update) { | ||
662 | vpif_dbg(2, debug, "invalid pitch alignment\n"); | ||
663 | goto exit; | ||
664 | } | ||
665 | /* adjust to next 8 byte boundary */ | ||
666 | hpitch = (((hpitch + 7) / 8) * 8); | ||
667 | } | ||
668 | /* if update is set, modify the bytesperline and sizeimage */ | ||
669 | if (update) { | ||
670 | pixfmt->bytesperline = hpitch; | ||
671 | pixfmt->sizeimage = hpitch * vpitch * 2; | ||
672 | } | ||
673 | /** | ||
674 | * Image width and height is always based on current standard width and | ||
675 | * height | ||
676 | */ | ||
677 | pixfmt->width = common->fmt.fmt.pix.width; | ||
678 | pixfmt->height = common->fmt.fmt.pix.height; | ||
679 | return 0; | ||
680 | exit: | ||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | /** | ||
685 | * vpif_config_addr() - function to configure buffer address in vpif | ||
686 | * @ch - channel ptr | ||
687 | * @muxmode - channel mux mode | ||
688 | */ | ||
689 | static void vpif_config_addr(struct channel_obj *ch, int muxmode) | ||
690 | { | ||
691 | struct common_obj *common; | ||
692 | |||
693 | vpif_dbg(2, debug, "vpif_config_addr\n"); | ||
694 | |||
695 | common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
696 | |||
697 | if (VPIF_CHANNEL1_VIDEO == ch->channel_id) | ||
698 | common->set_addr = ch1_set_videobuf_addr; | ||
699 | else if (2 == muxmode) | ||
700 | common->set_addr = ch0_set_videobuf_addr_yc_nmux; | ||
701 | else | ||
702 | common->set_addr = ch0_set_videobuf_addr; | ||
703 | } | ||
704 | |||
705 | /** | ||
706 | * vpfe_mmap : It is used to map kernel space buffers into user spaces | ||
707 | * @filep: file pointer | ||
708 | * @vma: ptr to vm_area_struct | ||
709 | */ | ||
710 | static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) | ||
711 | { | ||
712 | /* Get the channel object and file handle object */ | ||
713 | struct vpif_fh *fh = filep->private_data; | ||
714 | struct channel_obj *ch = fh->channel; | ||
715 | struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
716 | |||
717 | vpif_dbg(2, debug, "vpif_mmap\n"); | ||
718 | |||
719 | return videobuf_mmap_mapper(&common->buffer_queue, vma); | ||
720 | } | ||
721 | |||
722 | /** | ||
723 | * vpif_poll: It is used for select/poll system call | ||
724 | * @filep: file pointer | ||
725 | * @wait: poll table to wait | ||
726 | */ | ||
727 | static unsigned int vpif_poll(struct file *filep, poll_table * wait) | ||
728 | { | ||
729 | struct vpif_fh *fh = filep->private_data; | ||
730 | struct channel_obj *channel = fh->channel; | ||
731 | struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]); | ||
732 | |||
733 | vpif_dbg(2, debug, "vpif_poll\n"); | ||
734 | |||
735 | if (common->started) | ||
736 | return videobuf_poll_stream(filep, &common->buffer_queue, wait); | ||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | /** | ||
741 | * vpif_open : vpif open handler | ||
742 | * @filep: file ptr | ||
743 | * | ||
744 | * It creates object of file handle structure and stores it in private_data | ||
745 | * member of filepointer | ||
746 | */ | ||
747 | static int vpif_open(struct file *filep) | ||
748 | { | ||
749 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
750 | struct video_device *vdev = video_devdata(filep); | ||
751 | struct common_obj *common; | ||
752 | struct video_obj *vid_ch; | ||
753 | struct channel_obj *ch; | ||
754 | struct vpif_fh *fh; | ||
755 | int i; | ||
756 | |||
757 | vpif_dbg(2, debug, "vpif_open\n"); | ||
758 | |||
759 | ch = video_get_drvdata(vdev); | ||
760 | |||
761 | vid_ch = &ch->video; | ||
762 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
763 | |||
764 | if (NULL == ch->curr_subdev_info) { | ||
765 | /** | ||
766 | * search through the sub device to see a registered | ||
767 | * sub device and make it as current sub device | ||
768 | */ | ||
769 | for (i = 0; i < config->subdev_count; i++) { | ||
770 | if (vpif_obj.sd[i]) { | ||
771 | /* the sub device is registered */ | ||
772 | ch->curr_subdev_info = &config->subdev_info[i]; | ||
773 | /* make first input as the current input */ | ||
774 | vid_ch->input_idx = 0; | ||
775 | break; | ||
776 | } | ||
777 | } | ||
778 | if (i == config->subdev_count) { | ||
779 | vpif_err("No sub device registered\n"); | ||
780 | return -ENOENT; | ||
781 | } | ||
782 | } | ||
783 | |||
784 | /* Allocate memory for the file handle object */ | ||
785 | fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); | ||
786 | if (NULL == fh) { | ||
787 | vpif_err("unable to allocate memory for file handle object\n"); | ||
788 | return -ENOMEM; | ||
789 | } | ||
790 | |||
791 | /* store pointer to fh in private_data member of filep */ | ||
792 | filep->private_data = fh; | ||
793 | fh->channel = ch; | ||
794 | fh->initialized = 0; | ||
795 | /* If decoder is not initialized. initialize it */ | ||
796 | if (!ch->initialized) { | ||
797 | fh->initialized = 1; | ||
798 | ch->initialized = 1; | ||
799 | memset(&(ch->vpifparams), 0, sizeof(struct vpif_params)); | ||
800 | } | ||
801 | /* Increment channel usrs counter */ | ||
802 | ch->usrs++; | ||
803 | /* Set io_allowed member to false */ | ||
804 | fh->io_allowed[VPIF_VIDEO_INDEX] = 0; | ||
805 | /* Initialize priority of this instance to default priority */ | ||
806 | fh->prio = V4L2_PRIORITY_UNSET; | ||
807 | v4l2_prio_open(&ch->prio, &fh->prio); | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | /** | ||
812 | * vpif_release : function to clean up file close | ||
813 | * @filep: file pointer | ||
814 | * | ||
815 | * This function deletes buffer queue, frees the buffers and the vpfe file | ||
816 | * handle | ||
817 | */ | ||
818 | static int vpif_release(struct file *filep) | ||
819 | { | ||
820 | struct vpif_fh *fh = filep->private_data; | ||
821 | struct channel_obj *ch = fh->channel; | ||
822 | struct common_obj *common; | ||
823 | |||
824 | vpif_dbg(2, debug, "vpif_release\n"); | ||
825 | |||
826 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
827 | |||
828 | /* if this instance is doing IO */ | ||
829 | if (fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
830 | /* Reset io_usrs member of channel object */ | ||
831 | common->io_usrs = 0; | ||
832 | /* Disable channel as per its device type and channel id */ | ||
833 | if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { | ||
834 | enable_channel0(0); | ||
835 | channel0_intr_enable(0); | ||
836 | } | ||
837 | if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || | ||
838 | (2 == common->started)) { | ||
839 | enable_channel1(0); | ||
840 | channel1_intr_enable(0); | ||
841 | } | ||
842 | common->started = 0; | ||
843 | /* Free buffers allocated */ | ||
844 | videobuf_queue_cancel(&common->buffer_queue); | ||
845 | videobuf_mmap_free(&common->buffer_queue); | ||
846 | } | ||
847 | |||
848 | /* Decrement channel usrs counter */ | ||
849 | ch->usrs--; | ||
850 | |||
851 | /* Close the priority */ | ||
852 | v4l2_prio_close(&ch->prio, fh->prio); | ||
853 | |||
854 | if (fh->initialized) | ||
855 | ch->initialized = 0; | ||
856 | |||
857 | filep->private_data = NULL; | ||
858 | kfree(fh); | ||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | /** | ||
863 | * vpif_reqbufs() - request buffer handler | ||
864 | * @file: file ptr | ||
865 | * @priv: file handle | ||
866 | * @reqbuf: request buffer structure ptr | ||
867 | */ | ||
868 | static int vpif_reqbufs(struct file *file, void *priv, | ||
869 | struct v4l2_requestbuffers *reqbuf) | ||
870 | { | ||
871 | struct vpif_fh *fh = priv; | ||
872 | struct channel_obj *ch = fh->channel; | ||
873 | struct common_obj *common; | ||
874 | u8 index = 0; | ||
875 | |||
876 | vpif_dbg(2, debug, "vpif_reqbufs\n"); | ||
877 | |||
878 | /** | ||
879 | * This file handle has not initialized the channel, | ||
880 | * It is not allowed to do settings | ||
881 | */ | ||
882 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) | ||
883 | || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
884 | if (!fh->initialized) { | ||
885 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
886 | return -EBUSY; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) | ||
891 | return -EINVAL; | ||
892 | |||
893 | index = VPIF_VIDEO_INDEX; | ||
894 | |||
895 | common = &ch->common[index]; | ||
896 | |||
897 | if (0 != common->io_usrs) | ||
898 | return -EBUSY; | ||
899 | |||
900 | /* Initialize videobuf queue as per the buffer type */ | ||
901 | videobuf_queue_dma_contig_init(&common->buffer_queue, | ||
902 | &video_qops, NULL, | ||
903 | &common->irqlock, | ||
904 | reqbuf->type, | ||
905 | common->fmt.fmt.pix.field, | ||
906 | sizeof(struct videobuf_buffer), fh, | ||
907 | &common->lock); | ||
908 | |||
909 | /* Set io allowed member of file handle to TRUE */ | ||
910 | fh->io_allowed[index] = 1; | ||
911 | /* Increment io usrs member of channel object to 1 */ | ||
912 | common->io_usrs = 1; | ||
913 | /* Store type of memory requested in channel object */ | ||
914 | common->memory = reqbuf->memory; | ||
915 | INIT_LIST_HEAD(&common->dma_queue); | ||
916 | |||
917 | /* Allocate buffers */ | ||
918 | return videobuf_reqbufs(&common->buffer_queue, reqbuf); | ||
919 | } | ||
920 | |||
921 | /** | ||
922 | * vpif_querybuf() - query buffer handler | ||
923 | * @file: file ptr | ||
924 | * @priv: file handle | ||
925 | * @buf: v4l2 buffer structure ptr | ||
926 | */ | ||
927 | static int vpif_querybuf(struct file *file, void *priv, | ||
928 | struct v4l2_buffer *buf) | ||
929 | { | ||
930 | struct vpif_fh *fh = priv; | ||
931 | struct channel_obj *ch = fh->channel; | ||
932 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
933 | |||
934 | vpif_dbg(2, debug, "vpif_querybuf\n"); | ||
935 | |||
936 | if (common->fmt.type != buf->type) | ||
937 | return -EINVAL; | ||
938 | |||
939 | if (common->memory != V4L2_MEMORY_MMAP) { | ||
940 | vpif_dbg(1, debug, "Invalid memory\n"); | ||
941 | return -EINVAL; | ||
942 | } | ||
943 | |||
944 | return videobuf_querybuf(&common->buffer_queue, buf); | ||
945 | } | ||
946 | |||
947 | /** | ||
948 | * vpif_qbuf() - query buffer handler | ||
949 | * @file: file ptr | ||
950 | * @priv: file handle | ||
951 | * @buf: v4l2 buffer structure ptr | ||
952 | */ | ||
953 | static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
954 | { | ||
955 | |||
956 | struct vpif_fh *fh = priv; | ||
957 | struct channel_obj *ch = fh->channel; | ||
958 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
959 | struct v4l2_buffer tbuf = *buf; | ||
960 | struct videobuf_buffer *buf1; | ||
961 | unsigned long addr = 0; | ||
962 | unsigned long flags; | ||
963 | int ret = 0; | ||
964 | |||
965 | vpif_dbg(2, debug, "vpif_qbuf\n"); | ||
966 | |||
967 | if (common->fmt.type != tbuf.type) { | ||
968 | vpif_err("invalid buffer type\n"); | ||
969 | return -EINVAL; | ||
970 | } | ||
971 | |||
972 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
973 | vpif_err("fh io not allowed \n"); | ||
974 | return -EACCES; | ||
975 | } | ||
976 | |||
977 | if (!(list_empty(&common->dma_queue)) || | ||
978 | (common->cur_frm != common->next_frm) || | ||
979 | !common->started || | ||
980 | (common->started && (0 == ch->field_id))) | ||
981 | return videobuf_qbuf(&common->buffer_queue, buf); | ||
982 | |||
983 | /* bufferqueue is empty store buffer address in VPIF registers */ | ||
984 | mutex_lock(&common->buffer_queue.vb_lock); | ||
985 | buf1 = common->buffer_queue.bufs[tbuf.index]; | ||
986 | |||
987 | if ((buf1->state == VIDEOBUF_QUEUED) || | ||
988 | (buf1->state == VIDEOBUF_ACTIVE)) { | ||
989 | vpif_err("invalid state\n"); | ||
990 | goto qbuf_exit; | ||
991 | } | ||
992 | |||
993 | switch (buf1->memory) { | ||
994 | case V4L2_MEMORY_MMAP: | ||
995 | if (buf1->baddr == 0) | ||
996 | goto qbuf_exit; | ||
997 | break; | ||
998 | |||
999 | case V4L2_MEMORY_USERPTR: | ||
1000 | if (tbuf.length < buf1->bsize) | ||
1001 | goto qbuf_exit; | ||
1002 | |||
1003 | if ((VIDEOBUF_NEEDS_INIT != buf1->state) | ||
1004 | && (buf1->baddr != tbuf.m.userptr)) { | ||
1005 | vpif_buffer_release(&common->buffer_queue, buf1); | ||
1006 | buf1->baddr = tbuf.m.userptr; | ||
1007 | } | ||
1008 | break; | ||
1009 | |||
1010 | default: | ||
1011 | goto qbuf_exit; | ||
1012 | } | ||
1013 | |||
1014 | local_irq_save(flags); | ||
1015 | ret = vpif_buffer_prepare(&common->buffer_queue, buf1, | ||
1016 | common->buffer_queue.field); | ||
1017 | if (ret < 0) { | ||
1018 | local_irq_restore(flags); | ||
1019 | goto qbuf_exit; | ||
1020 | } | ||
1021 | |||
1022 | buf1->state = VIDEOBUF_ACTIVE; | ||
1023 | |||
1024 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
1025 | addr = buf1->boff; | ||
1026 | else | ||
1027 | addr = videobuf_to_dma_contig(buf1); | ||
1028 | |||
1029 | common->next_frm = buf1; | ||
1030 | common->set_addr(addr + common->ytop_off, | ||
1031 | addr + common->ybtm_off, | ||
1032 | addr + common->ctop_off, | ||
1033 | addr + common->cbtm_off); | ||
1034 | |||
1035 | local_irq_restore(flags); | ||
1036 | list_add_tail(&buf1->stream, &common->buffer_queue.stream); | ||
1037 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
1038 | return 0; | ||
1039 | |||
1040 | qbuf_exit: | ||
1041 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
1042 | return -EINVAL; | ||
1043 | } | ||
1044 | |||
1045 | /** | ||
1046 | * vpif_dqbuf() - query buffer handler | ||
1047 | * @file: file ptr | ||
1048 | * @priv: file handle | ||
1049 | * @buf: v4l2 buffer structure ptr | ||
1050 | */ | ||
1051 | static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1052 | { | ||
1053 | struct vpif_fh *fh = priv; | ||
1054 | struct channel_obj *ch = fh->channel; | ||
1055 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1056 | |||
1057 | vpif_dbg(2, debug, "vpif_dqbuf\n"); | ||
1058 | |||
1059 | return videobuf_dqbuf(&common->buffer_queue, buf, | ||
1060 | file->f_flags & O_NONBLOCK); | ||
1061 | } | ||
1062 | |||
1063 | /** | ||
1064 | * vpif_streamon() - streamon handler | ||
1065 | * @file: file ptr | ||
1066 | * @priv: file handle | ||
1067 | * @buftype: v4l2 buffer type | ||
1068 | */ | ||
1069 | static int vpif_streamon(struct file *file, void *priv, | ||
1070 | enum v4l2_buf_type buftype) | ||
1071 | { | ||
1072 | |||
1073 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1074 | struct vpif_fh *fh = priv; | ||
1075 | struct channel_obj *ch = fh->channel; | ||
1076 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1077 | struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; | ||
1078 | struct vpif_params *vpif; | ||
1079 | unsigned long addr = 0; | ||
1080 | int ret = 0; | ||
1081 | |||
1082 | vpif_dbg(2, debug, "vpif_streamon\n"); | ||
1083 | |||
1084 | vpif = &ch->vpifparams; | ||
1085 | |||
1086 | if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1087 | vpif_dbg(1, debug, "buffer type not supported\n"); | ||
1088 | return -EINVAL; | ||
1089 | } | ||
1090 | |||
1091 | /* If file handle is not allowed IO, return error */ | ||
1092 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1093 | vpif_dbg(1, debug, "io not allowed\n"); | ||
1094 | return -EACCES; | ||
1095 | } | ||
1096 | |||
1097 | /* If Streaming is already started, return error */ | ||
1098 | if (common->started) { | ||
1099 | vpif_dbg(1, debug, "channel->started\n"); | ||
1100 | return -EBUSY; | ||
1101 | } | ||
1102 | |||
1103 | if ((ch->channel_id == VPIF_CHANNEL0_VIDEO && | ||
1104 | oth_ch->common[VPIF_VIDEO_INDEX].started && | ||
1105 | vpif->std_info.ycmux_mode == 0) || | ||
1106 | ((ch->channel_id == VPIF_CHANNEL1_VIDEO) && | ||
1107 | (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { | ||
1108 | vpif_dbg(1, debug, "other channel is being used\n"); | ||
1109 | return -EBUSY; | ||
1110 | } | ||
1111 | |||
1112 | ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0); | ||
1113 | if (ret) | ||
1114 | return ret; | ||
1115 | |||
1116 | /* Enable streamon on the sub device */ | ||
1117 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, | ||
1118 | s_stream, 1); | ||
1119 | |||
1120 | if (ret && (ret != -ENOIOCTLCMD)) { | ||
1121 | vpif_dbg(1, debug, "stream on failed in subdev\n"); | ||
1122 | return ret; | ||
1123 | } | ||
1124 | |||
1125 | /* Call videobuf_streamon to start streaming in videobuf */ | ||
1126 | ret = videobuf_streamon(&common->buffer_queue); | ||
1127 | if (ret) { | ||
1128 | vpif_dbg(1, debug, "videobuf_streamon\n"); | ||
1129 | return ret; | ||
1130 | } | ||
1131 | |||
1132 | /* If buffer queue is empty, return error */ | ||
1133 | if (list_empty(&common->dma_queue)) { | ||
1134 | vpif_dbg(1, debug, "buffer queue is empty\n"); | ||
1135 | ret = -EIO; | ||
1136 | goto exit; | ||
1137 | } | ||
1138 | |||
1139 | /* Get the next frame from the buffer queue */ | ||
1140 | common->cur_frm = list_entry(common->dma_queue.next, | ||
1141 | struct videobuf_buffer, queue); | ||
1142 | common->next_frm = common->cur_frm; | ||
1143 | |||
1144 | /* Remove buffer from the buffer queue */ | ||
1145 | list_del(&common->cur_frm->queue); | ||
1146 | /* Mark state of the current frame to active */ | ||
1147 | common->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1148 | /* Initialize field_id and started member */ | ||
1149 | ch->field_id = 0; | ||
1150 | common->started = 1; | ||
1151 | |||
1152 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
1153 | addr = common->cur_frm->boff; | ||
1154 | else | ||
1155 | addr = videobuf_to_dma_contig(common->cur_frm); | ||
1156 | |||
1157 | /* Calculate the offset for Y and C data in the buffer */ | ||
1158 | vpif_calculate_offsets(ch); | ||
1159 | |||
1160 | if ((vpif->std_info.frm_fmt && | ||
1161 | ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && | ||
1162 | (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || | ||
1163 | (!vpif->std_info.frm_fmt && | ||
1164 | (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { | ||
1165 | vpif_dbg(1, debug, "conflict in field format and std format\n"); | ||
1166 | ret = -EINVAL; | ||
1167 | goto exit; | ||
1168 | } | ||
1169 | |||
1170 | /* configure 1 or 2 channel mode */ | ||
1171 | ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); | ||
1172 | |||
1173 | if (ret < 0) { | ||
1174 | vpif_dbg(1, debug, "can't set vpif channel mode\n"); | ||
1175 | goto exit; | ||
1176 | } | ||
1177 | |||
1178 | /* Call vpif_set_params function to set the parameters and addresses */ | ||
1179 | ret = vpif_set_video_params(vpif, ch->channel_id); | ||
1180 | |||
1181 | if (ret < 0) { | ||
1182 | vpif_dbg(1, debug, "can't set video params\n"); | ||
1183 | goto exit; | ||
1184 | } | ||
1185 | |||
1186 | common->started = ret; | ||
1187 | vpif_config_addr(ch, ret); | ||
1188 | |||
1189 | common->set_addr(addr + common->ytop_off, | ||
1190 | addr + common->ybtm_off, | ||
1191 | addr + common->ctop_off, | ||
1192 | addr + common->cbtm_off); | ||
1193 | |||
1194 | /** | ||
1195 | * Set interrupt for both the fields in VPIF Register enable channel in | ||
1196 | * VPIF register | ||
1197 | */ | ||
1198 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) { | ||
1199 | channel0_intr_assert(); | ||
1200 | channel0_intr_enable(1); | ||
1201 | enable_channel0(1); | ||
1202 | } | ||
1203 | if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || | ||
1204 | (common->started == 2)) { | ||
1205 | channel1_intr_assert(); | ||
1206 | channel1_intr_enable(1); | ||
1207 | enable_channel1(1); | ||
1208 | } | ||
1209 | channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; | ||
1210 | return ret; | ||
1211 | |||
1212 | exit: | ||
1213 | videobuf_streamoff(&common->buffer_queue); | ||
1214 | return ret; | ||
1215 | } | ||
1216 | |||
1217 | /** | ||
1218 | * vpif_streamoff() - streamoff handler | ||
1219 | * @file: file ptr | ||
1220 | * @priv: file handle | ||
1221 | * @buftype: v4l2 buffer type | ||
1222 | */ | ||
1223 | static int vpif_streamoff(struct file *file, void *priv, | ||
1224 | enum v4l2_buf_type buftype) | ||
1225 | { | ||
1226 | |||
1227 | struct vpif_fh *fh = priv; | ||
1228 | struct channel_obj *ch = fh->channel; | ||
1229 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1230 | int ret; | ||
1231 | |||
1232 | vpif_dbg(2, debug, "vpif_streamoff\n"); | ||
1233 | |||
1234 | if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1235 | vpif_dbg(1, debug, "buffer type not supported\n"); | ||
1236 | return -EINVAL; | ||
1237 | } | ||
1238 | |||
1239 | /* If io is allowed for this file handle, return error */ | ||
1240 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1241 | vpif_dbg(1, debug, "io not allowed\n"); | ||
1242 | return -EACCES; | ||
1243 | } | ||
1244 | |||
1245 | /* If streaming is not started, return error */ | ||
1246 | if (!common->started) { | ||
1247 | vpif_dbg(1, debug, "channel->started\n"); | ||
1248 | return -EINVAL; | ||
1249 | } | ||
1250 | |||
1251 | /* disable channel */ | ||
1252 | if (VPIF_CHANNEL0_VIDEO == ch->channel_id) { | ||
1253 | enable_channel0(0); | ||
1254 | channel0_intr_enable(0); | ||
1255 | } else { | ||
1256 | enable_channel1(0); | ||
1257 | channel1_intr_enable(0); | ||
1258 | } | ||
1259 | |||
1260 | common->started = 0; | ||
1261 | |||
1262 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, | ||
1263 | s_stream, 0); | ||
1264 | |||
1265 | if (ret && (ret != -ENOIOCTLCMD)) | ||
1266 | vpif_dbg(1, debug, "stream off failed in subdev\n"); | ||
1267 | |||
1268 | return videobuf_streamoff(&common->buffer_queue); | ||
1269 | } | ||
1270 | |||
1271 | /** | ||
1272 | * vpif_map_sub_device_to_input() - Maps sub device to input | ||
1273 | * @ch - ptr to channel | ||
1274 | * @config - ptr to capture configuration | ||
1275 | * @input_index - Given input index from application | ||
1276 | * @sub_device_index - index into sd table | ||
1277 | * | ||
1278 | * lookup the sub device information for a given input index. | ||
1279 | * we report all the inputs to application. inputs table also | ||
1280 | * has sub device name for the each input | ||
1281 | */ | ||
1282 | static struct vpif_subdev_info *vpif_map_sub_device_to_input( | ||
1283 | struct channel_obj *ch, | ||
1284 | struct vpif_capture_config *vpif_cfg, | ||
1285 | int input_index, | ||
1286 | int *sub_device_index) | ||
1287 | { | ||
1288 | struct vpif_capture_chan_config *chan_cfg; | ||
1289 | struct vpif_subdev_info *subdev_info = NULL; | ||
1290 | const char *subdev_name = NULL; | ||
1291 | int i; | ||
1292 | |||
1293 | vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); | ||
1294 | |||
1295 | chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; | ||
1296 | |||
1297 | /** | ||
1298 | * search through the inputs to find the sub device supporting | ||
1299 | * the input | ||
1300 | */ | ||
1301 | for (i = 0; i < chan_cfg->input_count; i++) { | ||
1302 | /* For each sub device, loop through input */ | ||
1303 | if (i == input_index) { | ||
1304 | subdev_name = chan_cfg->inputs[i].subdev_name; | ||
1305 | break; | ||
1306 | } | ||
1307 | } | ||
1308 | |||
1309 | /* if reached maximum. return null */ | ||
1310 | if (i == chan_cfg->input_count || (NULL == subdev_name)) | ||
1311 | return subdev_info; | ||
1312 | |||
1313 | /* loop through the sub device list to get the sub device info */ | ||
1314 | for (i = 0; i < vpif_cfg->subdev_count; i++) { | ||
1315 | subdev_info = &vpif_cfg->subdev_info[i]; | ||
1316 | if (!strcmp(subdev_info->name, subdev_name)) | ||
1317 | break; | ||
1318 | } | ||
1319 | |||
1320 | if (i == vpif_cfg->subdev_count) | ||
1321 | return subdev_info; | ||
1322 | |||
1323 | /* check if the sub device is registered */ | ||
1324 | if (NULL == vpif_obj.sd[i]) | ||
1325 | return NULL; | ||
1326 | |||
1327 | *sub_device_index = i; | ||
1328 | return subdev_info; | ||
1329 | } | ||
1330 | |||
1331 | /** | ||
1332 | * vpif_querystd() - querystd handler | ||
1333 | * @file: file ptr | ||
1334 | * @priv: file handle | ||
1335 | * @std_id: ptr to std id | ||
1336 | * | ||
1337 | * This function is called to detect standard at the selected input | ||
1338 | */ | ||
1339 | static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1340 | { | ||
1341 | struct vpif_fh *fh = priv; | ||
1342 | struct channel_obj *ch = fh->channel; | ||
1343 | int ret = 0; | ||
1344 | |||
1345 | vpif_dbg(2, debug, "vpif_querystd\n"); | ||
1346 | |||
1347 | /* Call querystd function of decoder device */ | ||
1348 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, | ||
1349 | querystd, std_id); | ||
1350 | if (ret < 0) | ||
1351 | vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); | ||
1352 | |||
1353 | return ret; | ||
1354 | } | ||
1355 | |||
1356 | /** | ||
1357 | * vpif_g_std() - get STD handler | ||
1358 | * @file: file ptr | ||
1359 | * @priv: file handle | ||
1360 | * @std_id: ptr to std id | ||
1361 | */ | ||
1362 | static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
1363 | { | ||
1364 | struct vpif_fh *fh = priv; | ||
1365 | struct channel_obj *ch = fh->channel; | ||
1366 | |||
1367 | vpif_dbg(2, debug, "vpif_g_std\n"); | ||
1368 | |||
1369 | *std = ch->video.stdid; | ||
1370 | return 0; | ||
1371 | } | ||
1372 | |||
1373 | /** | ||
1374 | * vpif_s_std() - set STD handler | ||
1375 | * @file: file ptr | ||
1376 | * @priv: file handle | ||
1377 | * @std_id: ptr to std id | ||
1378 | */ | ||
1379 | static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
1380 | { | ||
1381 | struct vpif_fh *fh = priv; | ||
1382 | struct channel_obj *ch = fh->channel; | ||
1383 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1384 | int ret = 0; | ||
1385 | |||
1386 | vpif_dbg(2, debug, "vpif_s_std\n"); | ||
1387 | |||
1388 | if (common->started) { | ||
1389 | vpif_err("streaming in progress\n"); | ||
1390 | return -EBUSY; | ||
1391 | } | ||
1392 | |||
1393 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || | ||
1394 | (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
1395 | if (!fh->initialized) { | ||
1396 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
1397 | return -EBUSY; | ||
1398 | } | ||
1399 | } | ||
1400 | |||
1401 | ret = v4l2_prio_check(&ch->prio, fh->prio); | ||
1402 | if (0 != ret) | ||
1403 | return ret; | ||
1404 | |||
1405 | fh->initialized = 1; | ||
1406 | |||
1407 | /* Call encoder subdevice function to set the standard */ | ||
1408 | ch->video.stdid = *std_id; | ||
1409 | ch->video.dv_preset = V4L2_DV_INVALID; | ||
1410 | memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); | ||
1411 | |||
1412 | /* Get the information about the standard */ | ||
1413 | if (vpif_update_std_info(ch)) { | ||
1414 | vpif_err("Error getting the standard info\n"); | ||
1415 | return -EINVAL; | ||
1416 | } | ||
1417 | |||
1418 | /* Configure the default format information */ | ||
1419 | vpif_config_format(ch); | ||
1420 | |||
1421 | /* set standard in the sub device */ | ||
1422 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, | ||
1423 | s_std, *std_id); | ||
1424 | if (ret < 0) | ||
1425 | vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); | ||
1426 | return ret; | ||
1427 | } | ||
1428 | |||
1429 | /** | ||
1430 | * vpif_enum_input() - ENUMINPUT handler | ||
1431 | * @file: file ptr | ||
1432 | * @priv: file handle | ||
1433 | * @input: ptr to input structure | ||
1434 | */ | ||
1435 | static int vpif_enum_input(struct file *file, void *priv, | ||
1436 | struct v4l2_input *input) | ||
1437 | { | ||
1438 | |||
1439 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1440 | struct vpif_capture_chan_config *chan_cfg; | ||
1441 | struct vpif_fh *fh = priv; | ||
1442 | struct channel_obj *ch = fh->channel; | ||
1443 | |||
1444 | chan_cfg = &config->chan_config[ch->channel_id]; | ||
1445 | |||
1446 | if (input->index >= chan_cfg->input_count) { | ||
1447 | vpif_dbg(1, debug, "Invalid input index\n"); | ||
1448 | return -EINVAL; | ||
1449 | } | ||
1450 | |||
1451 | memcpy(input, &chan_cfg->inputs[input->index].input, | ||
1452 | sizeof(*input)); | ||
1453 | return 0; | ||
1454 | } | ||
1455 | |||
1456 | /** | ||
1457 | * vpif_g_input() - Get INPUT handler | ||
1458 | * @file: file ptr | ||
1459 | * @priv: file handle | ||
1460 | * @index: ptr to input index | ||
1461 | */ | ||
1462 | static int vpif_g_input(struct file *file, void *priv, unsigned int *index) | ||
1463 | { | ||
1464 | struct vpif_fh *fh = priv; | ||
1465 | struct channel_obj *ch = fh->channel; | ||
1466 | struct video_obj *vid_ch = &ch->video; | ||
1467 | |||
1468 | *index = vid_ch->input_idx; | ||
1469 | |||
1470 | return 0; | ||
1471 | } | ||
1472 | |||
1473 | /** | ||
1474 | * vpif_s_input() - Set INPUT handler | ||
1475 | * @file: file ptr | ||
1476 | * @priv: file handle | ||
1477 | * @index: input index | ||
1478 | */ | ||
1479 | static int vpif_s_input(struct file *file, void *priv, unsigned int index) | ||
1480 | { | ||
1481 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1482 | struct vpif_capture_chan_config *chan_cfg; | ||
1483 | struct vpif_fh *fh = priv; | ||
1484 | struct channel_obj *ch = fh->channel; | ||
1485 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1486 | struct video_obj *vid_ch = &ch->video; | ||
1487 | struct vpif_subdev_info *subdev_info; | ||
1488 | int ret = 0, sd_index = 0; | ||
1489 | u32 input = 0, output = 0; | ||
1490 | |||
1491 | chan_cfg = &config->chan_config[ch->channel_id]; | ||
1492 | |||
1493 | if (common->started) { | ||
1494 | vpif_err("Streaming in progress\n"); | ||
1495 | return -EBUSY; | ||
1496 | } | ||
1497 | |||
1498 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || | ||
1499 | (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
1500 | if (!fh->initialized) { | ||
1501 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
1502 | return -EBUSY; | ||
1503 | } | ||
1504 | } | ||
1505 | |||
1506 | ret = v4l2_prio_check(&ch->prio, fh->prio); | ||
1507 | if (0 != ret) | ||
1508 | return ret; | ||
1509 | |||
1510 | fh->initialized = 1; | ||
1511 | subdev_info = vpif_map_sub_device_to_input(ch, config, index, | ||
1512 | &sd_index); | ||
1513 | if (NULL == subdev_info) { | ||
1514 | vpif_dbg(1, debug, | ||
1515 | "couldn't lookup sub device for the input index\n"); | ||
1516 | return -EINVAL; | ||
1517 | } | ||
1518 | |||
1519 | /* first setup input path from sub device to vpif */ | ||
1520 | if (config->setup_input_path) { | ||
1521 | ret = config->setup_input_path(ch->channel_id, | ||
1522 | subdev_info->name); | ||
1523 | if (ret < 0) { | ||
1524 | vpif_dbg(1, debug, "couldn't setup input path for the" | ||
1525 | " sub device %s, for input index %d\n", | ||
1526 | subdev_info->name, index); | ||
1527 | return ret; | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | if (subdev_info->can_route) { | ||
1532 | input = subdev_info->input; | ||
1533 | output = subdev_info->output; | ||
1534 | ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, | ||
1535 | input, output, 0); | ||
1536 | if (ret < 0) { | ||
1537 | vpif_dbg(1, debug, "Failed to set input\n"); | ||
1538 | return ret; | ||
1539 | } | ||
1540 | } | ||
1541 | vid_ch->input_idx = index; | ||
1542 | ch->curr_subdev_info = subdev_info; | ||
1543 | ch->curr_sd_index = sd_index; | ||
1544 | /* copy interface parameters to vpif */ | ||
1545 | ch->vpifparams.iface = subdev_info->vpif_if; | ||
1546 | |||
1547 | /* update tvnorms from the sub device input info */ | ||
1548 | ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; | ||
1549 | return ret; | ||
1550 | } | ||
1551 | |||
1552 | /** | ||
1553 | * vpif_enum_fmt_vid_cap() - ENUM_FMT handler | ||
1554 | * @file: file ptr | ||
1555 | * @priv: file handle | ||
1556 | * @index: input index | ||
1557 | */ | ||
1558 | static int vpif_enum_fmt_vid_cap(struct file *file, void *priv, | ||
1559 | struct v4l2_fmtdesc *fmt) | ||
1560 | { | ||
1561 | struct vpif_fh *fh = priv; | ||
1562 | struct channel_obj *ch = fh->channel; | ||
1563 | |||
1564 | if (fmt->index != 0) { | ||
1565 | vpif_dbg(1, debug, "Invalid format index\n"); | ||
1566 | return -EINVAL; | ||
1567 | } | ||
1568 | |||
1569 | /* Fill in the information about format */ | ||
1570 | if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) { | ||
1571 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1572 | strcpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb"); | ||
1573 | fmt->pixelformat = V4L2_PIX_FMT_SBGGR8; | ||
1574 | } else { | ||
1575 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1576 | strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); | ||
1577 | fmt->pixelformat = V4L2_PIX_FMT_YUV422P; | ||
1578 | } | ||
1579 | return 0; | ||
1580 | } | ||
1581 | |||
1582 | /** | ||
1583 | * vpif_try_fmt_vid_cap() - TRY_FMT handler | ||
1584 | * @file: file ptr | ||
1585 | * @priv: file handle | ||
1586 | * @fmt: ptr to v4l2 format structure | ||
1587 | */ | ||
1588 | static int vpif_try_fmt_vid_cap(struct file *file, void *priv, | ||
1589 | struct v4l2_format *fmt) | ||
1590 | { | ||
1591 | struct vpif_fh *fh = priv; | ||
1592 | struct channel_obj *ch = fh->channel; | ||
1593 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
1594 | |||
1595 | return vpif_check_format(ch, pixfmt, 1); | ||
1596 | } | ||
1597 | |||
1598 | |||
1599 | /** | ||
1600 | * vpif_g_fmt_vid_cap() - Set INPUT handler | ||
1601 | * @file: file ptr | ||
1602 | * @priv: file handle | ||
1603 | * @fmt: ptr to v4l2 format structure | ||
1604 | */ | ||
1605 | static int vpif_g_fmt_vid_cap(struct file *file, void *priv, | ||
1606 | struct v4l2_format *fmt) | ||
1607 | { | ||
1608 | struct vpif_fh *fh = priv; | ||
1609 | struct channel_obj *ch = fh->channel; | ||
1610 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1611 | |||
1612 | /* Check the validity of the buffer type */ | ||
1613 | if (common->fmt.type != fmt->type) | ||
1614 | return -EINVAL; | ||
1615 | |||
1616 | /* Fill in the information about format */ | ||
1617 | *fmt = common->fmt; | ||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | /** | ||
1622 | * vpif_s_fmt_vid_cap() - Set FMT handler | ||
1623 | * @file: file ptr | ||
1624 | * @priv: file handle | ||
1625 | * @fmt: ptr to v4l2 format structure | ||
1626 | */ | ||
1627 | static int vpif_s_fmt_vid_cap(struct file *file, void *priv, | ||
1628 | struct v4l2_format *fmt) | ||
1629 | { | ||
1630 | struct vpif_fh *fh = priv; | ||
1631 | struct channel_obj *ch = fh->channel; | ||
1632 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1633 | struct v4l2_pix_format *pixfmt; | ||
1634 | int ret = 0; | ||
1635 | |||
1636 | vpif_dbg(2, debug, "%s\n", __func__); | ||
1637 | |||
1638 | /* If streaming is started, return error */ | ||
1639 | if (common->started) { | ||
1640 | vpif_dbg(1, debug, "Streaming is started\n"); | ||
1641 | return -EBUSY; | ||
1642 | } | ||
1643 | |||
1644 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || | ||
1645 | (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
1646 | if (!fh->initialized) { | ||
1647 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
1648 | return -EBUSY; | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | ret = v4l2_prio_check(&ch->prio, fh->prio); | ||
1653 | if (0 != ret) | ||
1654 | return ret; | ||
1655 | |||
1656 | fh->initialized = 1; | ||
1657 | |||
1658 | pixfmt = &fmt->fmt.pix; | ||
1659 | /* Check for valid field format */ | ||
1660 | ret = vpif_check_format(ch, pixfmt, 0); | ||
1661 | |||
1662 | if (ret) | ||
1663 | return ret; | ||
1664 | /* store the format in the channel object */ | ||
1665 | common->fmt = *fmt; | ||
1666 | return 0; | ||
1667 | } | ||
1668 | |||
1669 | /** | ||
1670 | * vpif_querycap() - QUERYCAP handler | ||
1671 | * @file: file ptr | ||
1672 | * @priv: file handle | ||
1673 | * @cap: ptr to v4l2_capability structure | ||
1674 | */ | ||
1675 | static int vpif_querycap(struct file *file, void *priv, | ||
1676 | struct v4l2_capability *cap) | ||
1677 | { | ||
1678 | struct vpif_capture_config *config = vpif_dev->platform_data; | ||
1679 | |||
1680 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
1681 | strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); | ||
1682 | strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); | ||
1683 | strlcpy(cap->card, config->card_name, sizeof(cap->card)); | ||
1684 | |||
1685 | return 0; | ||
1686 | } | ||
1687 | |||
1688 | /** | ||
1689 | * vpif_g_priority() - get priority handler | ||
1690 | * @file: file ptr | ||
1691 | * @priv: file handle | ||
1692 | * @prio: ptr to v4l2_priority structure | ||
1693 | */ | ||
1694 | static int vpif_g_priority(struct file *file, void *priv, | ||
1695 | enum v4l2_priority *prio) | ||
1696 | { | ||
1697 | struct vpif_fh *fh = priv; | ||
1698 | struct channel_obj *ch = fh->channel; | ||
1699 | |||
1700 | *prio = v4l2_prio_max(&ch->prio); | ||
1701 | |||
1702 | return 0; | ||
1703 | } | ||
1704 | |||
1705 | /** | ||
1706 | * vpif_s_priority() - set priority handler | ||
1707 | * @file: file ptr | ||
1708 | * @priv: file handle | ||
1709 | * @prio: ptr to v4l2_priority structure | ||
1710 | */ | ||
1711 | static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) | ||
1712 | { | ||
1713 | struct vpif_fh *fh = priv; | ||
1714 | struct channel_obj *ch = fh->channel; | ||
1715 | |||
1716 | return v4l2_prio_change(&ch->prio, &fh->prio, p); | ||
1717 | } | ||
1718 | |||
1719 | /** | ||
1720 | * vpif_cropcap() - cropcap handler | ||
1721 | * @file: file ptr | ||
1722 | * @priv: file handle | ||
1723 | * @crop: ptr to v4l2_cropcap structure | ||
1724 | */ | ||
1725 | static int vpif_cropcap(struct file *file, void *priv, | ||
1726 | struct v4l2_cropcap *crop) | ||
1727 | { | ||
1728 | struct vpif_fh *fh = priv; | ||
1729 | struct channel_obj *ch = fh->channel; | ||
1730 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1731 | |||
1732 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type) | ||
1733 | return -EINVAL; | ||
1734 | |||
1735 | crop->bounds.left = 0; | ||
1736 | crop->bounds.top = 0; | ||
1737 | crop->bounds.height = common->height; | ||
1738 | crop->bounds.width = common->width; | ||
1739 | crop->defrect = crop->bounds; | ||
1740 | return 0; | ||
1741 | } | ||
1742 | |||
1743 | /** | ||
1744 | * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler | ||
1745 | * @file: file ptr | ||
1746 | * @priv: file handle | ||
1747 | * @preset: input preset | ||
1748 | */ | ||
1749 | static int vpif_enum_dv_presets(struct file *file, void *priv, | ||
1750 | struct v4l2_dv_enum_preset *preset) | ||
1751 | { | ||
1752 | struct vpif_fh *fh = priv; | ||
1753 | struct channel_obj *ch = fh->channel; | ||
1754 | |||
1755 | return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], | ||
1756 | video, enum_dv_presets, preset); | ||
1757 | } | ||
1758 | |||
1759 | /** | ||
1760 | * vpif_query_dv_presets() - QUERY_DV_PRESET handler | ||
1761 | * @file: file ptr | ||
1762 | * @priv: file handle | ||
1763 | * @preset: input preset | ||
1764 | */ | ||
1765 | static int vpif_query_dv_preset(struct file *file, void *priv, | ||
1766 | struct v4l2_dv_preset *preset) | ||
1767 | { | ||
1768 | struct vpif_fh *fh = priv; | ||
1769 | struct channel_obj *ch = fh->channel; | ||
1770 | |||
1771 | return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], | ||
1772 | video, query_dv_preset, preset); | ||
1773 | } | ||
1774 | /** | ||
1775 | * vpif_s_dv_presets() - S_DV_PRESETS handler | ||
1776 | * @file: file ptr | ||
1777 | * @priv: file handle | ||
1778 | * @preset: input preset | ||
1779 | */ | ||
1780 | static int vpif_s_dv_preset(struct file *file, void *priv, | ||
1781 | struct v4l2_dv_preset *preset) | ||
1782 | { | ||
1783 | struct vpif_fh *fh = priv; | ||
1784 | struct channel_obj *ch = fh->channel; | ||
1785 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1786 | int ret = 0; | ||
1787 | |||
1788 | if (common->started) { | ||
1789 | vpif_dbg(1, debug, "streaming in progress\n"); | ||
1790 | return -EBUSY; | ||
1791 | } | ||
1792 | |||
1793 | if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) || | ||
1794 | (VPIF_CHANNEL1_VIDEO == ch->channel_id)) { | ||
1795 | if (!fh->initialized) { | ||
1796 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
1797 | return -EBUSY; | ||
1798 | } | ||
1799 | } | ||
1800 | |||
1801 | ret = v4l2_prio_check(&ch->prio, fh->prio); | ||
1802 | if (ret) | ||
1803 | return ret; | ||
1804 | |||
1805 | fh->initialized = 1; | ||
1806 | |||
1807 | /* Call encoder subdevice function to set the standard */ | ||
1808 | if (mutex_lock_interruptible(&common->lock)) | ||
1809 | return -ERESTARTSYS; | ||
1810 | |||
1811 | ch->video.dv_preset = preset->preset; | ||
1812 | ch->video.stdid = V4L2_STD_UNKNOWN; | ||
1813 | memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); | ||
1814 | |||
1815 | /* Get the information about the standard */ | ||
1816 | if (vpif_update_std_info(ch)) { | ||
1817 | vpif_dbg(1, debug, "Error getting the standard info\n"); | ||
1818 | ret = -EINVAL; | ||
1819 | } else { | ||
1820 | /* Configure the default format information */ | ||
1821 | vpif_config_format(ch); | ||
1822 | |||
1823 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], | ||
1824 | video, s_dv_preset, preset); | ||
1825 | } | ||
1826 | |||
1827 | mutex_unlock(&common->lock); | ||
1828 | |||
1829 | return ret; | ||
1830 | } | ||
1831 | /** | ||
1832 | * vpif_g_dv_presets() - G_DV_PRESETS handler | ||
1833 | * @file: file ptr | ||
1834 | * @priv: file handle | ||
1835 | * @preset: input preset | ||
1836 | */ | ||
1837 | static int vpif_g_dv_preset(struct file *file, void *priv, | ||
1838 | struct v4l2_dv_preset *preset) | ||
1839 | { | ||
1840 | struct vpif_fh *fh = priv; | ||
1841 | struct channel_obj *ch = fh->channel; | ||
1842 | |||
1843 | preset->preset = ch->video.dv_preset; | ||
1844 | |||
1845 | return 0; | ||
1846 | } | ||
1847 | |||
1848 | /** | ||
1849 | * vpif_s_dv_timings() - S_DV_TIMINGS handler | ||
1850 | * @file: file ptr | ||
1851 | * @priv: file handle | ||
1852 | * @timings: digital video timings | ||
1853 | */ | ||
1854 | static int vpif_s_dv_timings(struct file *file, void *priv, | ||
1855 | struct v4l2_dv_timings *timings) | ||
1856 | { | ||
1857 | struct vpif_fh *fh = priv; | ||
1858 | struct channel_obj *ch = fh->channel; | ||
1859 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
1860 | struct vpif_channel_config_params *std_info = &vpifparams->std_info; | ||
1861 | struct video_obj *vid_ch = &ch->video; | ||
1862 | struct v4l2_bt_timings *bt = &vid_ch->bt_timings; | ||
1863 | int ret; | ||
1864 | |||
1865 | if (timings->type != V4L2_DV_BT_656_1120) { | ||
1866 | vpif_dbg(2, debug, "Timing type not defined\n"); | ||
1867 | return -EINVAL; | ||
1868 | } | ||
1869 | |||
1870 | /* Configure subdevice timings, if any */ | ||
1871 | ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], | ||
1872 | video, s_dv_timings, timings); | ||
1873 | if (ret == -ENOIOCTLCMD) { | ||
1874 | vpif_dbg(2, debug, "Custom DV timings not supported by " | ||
1875 | "subdevice\n"); | ||
1876 | return -EINVAL; | ||
1877 | } | ||
1878 | if (ret < 0) { | ||
1879 | vpif_dbg(2, debug, "Error setting custom DV timings\n"); | ||
1880 | return ret; | ||
1881 | } | ||
1882 | |||
1883 | if (!(timings->bt.width && timings->bt.height && | ||
1884 | (timings->bt.hbackporch || | ||
1885 | timings->bt.hfrontporch || | ||
1886 | timings->bt.hsync) && | ||
1887 | timings->bt.vfrontporch && | ||
1888 | (timings->bt.vbackporch || | ||
1889 | timings->bt.vsync))) { | ||
1890 | vpif_dbg(2, debug, "Timings for width, height, " | ||
1891 | "horizontal back porch, horizontal sync, " | ||
1892 | "horizontal front porch, vertical back porch, " | ||
1893 | "vertical sync and vertical back porch " | ||
1894 | "must be defined\n"); | ||
1895 | return -EINVAL; | ||
1896 | } | ||
1897 | |||
1898 | *bt = timings->bt; | ||
1899 | |||
1900 | /* Configure video port timings */ | ||
1901 | |||
1902 | std_info->eav2sav = bt->hbackporch + bt->hfrontporch + | ||
1903 | bt->hsync - 8; | ||
1904 | std_info->sav2eav = bt->width; | ||
1905 | |||
1906 | std_info->l1 = 1; | ||
1907 | std_info->l3 = bt->vsync + bt->vbackporch + 1; | ||
1908 | |||
1909 | if (bt->interlaced) { | ||
1910 | if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { | ||
1911 | std_info->vsize = bt->height * 2 + | ||
1912 | bt->vfrontporch + bt->vsync + bt->vbackporch + | ||
1913 | bt->il_vfrontporch + bt->il_vsync + | ||
1914 | bt->il_vbackporch; | ||
1915 | std_info->l5 = std_info->vsize/2 - | ||
1916 | (bt->vfrontporch - 1); | ||
1917 | std_info->l7 = std_info->vsize/2 + 1; | ||
1918 | std_info->l9 = std_info->l7 + bt->il_vsync + | ||
1919 | bt->il_vbackporch + 1; | ||
1920 | std_info->l11 = std_info->vsize - | ||
1921 | (bt->il_vfrontporch - 1); | ||
1922 | } else { | ||
1923 | vpif_dbg(2, debug, "Required timing values for " | ||
1924 | "interlaced BT format missing\n"); | ||
1925 | return -EINVAL; | ||
1926 | } | ||
1927 | } else { | ||
1928 | std_info->vsize = bt->height + bt->vfrontporch + | ||
1929 | bt->vsync + bt->vbackporch; | ||
1930 | std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); | ||
1931 | } | ||
1932 | strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME); | ||
1933 | std_info->width = bt->width; | ||
1934 | std_info->height = bt->height; | ||
1935 | std_info->frm_fmt = bt->interlaced ? 0 : 1; | ||
1936 | std_info->ycmux_mode = 0; | ||
1937 | std_info->capture_format = 0; | ||
1938 | std_info->vbi_supported = 0; | ||
1939 | std_info->hd_sd = 1; | ||
1940 | std_info->stdid = 0; | ||
1941 | std_info->dv_preset = V4L2_DV_INVALID; | ||
1942 | |||
1943 | vid_ch->stdid = 0; | ||
1944 | vid_ch->dv_preset = V4L2_DV_INVALID; | ||
1945 | return 0; | ||
1946 | } | ||
1947 | |||
1948 | /** | ||
1949 | * vpif_g_dv_timings() - G_DV_TIMINGS handler | ||
1950 | * @file: file ptr | ||
1951 | * @priv: file handle | ||
1952 | * @timings: digital video timings | ||
1953 | */ | ||
1954 | static int vpif_g_dv_timings(struct file *file, void *priv, | ||
1955 | struct v4l2_dv_timings *timings) | ||
1956 | { | ||
1957 | struct vpif_fh *fh = priv; | ||
1958 | struct channel_obj *ch = fh->channel; | ||
1959 | struct video_obj *vid_ch = &ch->video; | ||
1960 | struct v4l2_bt_timings *bt = &vid_ch->bt_timings; | ||
1961 | |||
1962 | timings->bt = *bt; | ||
1963 | |||
1964 | return 0; | ||
1965 | } | ||
1966 | |||
1967 | /* | ||
1968 | * vpif_g_chip_ident() - Identify the chip | ||
1969 | * @file: file ptr | ||
1970 | * @priv: file handle | ||
1971 | * @chip: chip identity | ||
1972 | * | ||
1973 | * Returns zero or -EINVAL if read operations fails. | ||
1974 | */ | ||
1975 | static int vpif_g_chip_ident(struct file *file, void *priv, | ||
1976 | struct v4l2_dbg_chip_ident *chip) | ||
1977 | { | ||
1978 | chip->ident = V4L2_IDENT_NONE; | ||
1979 | chip->revision = 0; | ||
1980 | if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && | ||
1981 | chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { | ||
1982 | vpif_dbg(2, debug, "match_type is invalid.\n"); | ||
1983 | return -EINVAL; | ||
1984 | } | ||
1985 | |||
1986 | return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, | ||
1987 | g_chip_ident, chip); | ||
1988 | } | ||
1989 | |||
1990 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1991 | /* | ||
1992 | * vpif_dbg_g_register() - Read register | ||
1993 | * @file: file ptr | ||
1994 | * @priv: file handle | ||
1995 | * @reg: register to be read | ||
1996 | * | ||
1997 | * Debugging only | ||
1998 | * Returns zero or -EINVAL if read operations fails. | ||
1999 | */ | ||
2000 | static int vpif_dbg_g_register(struct file *file, void *priv, | ||
2001 | struct v4l2_dbg_register *reg){ | ||
2002 | struct vpif_fh *fh = priv; | ||
2003 | struct channel_obj *ch = fh->channel; | ||
2004 | |||
2005 | return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, | ||
2006 | g_register, reg); | ||
2007 | } | ||
2008 | |||
2009 | /* | ||
2010 | * vpif_dbg_s_register() - Write to register | ||
2011 | * @file: file ptr | ||
2012 | * @priv: file handle | ||
2013 | * @reg: register to be modified | ||
2014 | * | ||
2015 | * Debugging only | ||
2016 | * Returns zero or -EINVAL if write operations fails. | ||
2017 | */ | ||
2018 | static int vpif_dbg_s_register(struct file *file, void *priv, | ||
2019 | struct v4l2_dbg_register *reg){ | ||
2020 | struct vpif_fh *fh = priv; | ||
2021 | struct channel_obj *ch = fh->channel; | ||
2022 | |||
2023 | return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, | ||
2024 | s_register, reg); | ||
2025 | } | ||
2026 | #endif | ||
2027 | |||
2028 | /* | ||
2029 | * vpif_log_status() - Status information | ||
2030 | * @file: file ptr | ||
2031 | * @priv: file handle | ||
2032 | * | ||
2033 | * Returns zero. | ||
2034 | */ | ||
2035 | static int vpif_log_status(struct file *filep, void *priv) | ||
2036 | { | ||
2037 | /* status for sub devices */ | ||
2038 | v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); | ||
2039 | |||
2040 | return 0; | ||
2041 | } | ||
2042 | |||
2043 | /* vpif capture ioctl operations */ | ||
2044 | static const struct v4l2_ioctl_ops vpif_ioctl_ops = { | ||
2045 | .vidioc_querycap = vpif_querycap, | ||
2046 | .vidioc_g_priority = vpif_g_priority, | ||
2047 | .vidioc_s_priority = vpif_s_priority, | ||
2048 | .vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap, | ||
2049 | .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap, | ||
2050 | .vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap, | ||
2051 | .vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap, | ||
2052 | .vidioc_enum_input = vpif_enum_input, | ||
2053 | .vidioc_s_input = vpif_s_input, | ||
2054 | .vidioc_g_input = vpif_g_input, | ||
2055 | .vidioc_reqbufs = vpif_reqbufs, | ||
2056 | .vidioc_querybuf = vpif_querybuf, | ||
2057 | .vidioc_querystd = vpif_querystd, | ||
2058 | .vidioc_s_std = vpif_s_std, | ||
2059 | .vidioc_g_std = vpif_g_std, | ||
2060 | .vidioc_qbuf = vpif_qbuf, | ||
2061 | .vidioc_dqbuf = vpif_dqbuf, | ||
2062 | .vidioc_streamon = vpif_streamon, | ||
2063 | .vidioc_streamoff = vpif_streamoff, | ||
2064 | .vidioc_cropcap = vpif_cropcap, | ||
2065 | .vidioc_enum_dv_presets = vpif_enum_dv_presets, | ||
2066 | .vidioc_s_dv_preset = vpif_s_dv_preset, | ||
2067 | .vidioc_g_dv_preset = vpif_g_dv_preset, | ||
2068 | .vidioc_query_dv_preset = vpif_query_dv_preset, | ||
2069 | .vidioc_s_dv_timings = vpif_s_dv_timings, | ||
2070 | .vidioc_g_dv_timings = vpif_g_dv_timings, | ||
2071 | .vidioc_g_chip_ident = vpif_g_chip_ident, | ||
2072 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
2073 | .vidioc_g_register = vpif_dbg_g_register, | ||
2074 | .vidioc_s_register = vpif_dbg_s_register, | ||
2075 | #endif | ||
2076 | .vidioc_log_status = vpif_log_status, | ||
2077 | }; | ||
2078 | |||
2079 | /* vpif file operations */ | ||
2080 | static struct v4l2_file_operations vpif_fops = { | ||
2081 | .owner = THIS_MODULE, | ||
2082 | .open = vpif_open, | ||
2083 | .release = vpif_release, | ||
2084 | .unlocked_ioctl = video_ioctl2, | ||
2085 | .mmap = vpif_mmap, | ||
2086 | .poll = vpif_poll | ||
2087 | }; | ||
2088 | |||
2089 | /* vpif video template */ | ||
2090 | static struct video_device vpif_video_template = { | ||
2091 | .name = "vpif", | ||
2092 | .fops = &vpif_fops, | ||
2093 | .minor = -1, | ||
2094 | .ioctl_ops = &vpif_ioctl_ops, | ||
2095 | }; | ||
2096 | |||
2097 | /** | ||
2098 | * initialize_vpif() - Initialize vpif data structures | ||
2099 | * | ||
2100 | * Allocate memory for data structures and initialize them | ||
2101 | */ | ||
2102 | static int initialize_vpif(void) | ||
2103 | { | ||
2104 | int err = 0, i, j; | ||
2105 | int free_channel_objects_index; | ||
2106 | |||
2107 | /* Default number of buffers should be 3 */ | ||
2108 | if ((ch0_numbuffers > 0) && | ||
2109 | (ch0_numbuffers < config_params.min_numbuffers)) | ||
2110 | ch0_numbuffers = config_params.min_numbuffers; | ||
2111 | if ((ch1_numbuffers > 0) && | ||
2112 | (ch1_numbuffers < config_params.min_numbuffers)) | ||
2113 | ch1_numbuffers = config_params.min_numbuffers; | ||
2114 | |||
2115 | /* Set buffer size to min buffers size if it is invalid */ | ||
2116 | if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]) | ||
2117 | ch0_bufsize = | ||
2118 | config_params.min_bufsize[VPIF_CHANNEL0_VIDEO]; | ||
2119 | if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]) | ||
2120 | ch1_bufsize = | ||
2121 | config_params.min_bufsize[VPIF_CHANNEL1_VIDEO]; | ||
2122 | |||
2123 | config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers; | ||
2124 | config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers; | ||
2125 | if (ch0_numbuffers) { | ||
2126 | config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO] | ||
2127 | = ch0_bufsize; | ||
2128 | } | ||
2129 | if (ch1_numbuffers) { | ||
2130 | config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO] | ||
2131 | = ch1_bufsize; | ||
2132 | } | ||
2133 | |||
2134 | /* Allocate memory for six channel objects */ | ||
2135 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
2136 | vpif_obj.dev[i] = | ||
2137 | kzalloc(sizeof(*vpif_obj.dev[i]), GFP_KERNEL); | ||
2138 | /* If memory allocation fails, return error */ | ||
2139 | if (!vpif_obj.dev[i]) { | ||
2140 | free_channel_objects_index = i; | ||
2141 | err = -ENOMEM; | ||
2142 | goto vpif_init_free_channel_objects; | ||
2143 | } | ||
2144 | } | ||
2145 | return 0; | ||
2146 | |||
2147 | vpif_init_free_channel_objects: | ||
2148 | for (j = 0; j < free_channel_objects_index; j++) | ||
2149 | kfree(vpif_obj.dev[j]); | ||
2150 | return err; | ||
2151 | } | ||
2152 | |||
2153 | /** | ||
2154 | * vpif_probe : This function probes the vpif capture driver | ||
2155 | * @pdev: platform device pointer | ||
2156 | * | ||
2157 | * This creates device entries by register itself to the V4L2 driver and | ||
2158 | * initializes fields of each channel objects | ||
2159 | */ | ||
2160 | static __init int vpif_probe(struct platform_device *pdev) | ||
2161 | { | ||
2162 | struct vpif_subdev_info *subdevdata; | ||
2163 | struct vpif_capture_config *config; | ||
2164 | int i, j, k, m, q, err; | ||
2165 | struct i2c_adapter *i2c_adap; | ||
2166 | struct channel_obj *ch; | ||
2167 | struct common_obj *common; | ||
2168 | struct video_device *vfd; | ||
2169 | struct resource *res; | ||
2170 | int subdev_count; | ||
2171 | |||
2172 | vpif_dev = &pdev->dev; | ||
2173 | |||
2174 | err = initialize_vpif(); | ||
2175 | if (err) { | ||
2176 | v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); | ||
2177 | return err; | ||
2178 | } | ||
2179 | |||
2180 | k = 0; | ||
2181 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { | ||
2182 | for (i = res->start; i <= res->end; i++) { | ||
2183 | if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, | ||
2184 | "DM646x_Capture", | ||
2185 | (void *)(&vpif_obj.dev[k]->channel_id))) { | ||
2186 | err = -EBUSY; | ||
2187 | i--; | ||
2188 | goto vpif_int_err; | ||
2189 | } | ||
2190 | } | ||
2191 | k++; | ||
2192 | } | ||
2193 | |||
2194 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
2195 | /* Get the pointer to the channel object */ | ||
2196 | ch = vpif_obj.dev[i]; | ||
2197 | /* Allocate memory for video device */ | ||
2198 | vfd = video_device_alloc(); | ||
2199 | if (NULL == vfd) { | ||
2200 | for (j = 0; j < i; j++) { | ||
2201 | ch = vpif_obj.dev[j]; | ||
2202 | video_device_release(ch->video_dev); | ||
2203 | } | ||
2204 | err = -ENOMEM; | ||
2205 | goto vpif_dev_alloc_err; | ||
2206 | } | ||
2207 | |||
2208 | /* Initialize field of video device */ | ||
2209 | *vfd = vpif_video_template; | ||
2210 | vfd->v4l2_dev = &vpif_obj.v4l2_dev; | ||
2211 | vfd->release = video_device_release; | ||
2212 | snprintf(vfd->name, sizeof(vfd->name), | ||
2213 | "DM646x_VPIFCapture_DRIVER_V%s", | ||
2214 | VPIF_CAPTURE_VERSION); | ||
2215 | /* Set video_dev to the video device */ | ||
2216 | ch->video_dev = vfd; | ||
2217 | } | ||
2218 | |||
2219 | for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { | ||
2220 | ch = vpif_obj.dev[j]; | ||
2221 | ch->channel_id = j; | ||
2222 | common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
2223 | spin_lock_init(&common->irqlock); | ||
2224 | mutex_init(&common->lock); | ||
2225 | ch->video_dev->lock = &common->lock; | ||
2226 | /* Initialize prio member of channel object */ | ||
2227 | v4l2_prio_init(&ch->prio); | ||
2228 | err = video_register_device(ch->video_dev, | ||
2229 | VFL_TYPE_GRABBER, (j ? 1 : 0)); | ||
2230 | if (err) | ||
2231 | goto probe_out; | ||
2232 | |||
2233 | video_set_drvdata(ch->video_dev, ch); | ||
2234 | |||
2235 | } | ||
2236 | |||
2237 | i2c_adap = i2c_get_adapter(1); | ||
2238 | config = pdev->dev.platform_data; | ||
2239 | |||
2240 | subdev_count = config->subdev_count; | ||
2241 | vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, | ||
2242 | GFP_KERNEL); | ||
2243 | if (vpif_obj.sd == NULL) { | ||
2244 | vpif_err("unable to allocate memory for subdevice pointers\n"); | ||
2245 | err = -ENOMEM; | ||
2246 | goto probe_out; | ||
2247 | } | ||
2248 | |||
2249 | err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); | ||
2250 | if (err) { | ||
2251 | v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); | ||
2252 | goto probe_subdev_out; | ||
2253 | } | ||
2254 | |||
2255 | for (i = 0; i < subdev_count; i++) { | ||
2256 | subdevdata = &config->subdev_info[i]; | ||
2257 | vpif_obj.sd[i] = | ||
2258 | v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, | ||
2259 | i2c_adap, | ||
2260 | &subdevdata->board_info, | ||
2261 | NULL); | ||
2262 | |||
2263 | if (!vpif_obj.sd[i]) { | ||
2264 | vpif_err("Error registering v4l2 subdevice\n"); | ||
2265 | goto probe_subdev_out; | ||
2266 | } | ||
2267 | v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", | ||
2268 | subdevdata->name); | ||
2269 | |||
2270 | if (vpif_obj.sd[i]) | ||
2271 | vpif_obj.sd[i]->grp_id = 1 << i; | ||
2272 | } | ||
2273 | |||
2274 | v4l2_info(&vpif_obj.v4l2_dev, | ||
2275 | "DM646x VPIF capture driver initialized\n"); | ||
2276 | return 0; | ||
2277 | |||
2278 | probe_subdev_out: | ||
2279 | /* free sub devices memory */ | ||
2280 | kfree(vpif_obj.sd); | ||
2281 | |||
2282 | j = VPIF_CAPTURE_MAX_DEVICES; | ||
2283 | probe_out: | ||
2284 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
2285 | for (k = 0; k < j; k++) { | ||
2286 | /* Get the pointer to the channel object */ | ||
2287 | ch = vpif_obj.dev[k]; | ||
2288 | /* Unregister video device */ | ||
2289 | video_unregister_device(ch->video_dev); | ||
2290 | } | ||
2291 | |||
2292 | vpif_dev_alloc_err: | ||
2293 | k = VPIF_CAPTURE_MAX_DEVICES-1; | ||
2294 | res = platform_get_resource(pdev, IORESOURCE_IRQ, k); | ||
2295 | i = res->end; | ||
2296 | |||
2297 | vpif_int_err: | ||
2298 | for (q = k; q >= 0; q--) { | ||
2299 | for (m = i; m >= (int)res->start; m--) | ||
2300 | free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); | ||
2301 | |||
2302 | res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); | ||
2303 | if (res) | ||
2304 | i = res->end; | ||
2305 | } | ||
2306 | return err; | ||
2307 | } | ||
2308 | |||
2309 | /** | ||
2310 | * vpif_remove() - driver remove handler | ||
2311 | * @device: ptr to platform device structure | ||
2312 | * | ||
2313 | * The vidoe device is unregistered | ||
2314 | */ | ||
2315 | static int vpif_remove(struct platform_device *device) | ||
2316 | { | ||
2317 | int i; | ||
2318 | struct channel_obj *ch; | ||
2319 | |||
2320 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
2321 | |||
2322 | /* un-register device */ | ||
2323 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { | ||
2324 | /* Get the pointer to the channel object */ | ||
2325 | ch = vpif_obj.dev[i]; | ||
2326 | /* Unregister video device */ | ||
2327 | video_unregister_device(ch->video_dev); | ||
2328 | } | ||
2329 | return 0; | ||
2330 | } | ||
2331 | |||
2332 | /** | ||
2333 | * vpif_suspend: vpif device suspend | ||
2334 | * | ||
2335 | * TODO: Add suspend code here | ||
2336 | */ | ||
2337 | static int | ||
2338 | vpif_suspend(struct device *dev) | ||
2339 | { | ||
2340 | return -1; | ||
2341 | } | ||
2342 | |||
2343 | /** | ||
2344 | * vpif_resume: vpif device suspend | ||
2345 | * | ||
2346 | * TODO: Add resume code here | ||
2347 | */ | ||
2348 | static int | ||
2349 | vpif_resume(struct device *dev) | ||
2350 | { | ||
2351 | return -1; | ||
2352 | } | ||
2353 | |||
2354 | static const struct dev_pm_ops vpif_dev_pm_ops = { | ||
2355 | .suspend = vpif_suspend, | ||
2356 | .resume = vpif_resume, | ||
2357 | }; | ||
2358 | |||
2359 | static __refdata struct platform_driver vpif_driver = { | ||
2360 | .driver = { | ||
2361 | .name = "vpif_capture", | ||
2362 | .owner = THIS_MODULE, | ||
2363 | .pm = &vpif_dev_pm_ops, | ||
2364 | }, | ||
2365 | .probe = vpif_probe, | ||
2366 | .remove = vpif_remove, | ||
2367 | }; | ||
2368 | |||
2369 | /** | ||
2370 | * vpif_init: initialize the vpif driver | ||
2371 | * | ||
2372 | * This function registers device and driver to the kernel, requests irq | ||
2373 | * handler and allocates memory | ||
2374 | * for channel objects | ||
2375 | */ | ||
2376 | static __init int vpif_init(void) | ||
2377 | { | ||
2378 | return platform_driver_register(&vpif_driver); | ||
2379 | } | ||
2380 | |||
2381 | /** | ||
2382 | * vpif_cleanup : This function clean up the vpif capture resources | ||
2383 | * | ||
2384 | * This will un-registers device and driver to the kernel, frees | ||
2385 | * requested irq handler and de-allocates memory allocated for channel | ||
2386 | * objects. | ||
2387 | */ | ||
2388 | static void vpif_cleanup(void) | ||
2389 | { | ||
2390 | struct platform_device *pdev; | ||
2391 | struct resource *res; | ||
2392 | int irq_num; | ||
2393 | int i = 0; | ||
2394 | |||
2395 | pdev = container_of(vpif_dev, struct platform_device, dev); | ||
2396 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { | ||
2397 | for (irq_num = res->start; irq_num <= res->end; irq_num++) | ||
2398 | free_irq(irq_num, | ||
2399 | (void *)(&vpif_obj.dev[i]->channel_id)); | ||
2400 | i++; | ||
2401 | } | ||
2402 | |||
2403 | platform_driver_unregister(&vpif_driver); | ||
2404 | |||
2405 | kfree(vpif_obj.sd); | ||
2406 | for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) | ||
2407 | kfree(vpif_obj.dev[i]); | ||
2408 | } | ||
2409 | |||
2410 | /* Function for module initialization and cleanup */ | ||
2411 | module_init(vpif_init); | ||
2412 | module_exit(vpif_cleanup); | ||
diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h new file mode 100644 index 00000000000..064550f5ce4 --- /dev/null +++ b/drivers/media/video/davinci/vpif_capture.h | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Texas Instruments Inc | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef VPIF_CAPTURE_H | ||
20 | #define VPIF_CAPTURE_H | ||
21 | |||
22 | #ifdef __KERNEL__ | ||
23 | |||
24 | /* Header files */ | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <media/v4l2-common.h> | ||
27 | #include <media/v4l2-device.h> | ||
28 | #include <media/videobuf-core.h> | ||
29 | #include <media/videobuf-dma-contig.h> | ||
30 | #include <mach/dm646x.h> | ||
31 | |||
32 | #include "vpif.h" | ||
33 | |||
34 | /* Macros */ | ||
35 | #define VPIF_CAPTURE_VERSION "0.0.2" | ||
36 | |||
37 | #define VPIF_VALID_FIELD(field) (((V4L2_FIELD_ANY == field) || \ | ||
38 | (V4L2_FIELD_NONE == field)) || \ | ||
39 | (((V4L2_FIELD_INTERLACED == field) || \ | ||
40 | (V4L2_FIELD_SEQ_TB == field)) || \ | ||
41 | (V4L2_FIELD_SEQ_BT == field))) | ||
42 | |||
43 | #define VPIF_CAPTURE_MAX_DEVICES 2 | ||
44 | #define VPIF_VIDEO_INDEX 0 | ||
45 | #define VPIF_NUMBER_OF_OBJECTS 1 | ||
46 | |||
47 | /* Enumerated data type to give id to each device per channel */ | ||
48 | enum vpif_channel_id { | ||
49 | VPIF_CHANNEL0_VIDEO = 0, | ||
50 | VPIF_CHANNEL1_VIDEO, | ||
51 | }; | ||
52 | |||
53 | struct video_obj { | ||
54 | enum v4l2_field buf_field; | ||
55 | /* Currently selected or default standard */ | ||
56 | v4l2_std_id stdid; | ||
57 | u32 dv_preset; | ||
58 | struct v4l2_bt_timings bt_timings; | ||
59 | /* This is to track the last input that is passed to application */ | ||
60 | u32 input_idx; | ||
61 | }; | ||
62 | |||
63 | struct common_obj { | ||
64 | /* Pointer pointing to current v4l2_buffer */ | ||
65 | struct videobuf_buffer *cur_frm; | ||
66 | /* Pointer pointing to current v4l2_buffer */ | ||
67 | struct videobuf_buffer *next_frm; | ||
68 | /* | ||
69 | * This field keeps track of type of buffer exchange mechanism | ||
70 | * user has selected | ||
71 | */ | ||
72 | enum v4l2_memory memory; | ||
73 | /* Used to store pixel format */ | ||
74 | struct v4l2_format fmt; | ||
75 | /* Buffer queue used in video-buf */ | ||
76 | struct videobuf_queue buffer_queue; | ||
77 | /* Queue of filled frames */ | ||
78 | struct list_head dma_queue; | ||
79 | /* Used in video-buf */ | ||
80 | spinlock_t irqlock; | ||
81 | /* lock used to access this structure */ | ||
82 | struct mutex lock; | ||
83 | /* number of users performing IO */ | ||
84 | u32 io_usrs; | ||
85 | /* Indicates whether streaming started */ | ||
86 | u8 started; | ||
87 | /* Function pointer to set the addresses */ | ||
88 | void (*set_addr) (unsigned long, unsigned long, unsigned long, | ||
89 | unsigned long); | ||
90 | /* offset where Y top starts from the starting of the buffer */ | ||
91 | u32 ytop_off; | ||
92 | /* offset where Y bottom starts from the starting of the buffer */ | ||
93 | u32 ybtm_off; | ||
94 | /* offset where C top starts from the starting of the buffer */ | ||
95 | u32 ctop_off; | ||
96 | /* offset where C bottom starts from the starting of the buffer */ | ||
97 | u32 cbtm_off; | ||
98 | /* Indicates width of the image data */ | ||
99 | u32 width; | ||
100 | /* Indicates height of the image data */ | ||
101 | u32 height; | ||
102 | }; | ||
103 | |||
104 | struct channel_obj { | ||
105 | /* Identifies video device for this channel */ | ||
106 | struct video_device *video_dev; | ||
107 | /* Used to keep track of state of the priority */ | ||
108 | struct v4l2_prio_state prio; | ||
109 | /* number of open instances of the channel */ | ||
110 | int usrs; | ||
111 | /* Indicates id of the field which is being displayed */ | ||
112 | u32 field_id; | ||
113 | /* flag to indicate whether decoder is initialized */ | ||
114 | u8 initialized; | ||
115 | /* Identifies channel */ | ||
116 | enum vpif_channel_id channel_id; | ||
117 | /* index into sd table */ | ||
118 | int curr_sd_index; | ||
119 | /* ptr to current sub device information */ | ||
120 | struct vpif_subdev_info *curr_subdev_info; | ||
121 | /* vpif configuration params */ | ||
122 | struct vpif_params vpifparams; | ||
123 | /* common object array */ | ||
124 | struct common_obj common[VPIF_NUMBER_OF_OBJECTS]; | ||
125 | /* video object */ | ||
126 | struct video_obj video; | ||
127 | }; | ||
128 | |||
129 | /* File handle structure */ | ||
130 | struct vpif_fh { | ||
131 | /* pointer to channel object for opened device */ | ||
132 | struct channel_obj *channel; | ||
133 | /* Indicates whether this file handle is doing IO */ | ||
134 | u8 io_allowed[VPIF_NUMBER_OF_OBJECTS]; | ||
135 | /* Used to keep track priority of this instance */ | ||
136 | enum v4l2_priority prio; | ||
137 | /* Used to indicate channel is initialize or not */ | ||
138 | u8 initialized; | ||
139 | }; | ||
140 | |||
141 | struct vpif_device { | ||
142 | struct v4l2_device v4l2_dev; | ||
143 | struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS]; | ||
144 | struct v4l2_subdev **sd; | ||
145 | }; | ||
146 | |||
147 | struct vpif_config_params { | ||
148 | u8 min_numbuffers; | ||
149 | u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS]; | ||
150 | s8 device_type; | ||
151 | u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; | ||
152 | u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; | ||
153 | u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; | ||
154 | u8 max_device_type; | ||
155 | }; | ||
156 | /* Struct which keeps track of the line numbers for the sliced vbi service */ | ||
157 | struct vpif_service_line { | ||
158 | u16 service_id; | ||
159 | u16 service_line[2]; | ||
160 | }; | ||
161 | #endif /* End of __KERNEL__ */ | ||
162 | #endif /* VPIF_CAPTURE_H */ | ||
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c new file mode 100644 index 00000000000..286f0291004 --- /dev/null +++ b/drivers/media/video/davinci/vpif_display.c | |||
@@ -0,0 +1,1914 @@ | |||
1 | /* | ||
2 | * vpif-display - VPIF display driver | ||
3 | * Display driver for TI DaVinci VPIF | ||
4 | * | ||
5 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation version 2. | ||
10 | * | ||
11 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
12 | * kind, whether express or implied; without even the implied warranty | ||
13 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/io.h> | ||
32 | #include <linux/slab.h> | ||
33 | |||
34 | #include <asm/irq.h> | ||
35 | #include <asm/page.h> | ||
36 | |||
37 | #include <media/adv7343.h> | ||
38 | #include <media/v4l2-device.h> | ||
39 | #include <media/v4l2-ioctl.h> | ||
40 | #include <media/v4l2-chip-ident.h> | ||
41 | |||
42 | #include <mach/dm646x.h> | ||
43 | |||
44 | #include "vpif_display.h" | ||
45 | #include "vpif.h" | ||
46 | |||
47 | MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); | ||
48 | MODULE_LICENSE("GPL"); | ||
49 | MODULE_VERSION(VPIF_DISPLAY_VERSION); | ||
50 | |||
51 | #define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) | ||
52 | |||
53 | #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) | ||
54 | #define vpif_dbg(level, debug, fmt, arg...) \ | ||
55 | v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg) | ||
56 | |||
57 | static int debug = 1; | ||
58 | static u32 ch2_numbuffers = 3; | ||
59 | static u32 ch3_numbuffers = 3; | ||
60 | static u32 ch2_bufsize = 1920 * 1080 * 2; | ||
61 | static u32 ch3_bufsize = 720 * 576 * 2; | ||
62 | |||
63 | module_param(debug, int, 0644); | ||
64 | module_param(ch2_numbuffers, uint, S_IRUGO); | ||
65 | module_param(ch3_numbuffers, uint, S_IRUGO); | ||
66 | module_param(ch2_bufsize, uint, S_IRUGO); | ||
67 | module_param(ch3_bufsize, uint, S_IRUGO); | ||
68 | |||
69 | MODULE_PARM_DESC(debug, "Debug level 0-1"); | ||
70 | MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)"); | ||
71 | MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)"); | ||
72 | MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)"); | ||
73 | MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)"); | ||
74 | |||
75 | static struct vpif_config_params config_params = { | ||
76 | .min_numbuffers = 3, | ||
77 | .numbuffers[0] = 3, | ||
78 | .numbuffers[1] = 3, | ||
79 | .min_bufsize[0] = 720 * 480 * 2, | ||
80 | .min_bufsize[1] = 720 * 480 * 2, | ||
81 | .channel_bufsize[0] = 1920 * 1080 * 2, | ||
82 | .channel_bufsize[1] = 720 * 576 * 2, | ||
83 | }; | ||
84 | |||
85 | static struct vpif_device vpif_obj = { {NULL} }; | ||
86 | static struct device *vpif_dev; | ||
87 | |||
88 | /* | ||
89 | * vpif_uservirt_to_phys: This function is used to convert user | ||
90 | * space virtual address to physical address. | ||
91 | */ | ||
92 | static u32 vpif_uservirt_to_phys(u32 virtp) | ||
93 | { | ||
94 | struct mm_struct *mm = current->mm; | ||
95 | unsigned long physp = 0; | ||
96 | struct vm_area_struct *vma; | ||
97 | |||
98 | vma = find_vma(mm, virtp); | ||
99 | |||
100 | /* For kernel direct-mapped memory, take the easy way */ | ||
101 | if (virtp >= PAGE_OFFSET) { | ||
102 | physp = virt_to_phys((void *)virtp); | ||
103 | } else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { | ||
104 | /* this will catch, kernel-allocated, mmaped-to-usermode addr */ | ||
105 | physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start); | ||
106 | } else { | ||
107 | /* otherwise, use get_user_pages() for general userland pages */ | ||
108 | int res, nr_pages = 1; | ||
109 | struct page *pages; | ||
110 | down_read(¤t->mm->mmap_sem); | ||
111 | |||
112 | res = get_user_pages(current, current->mm, | ||
113 | virtp, nr_pages, 1, 0, &pages, NULL); | ||
114 | up_read(¤t->mm->mmap_sem); | ||
115 | |||
116 | if (res == nr_pages) { | ||
117 | physp = __pa(page_address(&pages[0]) + | ||
118 | (virtp & ~PAGE_MASK)); | ||
119 | } else { | ||
120 | vpif_err("get_user_pages failed\n"); | ||
121 | return 0; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | return physp; | ||
126 | } | ||
127 | |||
128 | /* | ||
129 | * buffer_prepare: This is the callback function called from videobuf_qbuf() | ||
130 | * function the buffer is prepared and user space virtual address is converted | ||
131 | * into physical address | ||
132 | */ | ||
133 | static int vpif_buffer_prepare(struct videobuf_queue *q, | ||
134 | struct videobuf_buffer *vb, | ||
135 | enum v4l2_field field) | ||
136 | { | ||
137 | struct vpif_fh *fh = q->priv_data; | ||
138 | struct common_obj *common; | ||
139 | unsigned long addr; | ||
140 | |||
141 | common = &fh->channel->common[VPIF_VIDEO_INDEX]; | ||
142 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
143 | vb->width = common->width; | ||
144 | vb->height = common->height; | ||
145 | vb->size = vb->width * vb->height; | ||
146 | vb->field = field; | ||
147 | } | ||
148 | vb->state = VIDEOBUF_PREPARED; | ||
149 | |||
150 | /* if user pointer memory mechanism is used, get the physical | ||
151 | * address of the buffer */ | ||
152 | if (V4L2_MEMORY_USERPTR == common->memory) { | ||
153 | if (!vb->baddr) { | ||
154 | vpif_err("buffer_address is 0\n"); | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | |||
158 | vb->boff = vpif_uservirt_to_phys(vb->baddr); | ||
159 | if (!ISALIGNED(vb->boff)) | ||
160 | goto buf_align_exit; | ||
161 | } | ||
162 | |||
163 | addr = vb->boff; | ||
164 | if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) { | ||
165 | if (!ISALIGNED(addr + common->ytop_off) || | ||
166 | !ISALIGNED(addr + common->ybtm_off) || | ||
167 | !ISALIGNED(addr + common->ctop_off) || | ||
168 | !ISALIGNED(addr + common->cbtm_off)) | ||
169 | goto buf_align_exit; | ||
170 | } | ||
171 | return 0; | ||
172 | |||
173 | buf_align_exit: | ||
174 | vpif_err("buffer offset not aligned to 8 bytes\n"); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * vpif_buffer_setup: This function allocates memory for the buffers | ||
180 | */ | ||
181 | static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count, | ||
182 | unsigned int *size) | ||
183 | { | ||
184 | struct vpif_fh *fh = q->priv_data; | ||
185 | struct channel_obj *ch = fh->channel; | ||
186 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
187 | |||
188 | if (V4L2_MEMORY_MMAP != common->memory) | ||
189 | return 0; | ||
190 | |||
191 | *size = config_params.channel_bufsize[ch->channel_id]; | ||
192 | if (*count < config_params.min_numbuffers) | ||
193 | *count = config_params.min_numbuffers; | ||
194 | |||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | /* | ||
199 | * vpif_buffer_queue: This function adds the buffer to DMA queue | ||
200 | */ | ||
201 | static void vpif_buffer_queue(struct videobuf_queue *q, | ||
202 | struct videobuf_buffer *vb) | ||
203 | { | ||
204 | struct vpif_fh *fh = q->priv_data; | ||
205 | struct common_obj *common; | ||
206 | |||
207 | common = &fh->channel->common[VPIF_VIDEO_INDEX]; | ||
208 | |||
209 | /* add the buffer to the DMA queue */ | ||
210 | list_add_tail(&vb->queue, &common->dma_queue); | ||
211 | vb->state = VIDEOBUF_QUEUED; | ||
212 | } | ||
213 | |||
214 | /* | ||
215 | * vpif_buffer_release: This function is called from the videobuf layer to | ||
216 | * free memory allocated to the buffers | ||
217 | */ | ||
218 | static void vpif_buffer_release(struct videobuf_queue *q, | ||
219 | struct videobuf_buffer *vb) | ||
220 | { | ||
221 | struct vpif_fh *fh = q->priv_data; | ||
222 | struct channel_obj *ch = fh->channel; | ||
223 | struct common_obj *common; | ||
224 | unsigned int buf_size = 0; | ||
225 | |||
226 | common = &ch->common[VPIF_VIDEO_INDEX]; | ||
227 | |||
228 | videobuf_dma_contig_free(q, vb); | ||
229 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
230 | |||
231 | if (V4L2_MEMORY_MMAP != common->memory) | ||
232 | return; | ||
233 | |||
234 | buf_size = config_params.channel_bufsize[ch->channel_id]; | ||
235 | } | ||
236 | |||
237 | static struct videobuf_queue_ops video_qops = { | ||
238 | .buf_setup = vpif_buffer_setup, | ||
239 | .buf_prepare = vpif_buffer_prepare, | ||
240 | .buf_queue = vpif_buffer_queue, | ||
241 | .buf_release = vpif_buffer_release, | ||
242 | }; | ||
243 | static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} }; | ||
244 | |||
245 | static void process_progressive_mode(struct common_obj *common) | ||
246 | { | ||
247 | unsigned long addr = 0; | ||
248 | |||
249 | /* Get the next buffer from buffer queue */ | ||
250 | common->next_frm = list_entry(common->dma_queue.next, | ||
251 | struct videobuf_buffer, queue); | ||
252 | /* Remove that buffer from the buffer queue */ | ||
253 | list_del(&common->next_frm->queue); | ||
254 | /* Mark status of the buffer as active */ | ||
255 | common->next_frm->state = VIDEOBUF_ACTIVE; | ||
256 | |||
257 | /* Set top and bottom field addrs in VPIF registers */ | ||
258 | addr = videobuf_to_dma_contig(common->next_frm); | ||
259 | common->set_addr(addr + common->ytop_off, | ||
260 | addr + common->ybtm_off, | ||
261 | addr + common->ctop_off, | ||
262 | addr + common->cbtm_off); | ||
263 | } | ||
264 | |||
265 | static void process_interlaced_mode(int fid, struct common_obj *common) | ||
266 | { | ||
267 | /* device field id and local field id are in sync */ | ||
268 | /* If this is even field */ | ||
269 | if (0 == fid) { | ||
270 | if (common->cur_frm == common->next_frm) | ||
271 | return; | ||
272 | |||
273 | /* one frame is displayed If next frame is | ||
274 | * available, release cur_frm and move on */ | ||
275 | /* Copy frame display time */ | ||
276 | do_gettimeofday(&common->cur_frm->ts); | ||
277 | /* Change status of the cur_frm */ | ||
278 | common->cur_frm->state = VIDEOBUF_DONE; | ||
279 | /* unlock semaphore on cur_frm */ | ||
280 | wake_up_interruptible(&common->cur_frm->done); | ||
281 | /* Make cur_frm pointing to next_frm */ | ||
282 | common->cur_frm = common->next_frm; | ||
283 | |||
284 | } else if (1 == fid) { /* odd field */ | ||
285 | if (list_empty(&common->dma_queue) | ||
286 | || (common->cur_frm != common->next_frm)) { | ||
287 | return; | ||
288 | } | ||
289 | /* one field is displayed configure the next | ||
290 | * frame if it is available else hold on current | ||
291 | * frame */ | ||
292 | /* Get next from the buffer queue */ | ||
293 | process_progressive_mode(common); | ||
294 | |||
295 | } | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * vpif_channel_isr: It changes status of the displayed buffer, takes next | ||
300 | * buffer from the queue and sets its address in VPIF registers | ||
301 | */ | ||
302 | static irqreturn_t vpif_channel_isr(int irq, void *dev_id) | ||
303 | { | ||
304 | struct vpif_device *dev = &vpif_obj; | ||
305 | struct channel_obj *ch; | ||
306 | struct common_obj *common; | ||
307 | enum v4l2_field field; | ||
308 | int fid = -1, i; | ||
309 | int channel_id = 0; | ||
310 | |||
311 | channel_id = *(int *)(dev_id); | ||
312 | ch = dev->dev[channel_id]; | ||
313 | field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; | ||
314 | for (i = 0; i < VPIF_NUMOBJECTS; i++) { | ||
315 | common = &ch->common[i]; | ||
316 | /* If streaming is started in this channel */ | ||
317 | if (0 == common->started) | ||
318 | continue; | ||
319 | |||
320 | if (1 == ch->vpifparams.std_info.frm_fmt) { | ||
321 | if (list_empty(&common->dma_queue)) | ||
322 | continue; | ||
323 | |||
324 | /* Progressive mode */ | ||
325 | if (!channel_first_int[i][channel_id]) { | ||
326 | /* Mark status of the cur_frm to | ||
327 | * done and unlock semaphore on it */ | ||
328 | do_gettimeofday(&common->cur_frm->ts); | ||
329 | common->cur_frm->state = VIDEOBUF_DONE; | ||
330 | wake_up_interruptible(&common->cur_frm->done); | ||
331 | /* Make cur_frm pointing to next_frm */ | ||
332 | common->cur_frm = common->next_frm; | ||
333 | } | ||
334 | |||
335 | channel_first_int[i][channel_id] = 0; | ||
336 | process_progressive_mode(common); | ||
337 | } else { | ||
338 | /* Interlaced mode */ | ||
339 | /* If it is first interrupt, ignore it */ | ||
340 | |||
341 | if (channel_first_int[i][channel_id]) { | ||
342 | channel_first_int[i][channel_id] = 0; | ||
343 | continue; | ||
344 | } | ||
345 | |||
346 | if (0 == i) { | ||
347 | ch->field_id ^= 1; | ||
348 | /* Get field id from VPIF registers */ | ||
349 | fid = vpif_channel_getfid(ch->channel_id + 2); | ||
350 | /* If fid does not match with stored field id */ | ||
351 | if (fid != ch->field_id) { | ||
352 | /* Make them in sync */ | ||
353 | if (0 == fid) | ||
354 | ch->field_id = fid; | ||
355 | |||
356 | return IRQ_HANDLED; | ||
357 | } | ||
358 | } | ||
359 | process_interlaced_mode(fid, common); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | return IRQ_HANDLED; | ||
364 | } | ||
365 | |||
366 | static int vpif_update_std_info(struct channel_obj *ch) | ||
367 | { | ||
368 | struct video_obj *vid_ch = &ch->video; | ||
369 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
370 | struct vpif_channel_config_params *std_info = &vpifparams->std_info; | ||
371 | const struct vpif_channel_config_params *config; | ||
372 | |||
373 | int i; | ||
374 | |||
375 | for (i = 0; i < vpif_ch_params_count; i++) { | ||
376 | config = &ch_params[i]; | ||
377 | if (config->hd_sd == 0) { | ||
378 | vpif_dbg(2, debug, "SD format\n"); | ||
379 | if (config->stdid & vid_ch->stdid) { | ||
380 | memcpy(std_info, config, sizeof(*config)); | ||
381 | break; | ||
382 | } | ||
383 | } else { | ||
384 | vpif_dbg(2, debug, "HD format\n"); | ||
385 | if (config->dv_preset == vid_ch->dv_preset) { | ||
386 | memcpy(std_info, config, sizeof(*config)); | ||
387 | break; | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | |||
392 | if (i == vpif_ch_params_count) { | ||
393 | vpif_dbg(1, debug, "Format not found\n"); | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | static int vpif_update_resolution(struct channel_obj *ch) | ||
401 | { | ||
402 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
403 | struct video_obj *vid_ch = &ch->video; | ||
404 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
405 | struct vpif_channel_config_params *std_info = &vpifparams->std_info; | ||
406 | |||
407 | if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height) | ||
408 | return -EINVAL; | ||
409 | |||
410 | if (vid_ch->stdid || vid_ch->dv_preset) { | ||
411 | if (vpif_update_std_info(ch)) | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | |||
415 | common->fmt.fmt.pix.width = std_info->width; | ||
416 | common->fmt.fmt.pix.height = std_info->height; | ||
417 | vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n", | ||
418 | common->fmt.fmt.pix.width, common->fmt.fmt.pix.height); | ||
419 | |||
420 | /* Set height and width paramateres */ | ||
421 | common->height = std_info->height; | ||
422 | common->width = std_info->width; | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * vpif_calculate_offsets: This function calculates buffers offset for Y and C | ||
429 | * in the top and bottom field | ||
430 | */ | ||
431 | static void vpif_calculate_offsets(struct channel_obj *ch) | ||
432 | { | ||
433 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
434 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
435 | enum v4l2_field field = common->fmt.fmt.pix.field; | ||
436 | struct video_obj *vid_ch = &ch->video; | ||
437 | unsigned int hpitch, vpitch, sizeimage; | ||
438 | |||
439 | if (V4L2_FIELD_ANY == common->fmt.fmt.pix.field) { | ||
440 | if (ch->vpifparams.std_info.frm_fmt) | ||
441 | vid_ch->buf_field = V4L2_FIELD_NONE; | ||
442 | else | ||
443 | vid_ch->buf_field = V4L2_FIELD_INTERLACED; | ||
444 | } else { | ||
445 | vid_ch->buf_field = common->fmt.fmt.pix.field; | ||
446 | } | ||
447 | |||
448 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
449 | sizeimage = common->fmt.fmt.pix.sizeimage; | ||
450 | else | ||
451 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
452 | |||
453 | hpitch = common->fmt.fmt.pix.bytesperline; | ||
454 | vpitch = sizeimage / (hpitch * 2); | ||
455 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
456 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { | ||
457 | common->ytop_off = 0; | ||
458 | common->ybtm_off = hpitch; | ||
459 | common->ctop_off = sizeimage / 2; | ||
460 | common->cbtm_off = sizeimage / 2 + hpitch; | ||
461 | } else if (V4L2_FIELD_SEQ_TB == vid_ch->buf_field) { | ||
462 | common->ytop_off = 0; | ||
463 | common->ybtm_off = sizeimage / 4; | ||
464 | common->ctop_off = sizeimage / 2; | ||
465 | common->cbtm_off = common->ctop_off + sizeimage / 4; | ||
466 | } else if (V4L2_FIELD_SEQ_BT == vid_ch->buf_field) { | ||
467 | common->ybtm_off = 0; | ||
468 | common->ytop_off = sizeimage / 4; | ||
469 | common->cbtm_off = sizeimage / 2; | ||
470 | common->ctop_off = common->cbtm_off + sizeimage / 4; | ||
471 | } | ||
472 | |||
473 | if ((V4L2_FIELD_NONE == vid_ch->buf_field) || | ||
474 | (V4L2_FIELD_INTERLACED == vid_ch->buf_field)) { | ||
475 | vpifparams->video_params.storage_mode = 1; | ||
476 | } else { | ||
477 | vpifparams->video_params.storage_mode = 0; | ||
478 | } | ||
479 | |||
480 | if (ch->vpifparams.std_info.frm_fmt == 1) { | ||
481 | vpifparams->video_params.hpitch = | ||
482 | common->fmt.fmt.pix.bytesperline; | ||
483 | } else { | ||
484 | if ((field == V4L2_FIELD_ANY) || | ||
485 | (field == V4L2_FIELD_INTERLACED)) | ||
486 | vpifparams->video_params.hpitch = | ||
487 | common->fmt.fmt.pix.bytesperline * 2; | ||
488 | else | ||
489 | vpifparams->video_params.hpitch = | ||
490 | common->fmt.fmt.pix.bytesperline; | ||
491 | } | ||
492 | |||
493 | ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid; | ||
494 | } | ||
495 | |||
496 | static void vpif_config_format(struct channel_obj *ch) | ||
497 | { | ||
498 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
499 | |||
500 | common->fmt.fmt.pix.field = V4L2_FIELD_ANY; | ||
501 | if (config_params.numbuffers[ch->channel_id] == 0) | ||
502 | common->memory = V4L2_MEMORY_USERPTR; | ||
503 | else | ||
504 | common->memory = V4L2_MEMORY_MMAP; | ||
505 | |||
506 | common->fmt.fmt.pix.sizeimage = | ||
507 | config_params.channel_bufsize[ch->channel_id]; | ||
508 | common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P; | ||
509 | common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
510 | } | ||
511 | |||
512 | static int vpif_check_format(struct channel_obj *ch, | ||
513 | struct v4l2_pix_format *pixfmt) | ||
514 | { | ||
515 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
516 | enum v4l2_field field = pixfmt->field; | ||
517 | u32 sizeimage, hpitch, vpitch; | ||
518 | |||
519 | if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) | ||
520 | goto invalid_fmt_exit; | ||
521 | |||
522 | if (!(VPIF_VALID_FIELD(field))) | ||
523 | goto invalid_fmt_exit; | ||
524 | |||
525 | if (pixfmt->bytesperline <= 0) | ||
526 | goto invalid_pitch_exit; | ||
527 | |||
528 | if (V4L2_MEMORY_USERPTR == common->memory) | ||
529 | sizeimage = pixfmt->sizeimage; | ||
530 | else | ||
531 | sizeimage = config_params.channel_bufsize[ch->channel_id]; | ||
532 | |||
533 | if (vpif_update_resolution(ch)) | ||
534 | return -EINVAL; | ||
535 | |||
536 | hpitch = pixfmt->bytesperline; | ||
537 | vpitch = sizeimage / (hpitch * 2); | ||
538 | |||
539 | /* Check for valid value of pitch */ | ||
540 | if ((hpitch < ch->vpifparams.std_info.width) || | ||
541 | (vpitch < ch->vpifparams.std_info.height)) | ||
542 | goto invalid_pitch_exit; | ||
543 | |||
544 | /* Check for 8 byte alignment */ | ||
545 | if (!ISALIGNED(hpitch)) { | ||
546 | vpif_err("invalid pitch alignment\n"); | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | pixfmt->width = common->fmt.fmt.pix.width; | ||
550 | pixfmt->height = common->fmt.fmt.pix.height; | ||
551 | |||
552 | return 0; | ||
553 | |||
554 | invalid_fmt_exit: | ||
555 | vpif_err("invalid field format\n"); | ||
556 | return -EINVAL; | ||
557 | |||
558 | invalid_pitch_exit: | ||
559 | vpif_err("invalid pitch\n"); | ||
560 | return -EINVAL; | ||
561 | } | ||
562 | |||
563 | static void vpif_config_addr(struct channel_obj *ch, int muxmode) | ||
564 | { | ||
565 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
566 | |||
567 | if (VPIF_CHANNEL3_VIDEO == ch->channel_id) { | ||
568 | common->set_addr = ch3_set_videobuf_addr; | ||
569 | } else { | ||
570 | if (2 == muxmode) | ||
571 | common->set_addr = ch2_set_videobuf_addr_yc_nmux; | ||
572 | else | ||
573 | common->set_addr = ch2_set_videobuf_addr; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * vpif_mmap: It is used to map kernel space buffers into user spaces | ||
579 | */ | ||
580 | static int vpif_mmap(struct file *filep, struct vm_area_struct *vma) | ||
581 | { | ||
582 | struct vpif_fh *fh = filep->private_data; | ||
583 | struct channel_obj *ch = fh->channel; | ||
584 | struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]); | ||
585 | |||
586 | vpif_dbg(2, debug, "vpif_mmap\n"); | ||
587 | |||
588 | return videobuf_mmap_mapper(&common->buffer_queue, vma); | ||
589 | } | ||
590 | |||
591 | /* | ||
592 | * vpif_poll: It is used for select/poll system call | ||
593 | */ | ||
594 | static unsigned int vpif_poll(struct file *filep, poll_table *wait) | ||
595 | { | ||
596 | struct vpif_fh *fh = filep->private_data; | ||
597 | struct channel_obj *ch = fh->channel; | ||
598 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
599 | |||
600 | if (common->started) | ||
601 | return videobuf_poll_stream(filep, &common->buffer_queue, wait); | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | * vpif_open: It creates object of file handle structure and stores it in | ||
608 | * private_data member of filepointer | ||
609 | */ | ||
610 | static int vpif_open(struct file *filep) | ||
611 | { | ||
612 | struct video_device *vdev = video_devdata(filep); | ||
613 | struct channel_obj *ch = NULL; | ||
614 | struct vpif_fh *fh = NULL; | ||
615 | |||
616 | ch = video_get_drvdata(vdev); | ||
617 | /* Allocate memory for the file handle object */ | ||
618 | fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); | ||
619 | if (fh == NULL) { | ||
620 | vpif_err("unable to allocate memory for file handle object\n"); | ||
621 | return -ENOMEM; | ||
622 | } | ||
623 | |||
624 | /* store pointer to fh in private_data member of filep */ | ||
625 | filep->private_data = fh; | ||
626 | fh->channel = ch; | ||
627 | fh->initialized = 0; | ||
628 | if (!ch->initialized) { | ||
629 | fh->initialized = 1; | ||
630 | ch->initialized = 1; | ||
631 | memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); | ||
632 | } | ||
633 | |||
634 | /* Increment channel usrs counter */ | ||
635 | atomic_inc(&ch->usrs); | ||
636 | /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */ | ||
637 | fh->io_allowed[VPIF_VIDEO_INDEX] = 0; | ||
638 | /* Initialize priority of this instance to default priority */ | ||
639 | fh->prio = V4L2_PRIORITY_UNSET; | ||
640 | v4l2_prio_open(&ch->prio, &fh->prio); | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | /* | ||
646 | * vpif_release: This function deletes buffer queue, frees the buffers and | ||
647 | * the vpif file handle | ||
648 | */ | ||
649 | static int vpif_release(struct file *filep) | ||
650 | { | ||
651 | struct vpif_fh *fh = filep->private_data; | ||
652 | struct channel_obj *ch = fh->channel; | ||
653 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
654 | |||
655 | /* if this instance is doing IO */ | ||
656 | if (fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
657 | /* Reset io_usrs member of channel object */ | ||
658 | common->io_usrs = 0; | ||
659 | /* Disable channel */ | ||
660 | if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { | ||
661 | enable_channel2(0); | ||
662 | channel2_intr_enable(0); | ||
663 | } | ||
664 | if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || | ||
665 | (2 == common->started)) { | ||
666 | enable_channel3(0); | ||
667 | channel3_intr_enable(0); | ||
668 | } | ||
669 | common->started = 0; | ||
670 | /* Free buffers allocated */ | ||
671 | videobuf_queue_cancel(&common->buffer_queue); | ||
672 | videobuf_mmap_free(&common->buffer_queue); | ||
673 | common->numbuffers = | ||
674 | config_params.numbuffers[ch->channel_id]; | ||
675 | } | ||
676 | |||
677 | /* Decrement channel usrs counter */ | ||
678 | atomic_dec(&ch->usrs); | ||
679 | /* If this file handle has initialize encoder device, reset it */ | ||
680 | if (fh->initialized) | ||
681 | ch->initialized = 0; | ||
682 | |||
683 | /* Close the priority */ | ||
684 | v4l2_prio_close(&ch->prio, fh->prio); | ||
685 | filep->private_data = NULL; | ||
686 | fh->initialized = 0; | ||
687 | kfree(fh); | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | /* functions implementing ioctls */ | ||
693 | /** | ||
694 | * vpif_querycap() - QUERYCAP handler | ||
695 | * @file: file ptr | ||
696 | * @priv: file handle | ||
697 | * @cap: ptr to v4l2_capability structure | ||
698 | */ | ||
699 | static int vpif_querycap(struct file *file, void *priv, | ||
700 | struct v4l2_capability *cap) | ||
701 | { | ||
702 | struct vpif_display_config *config = vpif_dev->platform_data; | ||
703 | |||
704 | cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; | ||
705 | strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); | ||
706 | strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); | ||
707 | strlcpy(cap->card, config->card_name, sizeof(cap->card)); | ||
708 | |||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | static int vpif_enum_fmt_vid_out(struct file *file, void *priv, | ||
713 | struct v4l2_fmtdesc *fmt) | ||
714 | { | ||
715 | if (fmt->index != 0) { | ||
716 | vpif_err("Invalid format index\n"); | ||
717 | return -EINVAL; | ||
718 | } | ||
719 | |||
720 | /* Fill in the information about format */ | ||
721 | fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
722 | strcpy(fmt->description, "YCbCr4:2:2 YC Planar"); | ||
723 | fmt->pixelformat = V4L2_PIX_FMT_YUV422P; | ||
724 | |||
725 | return 0; | ||
726 | } | ||
727 | |||
728 | static int vpif_g_fmt_vid_out(struct file *file, void *priv, | ||
729 | struct v4l2_format *fmt) | ||
730 | { | ||
731 | struct vpif_fh *fh = priv; | ||
732 | struct channel_obj *ch = fh->channel; | ||
733 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
734 | |||
735 | /* Check the validity of the buffer type */ | ||
736 | if (common->fmt.type != fmt->type) | ||
737 | return -EINVAL; | ||
738 | |||
739 | if (vpif_update_resolution(ch)) | ||
740 | return -EINVAL; | ||
741 | *fmt = common->fmt; | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static int vpif_s_fmt_vid_out(struct file *file, void *priv, | ||
746 | struct v4l2_format *fmt) | ||
747 | { | ||
748 | struct vpif_fh *fh = priv; | ||
749 | struct v4l2_pix_format *pixfmt; | ||
750 | struct channel_obj *ch = fh->channel; | ||
751 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
752 | int ret = 0; | ||
753 | |||
754 | if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) | ||
755 | || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { | ||
756 | if (!fh->initialized) { | ||
757 | vpif_dbg(1, debug, "Channel Busy\n"); | ||
758 | return -EBUSY; | ||
759 | } | ||
760 | |||
761 | /* Check for the priority */ | ||
762 | ret = v4l2_prio_check(&ch->prio, fh->prio); | ||
763 | if (0 != ret) | ||
764 | return ret; | ||
765 | fh->initialized = 1; | ||
766 | } | ||
767 | |||
768 | if (common->started) { | ||
769 | vpif_dbg(1, debug, "Streaming in progress\n"); | ||
770 | return -EBUSY; | ||
771 | } | ||
772 | |||
773 | pixfmt = &fmt->fmt.pix; | ||
774 | /* Check for valid field format */ | ||
775 | ret = vpif_check_format(ch, pixfmt); | ||
776 | if (ret) | ||
777 | return ret; | ||
778 | |||
779 | /* store the pix format in the channel object */ | ||
780 | common->fmt.fmt.pix = *pixfmt; | ||
781 | /* store the format in the channel object */ | ||
782 | common->fmt = *fmt; | ||
783 | return 0; | ||
784 | } | ||
785 | |||
786 | static int vpif_try_fmt_vid_out(struct file *file, void *priv, | ||
787 | struct v4l2_format *fmt) | ||
788 | { | ||
789 | struct vpif_fh *fh = priv; | ||
790 | struct channel_obj *ch = fh->channel; | ||
791 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
792 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
793 | int ret = 0; | ||
794 | |||
795 | ret = vpif_check_format(ch, pixfmt); | ||
796 | if (ret) { | ||
797 | *pixfmt = common->fmt.fmt.pix; | ||
798 | pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2; | ||
799 | } | ||
800 | |||
801 | return ret; | ||
802 | } | ||
803 | |||
804 | static int vpif_reqbufs(struct file *file, void *priv, | ||
805 | struct v4l2_requestbuffers *reqbuf) | ||
806 | { | ||
807 | struct vpif_fh *fh = priv; | ||
808 | struct channel_obj *ch = fh->channel; | ||
809 | struct common_obj *common; | ||
810 | enum v4l2_field field; | ||
811 | u8 index = 0; | ||
812 | |||
813 | /* This file handle has not initialized the channel, | ||
814 | It is not allowed to do settings */ | ||
815 | if ((VPIF_CHANNEL2_VIDEO == ch->channel_id) | ||
816 | || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) { | ||
817 | if (!fh->initialized) { | ||
818 | vpif_err("Channel Busy\n"); | ||
819 | return -EBUSY; | ||
820 | } | ||
821 | } | ||
822 | |||
823 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type) | ||
824 | return -EINVAL; | ||
825 | |||
826 | index = VPIF_VIDEO_INDEX; | ||
827 | |||
828 | common = &ch->common[index]; | ||
829 | |||
830 | if (common->fmt.type != reqbuf->type) | ||
831 | return -EINVAL; | ||
832 | |||
833 | if (0 != common->io_usrs) | ||
834 | return -EBUSY; | ||
835 | |||
836 | if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
837 | if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY) | ||
838 | field = V4L2_FIELD_INTERLACED; | ||
839 | else | ||
840 | field = common->fmt.fmt.pix.field; | ||
841 | } else { | ||
842 | field = V4L2_VBI_INTERLACED; | ||
843 | } | ||
844 | |||
845 | /* Initialize videobuf queue as per the buffer type */ | ||
846 | videobuf_queue_dma_contig_init(&common->buffer_queue, | ||
847 | &video_qops, NULL, | ||
848 | &common->irqlock, | ||
849 | reqbuf->type, field, | ||
850 | sizeof(struct videobuf_buffer), fh, | ||
851 | &common->lock); | ||
852 | |||
853 | /* Set io allowed member of file handle to TRUE */ | ||
854 | fh->io_allowed[index] = 1; | ||
855 | /* Increment io usrs member of channel object to 1 */ | ||
856 | common->io_usrs = 1; | ||
857 | /* Store type of memory requested in channel object */ | ||
858 | common->memory = reqbuf->memory; | ||
859 | INIT_LIST_HEAD(&common->dma_queue); | ||
860 | |||
861 | /* Allocate buffers */ | ||
862 | return videobuf_reqbufs(&common->buffer_queue, reqbuf); | ||
863 | } | ||
864 | |||
865 | static int vpif_querybuf(struct file *file, void *priv, | ||
866 | struct v4l2_buffer *tbuf) | ||
867 | { | ||
868 | struct vpif_fh *fh = priv; | ||
869 | struct channel_obj *ch = fh->channel; | ||
870 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
871 | |||
872 | if (common->fmt.type != tbuf->type) | ||
873 | return -EINVAL; | ||
874 | |||
875 | return videobuf_querybuf(&common->buffer_queue, tbuf); | ||
876 | } | ||
877 | |||
878 | static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
879 | { | ||
880 | |||
881 | struct vpif_fh *fh = priv; | ||
882 | struct channel_obj *ch = fh->channel; | ||
883 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
884 | struct v4l2_buffer tbuf = *buf; | ||
885 | struct videobuf_buffer *buf1; | ||
886 | unsigned long addr = 0; | ||
887 | unsigned long flags; | ||
888 | int ret = 0; | ||
889 | |||
890 | if (common->fmt.type != tbuf.type) | ||
891 | return -EINVAL; | ||
892 | |||
893 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
894 | vpif_err("fh->io_allowed\n"); | ||
895 | return -EACCES; | ||
896 | } | ||
897 | |||
898 | if (!(list_empty(&common->dma_queue)) || | ||
899 | (common->cur_frm != common->next_frm) || | ||
900 | !(common->started) || | ||
901 | (common->started && (0 == ch->field_id))) | ||
902 | return videobuf_qbuf(&common->buffer_queue, buf); | ||
903 | |||
904 | /* bufferqueue is empty store buffer address in VPIF registers */ | ||
905 | mutex_lock(&common->buffer_queue.vb_lock); | ||
906 | buf1 = common->buffer_queue.bufs[tbuf.index]; | ||
907 | if (buf1->memory != tbuf.memory) { | ||
908 | vpif_err("invalid buffer type\n"); | ||
909 | goto qbuf_exit; | ||
910 | } | ||
911 | |||
912 | if ((buf1->state == VIDEOBUF_QUEUED) || | ||
913 | (buf1->state == VIDEOBUF_ACTIVE)) { | ||
914 | vpif_err("invalid state\n"); | ||
915 | goto qbuf_exit; | ||
916 | } | ||
917 | |||
918 | switch (buf1->memory) { | ||
919 | case V4L2_MEMORY_MMAP: | ||
920 | if (buf1->baddr == 0) | ||
921 | goto qbuf_exit; | ||
922 | break; | ||
923 | |||
924 | case V4L2_MEMORY_USERPTR: | ||
925 | if (tbuf.length < buf1->bsize) | ||
926 | goto qbuf_exit; | ||
927 | |||
928 | if ((VIDEOBUF_NEEDS_INIT != buf1->state) | ||
929 | && (buf1->baddr != tbuf.m.userptr)) { | ||
930 | vpif_buffer_release(&common->buffer_queue, buf1); | ||
931 | buf1->baddr = tbuf.m.userptr; | ||
932 | } | ||
933 | break; | ||
934 | |||
935 | default: | ||
936 | goto qbuf_exit; | ||
937 | } | ||
938 | |||
939 | local_irq_save(flags); | ||
940 | ret = vpif_buffer_prepare(&common->buffer_queue, buf1, | ||
941 | common->buffer_queue.field); | ||
942 | if (ret < 0) { | ||
943 | local_irq_restore(flags); | ||
944 | goto qbuf_exit; | ||
945 | } | ||
946 | |||
947 | buf1->state = VIDEOBUF_ACTIVE; | ||
948 | addr = buf1->boff; | ||
949 | common->next_frm = buf1; | ||
950 | if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) { | ||
951 | common->set_addr((addr + common->ytop_off), | ||
952 | (addr + common->ybtm_off), | ||
953 | (addr + common->ctop_off), | ||
954 | (addr + common->cbtm_off)); | ||
955 | } | ||
956 | |||
957 | local_irq_restore(flags); | ||
958 | list_add_tail(&buf1->stream, &common->buffer_queue.stream); | ||
959 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
960 | return 0; | ||
961 | |||
962 | qbuf_exit: | ||
963 | mutex_unlock(&common->buffer_queue.vb_lock); | ||
964 | return -EINVAL; | ||
965 | } | ||
966 | |||
967 | static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) | ||
968 | { | ||
969 | struct vpif_fh *fh = priv; | ||
970 | struct channel_obj *ch = fh->channel; | ||
971 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
972 | int ret = 0; | ||
973 | |||
974 | if (!(*std_id & DM646X_V4L2_STD)) | ||
975 | return -EINVAL; | ||
976 | |||
977 | if (common->started) { | ||
978 | vpif_err("streaming in progress\n"); | ||
979 | return -EBUSY; | ||
980 | } | ||
981 | |||
982 | /* Call encoder subdevice function to set the standard */ | ||
983 | ch->video.stdid = *std_id; | ||
984 | ch->video.dv_preset = V4L2_DV_INVALID; | ||
985 | memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); | ||
986 | |||
987 | /* Get the information about the standard */ | ||
988 | if (vpif_update_resolution(ch)) | ||
989 | return -EINVAL; | ||
990 | |||
991 | if ((ch->vpifparams.std_info.width * | ||
992 | ch->vpifparams.std_info.height * 2) > | ||
993 | config_params.channel_bufsize[ch->channel_id]) { | ||
994 | vpif_err("invalid std for this size\n"); | ||
995 | return -EINVAL; | ||
996 | } | ||
997 | |||
998 | common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width; | ||
999 | /* Configure the default format information */ | ||
1000 | vpif_config_format(ch); | ||
1001 | |||
1002 | ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, | ||
1003 | s_std_output, *std_id); | ||
1004 | if (ret < 0) { | ||
1005 | vpif_err("Failed to set output standard\n"); | ||
1006 | return ret; | ||
1007 | } | ||
1008 | |||
1009 | ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, | ||
1010 | s_std, *std_id); | ||
1011 | if (ret < 0) | ||
1012 | vpif_err("Failed to set standard for sub devices\n"); | ||
1013 | return ret; | ||
1014 | } | ||
1015 | |||
1016 | static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
1017 | { | ||
1018 | struct vpif_fh *fh = priv; | ||
1019 | struct channel_obj *ch = fh->channel; | ||
1020 | |||
1021 | *std = ch->video.stdid; | ||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) | ||
1026 | { | ||
1027 | struct vpif_fh *fh = priv; | ||
1028 | struct channel_obj *ch = fh->channel; | ||
1029 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1030 | |||
1031 | return videobuf_dqbuf(&common->buffer_queue, p, | ||
1032 | (file->f_flags & O_NONBLOCK)); | ||
1033 | } | ||
1034 | |||
1035 | static int vpif_streamon(struct file *file, void *priv, | ||
1036 | enum v4l2_buf_type buftype) | ||
1037 | { | ||
1038 | struct vpif_fh *fh = priv; | ||
1039 | struct channel_obj *ch = fh->channel; | ||
1040 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1041 | struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id]; | ||
1042 | struct vpif_params *vpif = &ch->vpifparams; | ||
1043 | struct vpif_display_config *vpif_config_data = | ||
1044 | vpif_dev->platform_data; | ||
1045 | unsigned long addr = 0; | ||
1046 | int ret = 0; | ||
1047 | |||
1048 | if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1049 | vpif_err("buffer type not supported\n"); | ||
1050 | return -EINVAL; | ||
1051 | } | ||
1052 | |||
1053 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1054 | vpif_err("fh->io_allowed\n"); | ||
1055 | return -EACCES; | ||
1056 | } | ||
1057 | |||
1058 | /* If Streaming is already started, return error */ | ||
1059 | if (common->started) { | ||
1060 | vpif_err("channel->started\n"); | ||
1061 | return -EBUSY; | ||
1062 | } | ||
1063 | |||
1064 | if ((ch->channel_id == VPIF_CHANNEL2_VIDEO | ||
1065 | && oth_ch->common[VPIF_VIDEO_INDEX].started && | ||
1066 | ch->vpifparams.std_info.ycmux_mode == 0) | ||
1067 | || ((ch->channel_id == VPIF_CHANNEL3_VIDEO) | ||
1068 | && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) { | ||
1069 | vpif_err("other channel is using\n"); | ||
1070 | return -EBUSY; | ||
1071 | } | ||
1072 | |||
1073 | ret = vpif_check_format(ch, &common->fmt.fmt.pix); | ||
1074 | if (ret < 0) | ||
1075 | return ret; | ||
1076 | |||
1077 | /* Call videobuf_streamon to start streaming in videobuf */ | ||
1078 | ret = videobuf_streamon(&common->buffer_queue); | ||
1079 | if (ret < 0) { | ||
1080 | vpif_err("videobuf_streamon\n"); | ||
1081 | return ret; | ||
1082 | } | ||
1083 | |||
1084 | /* If buffer queue is empty, return error */ | ||
1085 | if (list_empty(&common->dma_queue)) { | ||
1086 | vpif_err("buffer queue is empty\n"); | ||
1087 | return -EIO; | ||
1088 | } | ||
1089 | |||
1090 | /* Get the next frame from the buffer queue */ | ||
1091 | common->next_frm = common->cur_frm = | ||
1092 | list_entry(common->dma_queue.next, | ||
1093 | struct videobuf_buffer, queue); | ||
1094 | |||
1095 | list_del(&common->cur_frm->queue); | ||
1096 | /* Mark state of the current frame to active */ | ||
1097 | common->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1098 | |||
1099 | /* Initialize field_id and started member */ | ||
1100 | ch->field_id = 0; | ||
1101 | common->started = 1; | ||
1102 | if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1103 | addr = common->cur_frm->boff; | ||
1104 | /* Calculate the offset for Y and C data in the buffer */ | ||
1105 | vpif_calculate_offsets(ch); | ||
1106 | |||
1107 | if ((ch->vpifparams.std_info.frm_fmt && | ||
1108 | ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) | ||
1109 | && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) | ||
1110 | || (!ch->vpifparams.std_info.frm_fmt | ||
1111 | && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { | ||
1112 | vpif_err("conflict in field format and std format\n"); | ||
1113 | return -EINVAL; | ||
1114 | } | ||
1115 | |||
1116 | /* clock settings */ | ||
1117 | ret = | ||
1118 | vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, | ||
1119 | ch->vpifparams.std_info.hd_sd); | ||
1120 | if (ret < 0) { | ||
1121 | vpif_err("can't set clock\n"); | ||
1122 | return ret; | ||
1123 | } | ||
1124 | |||
1125 | /* set the parameters and addresses */ | ||
1126 | ret = vpif_set_video_params(vpif, ch->channel_id + 2); | ||
1127 | if (ret < 0) | ||
1128 | return ret; | ||
1129 | |||
1130 | common->started = ret; | ||
1131 | vpif_config_addr(ch, ret); | ||
1132 | common->set_addr((addr + common->ytop_off), | ||
1133 | (addr + common->ybtm_off), | ||
1134 | (addr + common->ctop_off), | ||
1135 | (addr + common->cbtm_off)); | ||
1136 | |||
1137 | /* Set interrupt for both the fields in VPIF | ||
1138 | Register enable channel in VPIF register */ | ||
1139 | if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { | ||
1140 | channel2_intr_assert(); | ||
1141 | channel2_intr_enable(1); | ||
1142 | enable_channel2(1); | ||
1143 | } | ||
1144 | |||
1145 | if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) | ||
1146 | || (common->started == 2)) { | ||
1147 | channel3_intr_assert(); | ||
1148 | channel3_intr_enable(1); | ||
1149 | enable_channel3(1); | ||
1150 | } | ||
1151 | channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; | ||
1152 | } | ||
1153 | return ret; | ||
1154 | } | ||
1155 | |||
1156 | static int vpif_streamoff(struct file *file, void *priv, | ||
1157 | enum v4l2_buf_type buftype) | ||
1158 | { | ||
1159 | struct vpif_fh *fh = priv; | ||
1160 | struct channel_obj *ch = fh->channel; | ||
1161 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1162 | |||
1163 | if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1164 | vpif_err("buffer type not supported\n"); | ||
1165 | return -EINVAL; | ||
1166 | } | ||
1167 | |||
1168 | if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { | ||
1169 | vpif_err("fh->io_allowed\n"); | ||
1170 | return -EACCES; | ||
1171 | } | ||
1172 | |||
1173 | if (!common->started) { | ||
1174 | vpif_err("channel->started\n"); | ||
1175 | return -EINVAL; | ||
1176 | } | ||
1177 | |||
1178 | if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1179 | /* disable channel */ | ||
1180 | if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { | ||
1181 | enable_channel2(0); | ||
1182 | channel2_intr_enable(0); | ||
1183 | } | ||
1184 | if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || | ||
1185 | (2 == common->started)) { | ||
1186 | enable_channel3(0); | ||
1187 | channel3_intr_enable(0); | ||
1188 | } | ||
1189 | } | ||
1190 | |||
1191 | common->started = 0; | ||
1192 | return videobuf_streamoff(&common->buffer_queue); | ||
1193 | } | ||
1194 | |||
1195 | static int vpif_cropcap(struct file *file, void *priv, | ||
1196 | struct v4l2_cropcap *crop) | ||
1197 | { | ||
1198 | struct vpif_fh *fh = priv; | ||
1199 | struct channel_obj *ch = fh->channel; | ||
1200 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1201 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type) | ||
1202 | return -EINVAL; | ||
1203 | |||
1204 | crop->bounds.left = crop->bounds.top = 0; | ||
1205 | crop->defrect.left = crop->defrect.top = 0; | ||
1206 | crop->defrect.height = crop->bounds.height = common->height; | ||
1207 | crop->defrect.width = crop->bounds.width = common->width; | ||
1208 | |||
1209 | return 0; | ||
1210 | } | ||
1211 | |||
1212 | static int vpif_enum_output(struct file *file, void *fh, | ||
1213 | struct v4l2_output *output) | ||
1214 | { | ||
1215 | |||
1216 | struct vpif_display_config *config = vpif_dev->platform_data; | ||
1217 | |||
1218 | if (output->index >= config->output_count) { | ||
1219 | vpif_dbg(1, debug, "Invalid output index\n"); | ||
1220 | return -EINVAL; | ||
1221 | } | ||
1222 | |||
1223 | strcpy(output->name, config->output[output->index]); | ||
1224 | output->type = V4L2_OUTPUT_TYPE_ANALOG; | ||
1225 | output->std = DM646X_V4L2_STD; | ||
1226 | |||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static int vpif_s_output(struct file *file, void *priv, unsigned int i) | ||
1231 | { | ||
1232 | struct vpif_fh *fh = priv; | ||
1233 | struct channel_obj *ch = fh->channel; | ||
1234 | struct video_obj *vid_ch = &ch->video; | ||
1235 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1236 | int ret = 0; | ||
1237 | |||
1238 | if (common->started) { | ||
1239 | vpif_err("Streaming in progress\n"); | ||
1240 | return -EBUSY; | ||
1241 | } | ||
1242 | |||
1243 | ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, | ||
1244 | s_routing, 0, i, 0); | ||
1245 | |||
1246 | if (ret < 0) | ||
1247 | vpif_err("Failed to set output standard\n"); | ||
1248 | |||
1249 | vid_ch->output_id = i; | ||
1250 | return ret; | ||
1251 | } | ||
1252 | |||
1253 | static int vpif_g_output(struct file *file, void *priv, unsigned int *i) | ||
1254 | { | ||
1255 | struct vpif_fh *fh = priv; | ||
1256 | struct channel_obj *ch = fh->channel; | ||
1257 | struct video_obj *vid_ch = &ch->video; | ||
1258 | |||
1259 | *i = vid_ch->output_id; | ||
1260 | |||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1264 | static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p) | ||
1265 | { | ||
1266 | struct vpif_fh *fh = priv; | ||
1267 | struct channel_obj *ch = fh->channel; | ||
1268 | |||
1269 | *p = v4l2_prio_max(&ch->prio); | ||
1270 | |||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p) | ||
1275 | { | ||
1276 | struct vpif_fh *fh = priv; | ||
1277 | struct channel_obj *ch = fh->channel; | ||
1278 | |||
1279 | return v4l2_prio_change(&ch->prio, &fh->prio, p); | ||
1280 | } | ||
1281 | |||
1282 | /** | ||
1283 | * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler | ||
1284 | * @file: file ptr | ||
1285 | * @priv: file handle | ||
1286 | * @preset: input preset | ||
1287 | */ | ||
1288 | static int vpif_enum_dv_presets(struct file *file, void *priv, | ||
1289 | struct v4l2_dv_enum_preset *preset) | ||
1290 | { | ||
1291 | struct vpif_fh *fh = priv; | ||
1292 | struct channel_obj *ch = fh->channel; | ||
1293 | struct video_obj *vid_ch = &ch->video; | ||
1294 | |||
1295 | return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], | ||
1296 | video, enum_dv_presets, preset); | ||
1297 | } | ||
1298 | |||
1299 | /** | ||
1300 | * vpif_s_dv_presets() - S_DV_PRESETS handler | ||
1301 | * @file: file ptr | ||
1302 | * @priv: file handle | ||
1303 | * @preset: input preset | ||
1304 | */ | ||
1305 | static int vpif_s_dv_preset(struct file *file, void *priv, | ||
1306 | struct v4l2_dv_preset *preset) | ||
1307 | { | ||
1308 | struct vpif_fh *fh = priv; | ||
1309 | struct channel_obj *ch = fh->channel; | ||
1310 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | ||
1311 | struct video_obj *vid_ch = &ch->video; | ||
1312 | int ret = 0; | ||
1313 | |||
1314 | if (common->started) { | ||
1315 | vpif_dbg(1, debug, "streaming in progress\n"); | ||
1316 | return -EBUSY; | ||
1317 | } | ||
1318 | |||
1319 | ret = v4l2_prio_check(&ch->prio, fh->prio); | ||
1320 | if (ret != 0) | ||
1321 | return ret; | ||
1322 | |||
1323 | fh->initialized = 1; | ||
1324 | |||
1325 | /* Call encoder subdevice function to set the standard */ | ||
1326 | if (mutex_lock_interruptible(&common->lock)) | ||
1327 | return -ERESTARTSYS; | ||
1328 | |||
1329 | ch->video.dv_preset = preset->preset; | ||
1330 | ch->video.stdid = V4L2_STD_UNKNOWN; | ||
1331 | memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings)); | ||
1332 | |||
1333 | /* Get the information about the standard */ | ||
1334 | if (vpif_update_resolution(ch)) { | ||
1335 | ret = -EINVAL; | ||
1336 | } else { | ||
1337 | /* Configure the default format information */ | ||
1338 | vpif_config_format(ch); | ||
1339 | |||
1340 | ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], | ||
1341 | video, s_dv_preset, preset); | ||
1342 | } | ||
1343 | |||
1344 | mutex_unlock(&common->lock); | ||
1345 | |||
1346 | return ret; | ||
1347 | } | ||
1348 | /** | ||
1349 | * vpif_g_dv_presets() - G_DV_PRESETS handler | ||
1350 | * @file: file ptr | ||
1351 | * @priv: file handle | ||
1352 | * @preset: input preset | ||
1353 | */ | ||
1354 | static int vpif_g_dv_preset(struct file *file, void *priv, | ||
1355 | struct v4l2_dv_preset *preset) | ||
1356 | { | ||
1357 | struct vpif_fh *fh = priv; | ||
1358 | struct channel_obj *ch = fh->channel; | ||
1359 | |||
1360 | preset->preset = ch->video.dv_preset; | ||
1361 | |||
1362 | return 0; | ||
1363 | } | ||
1364 | /** | ||
1365 | * vpif_s_dv_timings() - S_DV_TIMINGS handler | ||
1366 | * @file: file ptr | ||
1367 | * @priv: file handle | ||
1368 | * @timings: digital video timings | ||
1369 | */ | ||
1370 | static int vpif_s_dv_timings(struct file *file, void *priv, | ||
1371 | struct v4l2_dv_timings *timings) | ||
1372 | { | ||
1373 | struct vpif_fh *fh = priv; | ||
1374 | struct channel_obj *ch = fh->channel; | ||
1375 | struct vpif_params *vpifparams = &ch->vpifparams; | ||
1376 | struct vpif_channel_config_params *std_info = &vpifparams->std_info; | ||
1377 | struct video_obj *vid_ch = &ch->video; | ||
1378 | struct v4l2_bt_timings *bt = &vid_ch->bt_timings; | ||
1379 | int ret; | ||
1380 | |||
1381 | if (timings->type != V4L2_DV_BT_656_1120) { | ||
1382 | vpif_dbg(2, debug, "Timing type not defined\n"); | ||
1383 | return -EINVAL; | ||
1384 | } | ||
1385 | |||
1386 | /* Configure subdevice timings, if any */ | ||
1387 | ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], | ||
1388 | video, s_dv_timings, timings); | ||
1389 | if (ret == -ENOIOCTLCMD) { | ||
1390 | vpif_dbg(2, debug, "Custom DV timings not supported by " | ||
1391 | "subdevice\n"); | ||
1392 | return -EINVAL; | ||
1393 | } | ||
1394 | if (ret < 0) { | ||
1395 | vpif_dbg(2, debug, "Error setting custom DV timings\n"); | ||
1396 | return ret; | ||
1397 | } | ||
1398 | |||
1399 | if (!(timings->bt.width && timings->bt.height && | ||
1400 | (timings->bt.hbackporch || | ||
1401 | timings->bt.hfrontporch || | ||
1402 | timings->bt.hsync) && | ||
1403 | timings->bt.vfrontporch && | ||
1404 | (timings->bt.vbackporch || | ||
1405 | timings->bt.vsync))) { | ||
1406 | vpif_dbg(2, debug, "Timings for width, height, " | ||
1407 | "horizontal back porch, horizontal sync, " | ||
1408 | "horizontal front porch, vertical back porch, " | ||
1409 | "vertical sync and vertical back porch " | ||
1410 | "must be defined\n"); | ||
1411 | return -EINVAL; | ||
1412 | } | ||
1413 | |||
1414 | *bt = timings->bt; | ||
1415 | |||
1416 | /* Configure video port timings */ | ||
1417 | |||
1418 | std_info->eav2sav = bt->hbackporch + bt->hfrontporch + | ||
1419 | bt->hsync - 8; | ||
1420 | std_info->sav2eav = bt->width; | ||
1421 | |||
1422 | std_info->l1 = 1; | ||
1423 | std_info->l3 = bt->vsync + bt->vbackporch + 1; | ||
1424 | |||
1425 | if (bt->interlaced) { | ||
1426 | if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) { | ||
1427 | std_info->vsize = bt->height * 2 + | ||
1428 | bt->vfrontporch + bt->vsync + bt->vbackporch + | ||
1429 | bt->il_vfrontporch + bt->il_vsync + | ||
1430 | bt->il_vbackporch; | ||
1431 | std_info->l5 = std_info->vsize/2 - | ||
1432 | (bt->vfrontporch - 1); | ||
1433 | std_info->l7 = std_info->vsize/2 + 1; | ||
1434 | std_info->l9 = std_info->l7 + bt->il_vsync + | ||
1435 | bt->il_vbackporch + 1; | ||
1436 | std_info->l11 = std_info->vsize - | ||
1437 | (bt->il_vfrontporch - 1); | ||
1438 | } else { | ||
1439 | vpif_dbg(2, debug, "Required timing values for " | ||
1440 | "interlaced BT format missing\n"); | ||
1441 | return -EINVAL; | ||
1442 | } | ||
1443 | } else { | ||
1444 | std_info->vsize = bt->height + bt->vfrontporch + | ||
1445 | bt->vsync + bt->vbackporch; | ||
1446 | std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); | ||
1447 | } | ||
1448 | strncpy(std_info->name, "Custom timings BT656/1120", | ||
1449 | VPIF_MAX_NAME); | ||
1450 | std_info->width = bt->width; | ||
1451 | std_info->height = bt->height; | ||
1452 | std_info->frm_fmt = bt->interlaced ? 0 : 1; | ||
1453 | std_info->ycmux_mode = 0; | ||
1454 | std_info->capture_format = 0; | ||
1455 | std_info->vbi_supported = 0; | ||
1456 | std_info->hd_sd = 1; | ||
1457 | std_info->stdid = 0; | ||
1458 | std_info->dv_preset = V4L2_DV_INVALID; | ||
1459 | |||
1460 | vid_ch->stdid = 0; | ||
1461 | vid_ch->dv_preset = V4L2_DV_INVALID; | ||
1462 | |||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | /** | ||
1467 | * vpif_g_dv_timings() - G_DV_TIMINGS handler | ||
1468 | * @file: file ptr | ||
1469 | * @priv: file handle | ||
1470 | * @timings: digital video timings | ||
1471 | */ | ||
1472 | static int vpif_g_dv_timings(struct file *file, void *priv, | ||
1473 | struct v4l2_dv_timings *timings) | ||
1474 | { | ||
1475 | struct vpif_fh *fh = priv; | ||
1476 | struct channel_obj *ch = fh->channel; | ||
1477 | struct video_obj *vid_ch = &ch->video; | ||
1478 | struct v4l2_bt_timings *bt = &vid_ch->bt_timings; | ||
1479 | |||
1480 | timings->bt = *bt; | ||
1481 | |||
1482 | return 0; | ||
1483 | } | ||
1484 | |||
1485 | /* | ||
1486 | * vpif_g_chip_ident() - Identify the chip | ||
1487 | * @file: file ptr | ||
1488 | * @priv: file handle | ||
1489 | * @chip: chip identity | ||
1490 | * | ||
1491 | * Returns zero or -EINVAL if read operations fails. | ||
1492 | */ | ||
1493 | static int vpif_g_chip_ident(struct file *file, void *priv, | ||
1494 | struct v4l2_dbg_chip_ident *chip) | ||
1495 | { | ||
1496 | chip->ident = V4L2_IDENT_NONE; | ||
1497 | chip->revision = 0; | ||
1498 | if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && | ||
1499 | chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) { | ||
1500 | vpif_dbg(2, debug, "match_type is invalid.\n"); | ||
1501 | return -EINVAL; | ||
1502 | } | ||
1503 | |||
1504 | return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core, | ||
1505 | g_chip_ident, chip); | ||
1506 | } | ||
1507 | |||
1508 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1509 | /* | ||
1510 | * vpif_dbg_g_register() - Read register | ||
1511 | * @file: file ptr | ||
1512 | * @priv: file handle | ||
1513 | * @reg: register to be read | ||
1514 | * | ||
1515 | * Debugging only | ||
1516 | * Returns zero or -EINVAL if read operations fails. | ||
1517 | */ | ||
1518 | static int vpif_dbg_g_register(struct file *file, void *priv, | ||
1519 | struct v4l2_dbg_register *reg){ | ||
1520 | struct vpif_fh *fh = priv; | ||
1521 | struct channel_obj *ch = fh->channel; | ||
1522 | struct video_obj *vid_ch = &ch->video; | ||
1523 | |||
1524 | return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, | ||
1525 | g_register, reg); | ||
1526 | } | ||
1527 | |||
1528 | /* | ||
1529 | * vpif_dbg_s_register() - Write to register | ||
1530 | * @file: file ptr | ||
1531 | * @priv: file handle | ||
1532 | * @reg: register to be modified | ||
1533 | * | ||
1534 | * Debugging only | ||
1535 | * Returns zero or -EINVAL if write operations fails. | ||
1536 | */ | ||
1537 | static int vpif_dbg_s_register(struct file *file, void *priv, | ||
1538 | struct v4l2_dbg_register *reg){ | ||
1539 | struct vpif_fh *fh = priv; | ||
1540 | struct channel_obj *ch = fh->channel; | ||
1541 | struct video_obj *vid_ch = &ch->video; | ||
1542 | |||
1543 | return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, | ||
1544 | s_register, reg); | ||
1545 | } | ||
1546 | #endif | ||
1547 | |||
1548 | /* | ||
1549 | * vpif_log_status() - Status information | ||
1550 | * @file: file ptr | ||
1551 | * @priv: file handle | ||
1552 | * | ||
1553 | * Returns zero. | ||
1554 | */ | ||
1555 | static int vpif_log_status(struct file *filep, void *priv) | ||
1556 | { | ||
1557 | /* status for sub devices */ | ||
1558 | v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status); | ||
1559 | |||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* vpif display ioctl operations */ | ||
1564 | static const struct v4l2_ioctl_ops vpif_ioctl_ops = { | ||
1565 | .vidioc_querycap = vpif_querycap, | ||
1566 | .vidioc_g_priority = vpif_g_priority, | ||
1567 | .vidioc_s_priority = vpif_s_priority, | ||
1568 | .vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out, | ||
1569 | .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out, | ||
1570 | .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out, | ||
1571 | .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out, | ||
1572 | .vidioc_reqbufs = vpif_reqbufs, | ||
1573 | .vidioc_querybuf = vpif_querybuf, | ||
1574 | .vidioc_qbuf = vpif_qbuf, | ||
1575 | .vidioc_dqbuf = vpif_dqbuf, | ||
1576 | .vidioc_streamon = vpif_streamon, | ||
1577 | .vidioc_streamoff = vpif_streamoff, | ||
1578 | .vidioc_s_std = vpif_s_std, | ||
1579 | .vidioc_g_std = vpif_g_std, | ||
1580 | .vidioc_enum_output = vpif_enum_output, | ||
1581 | .vidioc_s_output = vpif_s_output, | ||
1582 | .vidioc_g_output = vpif_g_output, | ||
1583 | .vidioc_cropcap = vpif_cropcap, | ||
1584 | .vidioc_enum_dv_presets = vpif_enum_dv_presets, | ||
1585 | .vidioc_s_dv_preset = vpif_s_dv_preset, | ||
1586 | .vidioc_g_dv_preset = vpif_g_dv_preset, | ||
1587 | .vidioc_s_dv_timings = vpif_s_dv_timings, | ||
1588 | .vidioc_g_dv_timings = vpif_g_dv_timings, | ||
1589 | .vidioc_g_chip_ident = vpif_g_chip_ident, | ||
1590 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1591 | .vidioc_g_register = vpif_dbg_g_register, | ||
1592 | .vidioc_s_register = vpif_dbg_s_register, | ||
1593 | #endif | ||
1594 | .vidioc_log_status = vpif_log_status, | ||
1595 | }; | ||
1596 | |||
1597 | static const struct v4l2_file_operations vpif_fops = { | ||
1598 | .owner = THIS_MODULE, | ||
1599 | .open = vpif_open, | ||
1600 | .release = vpif_release, | ||
1601 | .unlocked_ioctl = video_ioctl2, | ||
1602 | .mmap = vpif_mmap, | ||
1603 | .poll = vpif_poll | ||
1604 | }; | ||
1605 | |||
1606 | static struct video_device vpif_video_template = { | ||
1607 | .name = "vpif", | ||
1608 | .fops = &vpif_fops, | ||
1609 | .ioctl_ops = &vpif_ioctl_ops, | ||
1610 | .tvnorms = DM646X_V4L2_STD, | ||
1611 | .current_norm = V4L2_STD_625_50, | ||
1612 | |||
1613 | }; | ||
1614 | |||
1615 | /*Configure the channels, buffer sizei, request irq */ | ||
1616 | static int initialize_vpif(void) | ||
1617 | { | ||
1618 | int free_channel_objects_index; | ||
1619 | int free_buffer_channel_index; | ||
1620 | int free_buffer_index; | ||
1621 | int err = 0, i, j; | ||
1622 | |||
1623 | /* Default number of buffers should be 3 */ | ||
1624 | if ((ch2_numbuffers > 0) && | ||
1625 | (ch2_numbuffers < config_params.min_numbuffers)) | ||
1626 | ch2_numbuffers = config_params.min_numbuffers; | ||
1627 | if ((ch3_numbuffers > 0) && | ||
1628 | (ch3_numbuffers < config_params.min_numbuffers)) | ||
1629 | ch3_numbuffers = config_params.min_numbuffers; | ||
1630 | |||
1631 | /* Set buffer size to min buffers size if invalid buffer size is | ||
1632 | * given */ | ||
1633 | if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]) | ||
1634 | ch2_bufsize = | ||
1635 | config_params.min_bufsize[VPIF_CHANNEL2_VIDEO]; | ||
1636 | if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]) | ||
1637 | ch3_bufsize = | ||
1638 | config_params.min_bufsize[VPIF_CHANNEL3_VIDEO]; | ||
1639 | |||
1640 | config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers; | ||
1641 | |||
1642 | if (ch2_numbuffers) { | ||
1643 | config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] = | ||
1644 | ch2_bufsize; | ||
1645 | } | ||
1646 | config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers; | ||
1647 | |||
1648 | if (ch3_numbuffers) { | ||
1649 | config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] = | ||
1650 | ch3_bufsize; | ||
1651 | } | ||
1652 | |||
1653 | /* Allocate memory for six channel objects */ | ||
1654 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
1655 | vpif_obj.dev[i] = | ||
1656 | kzalloc(sizeof(struct channel_obj), GFP_KERNEL); | ||
1657 | /* If memory allocation fails, return error */ | ||
1658 | if (!vpif_obj.dev[i]) { | ||
1659 | free_channel_objects_index = i; | ||
1660 | err = -ENOMEM; | ||
1661 | goto vpif_init_free_channel_objects; | ||
1662 | } | ||
1663 | } | ||
1664 | |||
1665 | free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES; | ||
1666 | free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS; | ||
1667 | free_buffer_index = config_params.numbuffers[i - 1]; | ||
1668 | |||
1669 | return 0; | ||
1670 | |||
1671 | vpif_init_free_channel_objects: | ||
1672 | for (j = 0; j < free_channel_objects_index; j++) | ||
1673 | kfree(vpif_obj.dev[j]); | ||
1674 | return err; | ||
1675 | } | ||
1676 | |||
1677 | /* | ||
1678 | * vpif_probe: This function creates device entries by register itself to the | ||
1679 | * V4L2 driver and initializes fields of each channel objects | ||
1680 | */ | ||
1681 | static __init int vpif_probe(struct platform_device *pdev) | ||
1682 | { | ||
1683 | struct vpif_subdev_info *subdevdata; | ||
1684 | struct vpif_display_config *config; | ||
1685 | int i, j = 0, k, q, m, err = 0; | ||
1686 | struct i2c_adapter *i2c_adap; | ||
1687 | struct common_obj *common; | ||
1688 | struct channel_obj *ch; | ||
1689 | struct video_device *vfd; | ||
1690 | struct resource *res; | ||
1691 | int subdev_count; | ||
1692 | |||
1693 | vpif_dev = &pdev->dev; | ||
1694 | |||
1695 | err = initialize_vpif(); | ||
1696 | |||
1697 | if (err) { | ||
1698 | v4l2_err(vpif_dev->driver, "Error initializing vpif\n"); | ||
1699 | return err; | ||
1700 | } | ||
1701 | |||
1702 | err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); | ||
1703 | if (err) { | ||
1704 | v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); | ||
1705 | return err; | ||
1706 | } | ||
1707 | |||
1708 | k = 0; | ||
1709 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { | ||
1710 | for (i = res->start; i <= res->end; i++) { | ||
1711 | if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, | ||
1712 | "DM646x_Display", | ||
1713 | (void *)(&vpif_obj.dev[k]->channel_id))) { | ||
1714 | err = -EBUSY; | ||
1715 | goto vpif_int_err; | ||
1716 | } | ||
1717 | } | ||
1718 | k++; | ||
1719 | } | ||
1720 | |||
1721 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
1722 | |||
1723 | /* Get the pointer to the channel object */ | ||
1724 | ch = vpif_obj.dev[i]; | ||
1725 | |||
1726 | /* Allocate memory for video device */ | ||
1727 | vfd = video_device_alloc(); | ||
1728 | if (vfd == NULL) { | ||
1729 | for (j = 0; j < i; j++) { | ||
1730 | ch = vpif_obj.dev[j]; | ||
1731 | video_device_release(ch->video_dev); | ||
1732 | } | ||
1733 | err = -ENOMEM; | ||
1734 | goto vpif_int_err; | ||
1735 | } | ||
1736 | |||
1737 | /* Initialize field of video device */ | ||
1738 | *vfd = vpif_video_template; | ||
1739 | vfd->v4l2_dev = &vpif_obj.v4l2_dev; | ||
1740 | vfd->release = video_device_release; | ||
1741 | snprintf(vfd->name, sizeof(vfd->name), | ||
1742 | "DM646x_VPIFDisplay_DRIVER_V%s", | ||
1743 | VPIF_DISPLAY_VERSION); | ||
1744 | |||
1745 | /* Set video_dev to the video device */ | ||
1746 | ch->video_dev = vfd; | ||
1747 | } | ||
1748 | |||
1749 | for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { | ||
1750 | ch = vpif_obj.dev[j]; | ||
1751 | /* Initialize field of the channel objects */ | ||
1752 | atomic_set(&ch->usrs, 0); | ||
1753 | for (k = 0; k < VPIF_NUMOBJECTS; k++) { | ||
1754 | ch->common[k].numbuffers = 0; | ||
1755 | common = &ch->common[k]; | ||
1756 | common->io_usrs = 0; | ||
1757 | common->started = 0; | ||
1758 | spin_lock_init(&common->irqlock); | ||
1759 | mutex_init(&common->lock); | ||
1760 | common->numbuffers = 0; | ||
1761 | common->set_addr = NULL; | ||
1762 | common->ytop_off = common->ybtm_off = 0; | ||
1763 | common->ctop_off = common->cbtm_off = 0; | ||
1764 | common->cur_frm = common->next_frm = NULL; | ||
1765 | memset(&common->fmt, 0, sizeof(common->fmt)); | ||
1766 | common->numbuffers = config_params.numbuffers[k]; | ||
1767 | |||
1768 | } | ||
1769 | ch->initialized = 0; | ||
1770 | ch->channel_id = j; | ||
1771 | if (j < 2) | ||
1772 | ch->common[VPIF_VIDEO_INDEX].numbuffers = | ||
1773 | config_params.numbuffers[ch->channel_id]; | ||
1774 | else | ||
1775 | ch->common[VPIF_VIDEO_INDEX].numbuffers = 0; | ||
1776 | |||
1777 | memset(&ch->vpifparams, 0, sizeof(ch->vpifparams)); | ||
1778 | |||
1779 | /* Initialize prio member of channel object */ | ||
1780 | v4l2_prio_init(&ch->prio); | ||
1781 | ch->common[VPIF_VIDEO_INDEX].fmt.type = | ||
1782 | V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
1783 | ch->video_dev->lock = &common->lock; | ||
1784 | |||
1785 | /* register video device */ | ||
1786 | vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", | ||
1787 | (int)ch, (int)&ch->video_dev); | ||
1788 | |||
1789 | err = video_register_device(ch->video_dev, | ||
1790 | VFL_TYPE_GRABBER, (j ? 3 : 2)); | ||
1791 | if (err < 0) | ||
1792 | goto probe_out; | ||
1793 | |||
1794 | video_set_drvdata(ch->video_dev, ch); | ||
1795 | } | ||
1796 | |||
1797 | i2c_adap = i2c_get_adapter(1); | ||
1798 | config = pdev->dev.platform_data; | ||
1799 | subdev_count = config->subdev_count; | ||
1800 | subdevdata = config->subdevinfo; | ||
1801 | vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, | ||
1802 | GFP_KERNEL); | ||
1803 | if (vpif_obj.sd == NULL) { | ||
1804 | vpif_err("unable to allocate memory for subdevice pointers\n"); | ||
1805 | err = -ENOMEM; | ||
1806 | goto probe_out; | ||
1807 | } | ||
1808 | |||
1809 | for (i = 0; i < subdev_count; i++) { | ||
1810 | vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, | ||
1811 | i2c_adap, | ||
1812 | &subdevdata[i].board_info, | ||
1813 | NULL); | ||
1814 | if (!vpif_obj.sd[i]) { | ||
1815 | vpif_err("Error registering v4l2 subdevice\n"); | ||
1816 | goto probe_subdev_out; | ||
1817 | } | ||
1818 | |||
1819 | if (vpif_obj.sd[i]) | ||
1820 | vpif_obj.sd[i]->grp_id = 1 << i; | ||
1821 | } | ||
1822 | |||
1823 | v4l2_info(&vpif_obj.v4l2_dev, | ||
1824 | "DM646x VPIF display driver initialized\n"); | ||
1825 | return 0; | ||
1826 | |||
1827 | probe_subdev_out: | ||
1828 | kfree(vpif_obj.sd); | ||
1829 | probe_out: | ||
1830 | for (k = 0; k < j; k++) { | ||
1831 | ch = vpif_obj.dev[k]; | ||
1832 | video_unregister_device(ch->video_dev); | ||
1833 | video_device_release(ch->video_dev); | ||
1834 | ch->video_dev = NULL; | ||
1835 | } | ||
1836 | vpif_int_err: | ||
1837 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
1838 | vpif_err("VPIF IRQ request failed\n"); | ||
1839 | for (q = k; k >= 0; k--) { | ||
1840 | for (m = i; m >= res->start; m--) | ||
1841 | free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); | ||
1842 | res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); | ||
1843 | m = res->end; | ||
1844 | } | ||
1845 | |||
1846 | return err; | ||
1847 | } | ||
1848 | |||
1849 | /* | ||
1850 | * vpif_remove: It un-register channels from V4L2 driver | ||
1851 | */ | ||
1852 | static int vpif_remove(struct platform_device *device) | ||
1853 | { | ||
1854 | struct channel_obj *ch; | ||
1855 | int i; | ||
1856 | |||
1857 | v4l2_device_unregister(&vpif_obj.v4l2_dev); | ||
1858 | |||
1859 | /* un-register device */ | ||
1860 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { | ||
1861 | /* Get the pointer to the channel object */ | ||
1862 | ch = vpif_obj.dev[i]; | ||
1863 | /* Unregister video device */ | ||
1864 | video_unregister_device(ch->video_dev); | ||
1865 | |||
1866 | ch->video_dev = NULL; | ||
1867 | } | ||
1868 | |||
1869 | return 0; | ||
1870 | } | ||
1871 | |||
1872 | static __refdata struct platform_driver vpif_driver = { | ||
1873 | .driver = { | ||
1874 | .name = "vpif_display", | ||
1875 | .owner = THIS_MODULE, | ||
1876 | }, | ||
1877 | .probe = vpif_probe, | ||
1878 | .remove = vpif_remove, | ||
1879 | }; | ||
1880 | |||
1881 | static __init int vpif_init(void) | ||
1882 | { | ||
1883 | return platform_driver_register(&vpif_driver); | ||
1884 | } | ||
1885 | |||
1886 | /* | ||
1887 | * vpif_cleanup: This function un-registers device and driver to the kernel, | ||
1888 | * frees requested irq handler and de-allocates memory allocated for channel | ||
1889 | * objects. | ||
1890 | */ | ||
1891 | static void vpif_cleanup(void) | ||
1892 | { | ||
1893 | struct platform_device *pdev; | ||
1894 | struct resource *res; | ||
1895 | int irq_num; | ||
1896 | int i = 0; | ||
1897 | |||
1898 | pdev = container_of(vpif_dev, struct platform_device, dev); | ||
1899 | |||
1900 | while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, i))) { | ||
1901 | for (irq_num = res->start; irq_num <= res->end; irq_num++) | ||
1902 | free_irq(irq_num, | ||
1903 | (void *)(&vpif_obj.dev[i]->channel_id)); | ||
1904 | i++; | ||
1905 | } | ||
1906 | |||
1907 | platform_driver_unregister(&vpif_driver); | ||
1908 | kfree(vpif_obj.sd); | ||
1909 | for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) | ||
1910 | kfree(vpif_obj.dev[i]); | ||
1911 | } | ||
1912 | |||
1913 | module_init(vpif_init); | ||
1914 | module_exit(vpif_cleanup); | ||
diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h new file mode 100644 index 00000000000..5d1936dafed --- /dev/null +++ b/drivers/media/video/davinci/vpif_display.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * DM646x display header file | ||
3 | * | ||
4 | * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed .as is. WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #ifndef DAVINCIHD_DISPLAY_H | ||
17 | #define DAVINCIHD_DISPLAY_H | ||
18 | |||
19 | /* Header files */ | ||
20 | #include <linux/videodev2.h> | ||
21 | #include <media/v4l2-common.h> | ||
22 | #include <media/v4l2-device.h> | ||
23 | #include <media/videobuf-core.h> | ||
24 | #include <media/videobuf-dma-contig.h> | ||
25 | |||
26 | #include "vpif.h" | ||
27 | |||
28 | /* Macros */ | ||
29 | #define VPIF_DISPLAY_VERSION "0.0.2" | ||
30 | |||
31 | #define VPIF_VALID_FIELD(field) \ | ||
32 | (((V4L2_FIELD_ANY == field) || (V4L2_FIELD_NONE == field)) || \ | ||
33 | (((V4L2_FIELD_INTERLACED == field) || (V4L2_FIELD_SEQ_TB == field)) || \ | ||
34 | (V4L2_FIELD_SEQ_BT == field))) | ||
35 | |||
36 | #define VPIF_DISPLAY_MAX_DEVICES (2) | ||
37 | #define VPIF_SLICED_BUF_SIZE (256) | ||
38 | #define VPIF_SLICED_MAX_SERVICES (3) | ||
39 | #define VPIF_VIDEO_INDEX (0) | ||
40 | #define VPIF_VBI_INDEX (1) | ||
41 | #define VPIF_HBI_INDEX (2) | ||
42 | |||
43 | /* Setting it to 1 as HBI/VBI support yet to be added , else 3*/ | ||
44 | #define VPIF_NUMOBJECTS (1) | ||
45 | |||
46 | /* Macros */ | ||
47 | #define ISALIGNED(a) (0 == ((a) & 7)) | ||
48 | |||
49 | /* enumerated data types */ | ||
50 | /* Enumerated data type to give id to each device per channel */ | ||
51 | enum vpif_channel_id { | ||
52 | VPIF_CHANNEL2_VIDEO = 0, /* Channel2 Video */ | ||
53 | VPIF_CHANNEL3_VIDEO, /* Channel3 Video */ | ||
54 | }; | ||
55 | |||
56 | /* structures */ | ||
57 | |||
58 | struct video_obj { | ||
59 | enum v4l2_field buf_field; | ||
60 | u32 latest_only; /* indicate whether to return | ||
61 | * most recent displayed frame only */ | ||
62 | v4l2_std_id stdid; /* Currently selected or default | ||
63 | * standard */ | ||
64 | u32 dv_preset; | ||
65 | struct v4l2_bt_timings bt_timings; | ||
66 | u32 output_id; /* Current output id */ | ||
67 | }; | ||
68 | |||
69 | struct vbi_obj { | ||
70 | int num_services; | ||
71 | struct vpif_vbi_params vbiparams; /* vpif parameters for the raw | ||
72 | * vbi data */ | ||
73 | }; | ||
74 | |||
75 | struct common_obj { | ||
76 | /* Buffer specific parameters */ | ||
77 | u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for | ||
78 | * storing frames */ | ||
79 | u32 numbuffers; /* number of buffers */ | ||
80 | struct videobuf_buffer *cur_frm; /* Pointer pointing to current | ||
81 | * videobuf_buffer */ | ||
82 | struct videobuf_buffer *next_frm; /* Pointer pointing to next | ||
83 | * videobuf_buffer */ | ||
84 | enum v4l2_memory memory; /* This field keeps track of | ||
85 | * type of buffer exchange | ||
86 | * method user has selected */ | ||
87 | struct v4l2_format fmt; /* Used to store the format */ | ||
88 | struct videobuf_queue buffer_queue; /* Buffer queue used in | ||
89 | * video-buf */ | ||
90 | struct list_head dma_queue; /* Queue of filled frames */ | ||
91 | spinlock_t irqlock; /* Used in video-buf */ | ||
92 | |||
93 | /* channel specific parameters */ | ||
94 | struct mutex lock; /* lock used to access this | ||
95 | * structure */ | ||
96 | u32 io_usrs; /* number of users performing | ||
97 | * IO */ | ||
98 | u8 started; /* Indicates whether streaming | ||
99 | * started */ | ||
100 | u32 ytop_off; /* offset of Y top from the | ||
101 | * starting of the buffer */ | ||
102 | u32 ybtm_off; /* offset of Y bottom from the | ||
103 | * starting of the buffer */ | ||
104 | u32 ctop_off; /* offset of C top from the | ||
105 | * starting of the buffer */ | ||
106 | u32 cbtm_off; /* offset of C bottom from the | ||
107 | * starting of the buffer */ | ||
108 | /* Function pointer to set the addresses */ | ||
109 | void (*set_addr) (unsigned long, unsigned long, | ||
110 | unsigned long, unsigned long); | ||
111 | u32 height; | ||
112 | u32 width; | ||
113 | }; | ||
114 | |||
115 | struct channel_obj { | ||
116 | /* V4l2 specific parameters */ | ||
117 | struct video_device *video_dev; /* Identifies video device for | ||
118 | * this channel */ | ||
119 | struct v4l2_prio_state prio; /* Used to keep track of state of | ||
120 | * the priority */ | ||
121 | atomic_t usrs; /* number of open instances of | ||
122 | * the channel */ | ||
123 | u32 field_id; /* Indicates id of the field | ||
124 | * which is being displayed */ | ||
125 | u8 initialized; /* flag to indicate whether | ||
126 | * encoder is initialized */ | ||
127 | |||
128 | enum vpif_channel_id channel_id;/* Identifies channel */ | ||
129 | struct vpif_params vpifparams; | ||
130 | struct common_obj common[VPIF_NUMOBJECTS]; | ||
131 | struct video_obj video; | ||
132 | struct vbi_obj vbi; | ||
133 | }; | ||
134 | |||
135 | /* File handle structure */ | ||
136 | struct vpif_fh { | ||
137 | struct channel_obj *channel; /* pointer to channel object for | ||
138 | * opened device */ | ||
139 | u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle | ||
140 | * is doing IO */ | ||
141 | enum v4l2_priority prio; /* Used to keep track priority of | ||
142 | * this instance */ | ||
143 | u8 initialized; /* Used to keep track of whether this | ||
144 | * file handle has initialized | ||
145 | * channel or not */ | ||
146 | }; | ||
147 | |||
148 | /* vpif device structure */ | ||
149 | struct vpif_device { | ||
150 | struct v4l2_device v4l2_dev; | ||
151 | struct channel_obj *dev[VPIF_DISPLAY_NUM_CHANNELS]; | ||
152 | struct v4l2_subdev **sd; | ||
153 | |||
154 | }; | ||
155 | |||
156 | struct vpif_config_params { | ||
157 | u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; | ||
158 | u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; | ||
159 | u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; | ||
160 | u8 min_numbuffers; | ||
161 | }; | ||
162 | |||
163 | /* Struct which keeps track of the line numbers for the sliced vbi service */ | ||
164 | struct vpif_service_line { | ||
165 | u16 service_id; | ||
166 | u16 service_line[2]; | ||
167 | u16 enc_service_id; | ||
168 | u8 bytestowrite; | ||
169 | }; | ||
170 | |||
171 | #endif /* DAVINCIHD_DISPLAY_H */ | ||
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c new file mode 100644 index 00000000000..3e5cf27ec2b --- /dev/null +++ b/drivers/media/video/davinci/vpss.c | |||
@@ -0,0 +1,482 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Texas Instruments. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | * | ||
18 | * common vpss system module platform driver for all video drivers. | ||
19 | */ | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/compiler.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <mach/hardware.h> | ||
29 | #include <media/davinci/vpss.h> | ||
30 | |||
31 | MODULE_LICENSE("GPL"); | ||
32 | MODULE_DESCRIPTION("VPSS Driver"); | ||
33 | MODULE_AUTHOR("Texas Instruments"); | ||
34 | |||
35 | /* DM644x defines */ | ||
36 | #define DM644X_SBL_PCR_VPSS (4) | ||
37 | |||
38 | #define DM355_VPSSBL_INTSEL 0x10 | ||
39 | #define DM355_VPSSBL_EVTSEL 0x14 | ||
40 | /* vpss BL register offsets */ | ||
41 | #define DM355_VPSSBL_CCDCMUX 0x1c | ||
42 | /* vpss CLK register offsets */ | ||
43 | #define DM355_VPSSCLK_CLKCTRL 0x04 | ||
44 | /* masks and shifts */ | ||
45 | #define VPSS_HSSISEL_SHIFT 4 | ||
46 | /* | ||
47 | * VDINT0 - vpss_int0, VDINT1 - vpss_int1, H3A - vpss_int4, | ||
48 | * IPIPE_INT1_SDR - vpss_int5 | ||
49 | */ | ||
50 | #define DM355_VPSSBL_INTSEL_DEFAULT 0xff83ff10 | ||
51 | /* VENCINT - vpss_int8 */ | ||
52 | #define DM355_VPSSBL_EVTSEL_DEFAULT 0x4 | ||
53 | |||
54 | #define DM365_ISP5_PCCR 0x04 | ||
55 | #define DM365_ISP5_INTSEL1 0x10 | ||
56 | #define DM365_ISP5_INTSEL2 0x14 | ||
57 | #define DM365_ISP5_INTSEL3 0x18 | ||
58 | #define DM365_ISP5_CCDCMUX 0x20 | ||
59 | #define DM365_ISP5_PG_FRAME_SIZE 0x28 | ||
60 | #define DM365_VPBE_CLK_CTRL 0x00 | ||
61 | /* | ||
62 | * vpss interrupts. VDINT0 - vpss_int0, VDINT1 - vpss_int1, | ||
63 | * AF - vpss_int3 | ||
64 | */ | ||
65 | #define DM365_ISP5_INTSEL1_DEFAULT 0x0b1f0100 | ||
66 | /* AEW - vpss_int6, RSZ_INT_DMA - vpss_int5 */ | ||
67 | #define DM365_ISP5_INTSEL2_DEFAULT 0x1f0a0f1f | ||
68 | /* VENC - vpss_int8 */ | ||
69 | #define DM365_ISP5_INTSEL3_DEFAULT 0x00000015 | ||
70 | |||
71 | /* masks and shifts for DM365*/ | ||
72 | #define DM365_CCDC_PG_VD_POL_SHIFT 0 | ||
73 | #define DM365_CCDC_PG_HD_POL_SHIFT 1 | ||
74 | |||
75 | #define CCD_SRC_SEL_MASK (BIT_MASK(5) | BIT_MASK(4)) | ||
76 | #define CCD_SRC_SEL_SHIFT 4 | ||
77 | |||
78 | /* Different SoC platforms supported by this driver */ | ||
79 | enum vpss_platform_type { | ||
80 | DM644X, | ||
81 | DM355, | ||
82 | DM365, | ||
83 | }; | ||
84 | |||
85 | /* | ||
86 | * vpss operations. Depends on platform. Not all functions are available | ||
87 | * on all platforms. The api, first check if a functio is available before | ||
88 | * invoking it. In the probe, the function ptrs are initialized based on | ||
89 | * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. | ||
90 | */ | ||
91 | struct vpss_hw_ops { | ||
92 | /* enable clock */ | ||
93 | int (*enable_clock)(enum vpss_clock_sel clock_sel, int en); | ||
94 | /* select input to ccdc */ | ||
95 | void (*select_ccdc_source)(enum vpss_ccdc_source_sel src_sel); | ||
96 | /* clear wbl overflow bit */ | ||
97 | int (*clear_wbl_overflow)(enum vpss_wbl_sel wbl_sel); | ||
98 | }; | ||
99 | |||
100 | /* vpss configuration */ | ||
101 | struct vpss_oper_config { | ||
102 | __iomem void *vpss_regs_base0; | ||
103 | __iomem void *vpss_regs_base1; | ||
104 | enum vpss_platform_type platform; | ||
105 | spinlock_t vpss_lock; | ||
106 | struct vpss_hw_ops hw_ops; | ||
107 | }; | ||
108 | |||
109 | static struct vpss_oper_config oper_cfg; | ||
110 | |||
111 | /* register access routines */ | ||
112 | static inline u32 bl_regr(u32 offset) | ||
113 | { | ||
114 | return __raw_readl(oper_cfg.vpss_regs_base0 + offset); | ||
115 | } | ||
116 | |||
117 | static inline void bl_regw(u32 val, u32 offset) | ||
118 | { | ||
119 | __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); | ||
120 | } | ||
121 | |||
122 | static inline u32 vpss_regr(u32 offset) | ||
123 | { | ||
124 | return __raw_readl(oper_cfg.vpss_regs_base1 + offset); | ||
125 | } | ||
126 | |||
127 | static inline void vpss_regw(u32 val, u32 offset) | ||
128 | { | ||
129 | __raw_writel(val, oper_cfg.vpss_regs_base1 + offset); | ||
130 | } | ||
131 | |||
132 | /* For DM365 only */ | ||
133 | static inline u32 isp5_read(u32 offset) | ||
134 | { | ||
135 | return __raw_readl(oper_cfg.vpss_regs_base0 + offset); | ||
136 | } | ||
137 | |||
138 | /* For DM365 only */ | ||
139 | static inline void isp5_write(u32 val, u32 offset) | ||
140 | { | ||
141 | __raw_writel(val, oper_cfg.vpss_regs_base0 + offset); | ||
142 | } | ||
143 | |||
144 | static void dm365_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) | ||
145 | { | ||
146 | u32 temp = isp5_read(DM365_ISP5_CCDCMUX) & ~CCD_SRC_SEL_MASK; | ||
147 | |||
148 | /* if we are using pattern generator, enable it */ | ||
149 | if (src_sel == VPSS_PGLPBK || src_sel == VPSS_CCDCPG) | ||
150 | temp |= 0x08; | ||
151 | |||
152 | temp |= (src_sel << CCD_SRC_SEL_SHIFT); | ||
153 | isp5_write(temp, DM365_ISP5_CCDCMUX); | ||
154 | } | ||
155 | |||
156 | static void dm355_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) | ||
157 | { | ||
158 | bl_regw(src_sel << VPSS_HSSISEL_SHIFT, DM355_VPSSBL_CCDCMUX); | ||
159 | } | ||
160 | |||
161 | int vpss_select_ccdc_source(enum vpss_ccdc_source_sel src_sel) | ||
162 | { | ||
163 | if (!oper_cfg.hw_ops.select_ccdc_source) | ||
164 | return -EINVAL; | ||
165 | |||
166 | oper_cfg.hw_ops.select_ccdc_source(src_sel); | ||
167 | return 0; | ||
168 | } | ||
169 | EXPORT_SYMBOL(vpss_select_ccdc_source); | ||
170 | |||
171 | static int dm644x_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) | ||
172 | { | ||
173 | u32 mask = 1, val; | ||
174 | |||
175 | if (wbl_sel < VPSS_PCR_AEW_WBL_0 || | ||
176 | wbl_sel > VPSS_PCR_CCDC_WBL_O) | ||
177 | return -EINVAL; | ||
178 | |||
179 | /* writing a 0 clear the overflow */ | ||
180 | mask = ~(mask << wbl_sel); | ||
181 | val = bl_regr(DM644X_SBL_PCR_VPSS) & mask; | ||
182 | bl_regw(val, DM644X_SBL_PCR_VPSS); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | int vpss_clear_wbl_overflow(enum vpss_wbl_sel wbl_sel) | ||
187 | { | ||
188 | if (!oper_cfg.hw_ops.clear_wbl_overflow) | ||
189 | return -EINVAL; | ||
190 | |||
191 | return oper_cfg.hw_ops.clear_wbl_overflow(wbl_sel); | ||
192 | } | ||
193 | EXPORT_SYMBOL(vpss_clear_wbl_overflow); | ||
194 | |||
195 | /* | ||
196 | * dm355_enable_clock - Enable VPSS Clock | ||
197 | * @clock_sel: CLock to be enabled/disabled | ||
198 | * @en: enable/disable flag | ||
199 | * | ||
200 | * This is called to enable or disable a vpss clock | ||
201 | */ | ||
202 | static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) | ||
203 | { | ||
204 | unsigned long flags; | ||
205 | u32 utemp, mask = 0x1, shift = 0; | ||
206 | |||
207 | switch (clock_sel) { | ||
208 | case VPSS_VPBE_CLOCK: | ||
209 | /* nothing since lsb */ | ||
210 | break; | ||
211 | case VPSS_VENC_CLOCK_SEL: | ||
212 | shift = 2; | ||
213 | break; | ||
214 | case VPSS_CFALD_CLOCK: | ||
215 | shift = 3; | ||
216 | break; | ||
217 | case VPSS_H3A_CLOCK: | ||
218 | shift = 4; | ||
219 | break; | ||
220 | case VPSS_IPIPE_CLOCK: | ||
221 | shift = 5; | ||
222 | break; | ||
223 | case VPSS_CCDC_CLOCK: | ||
224 | shift = 6; | ||
225 | break; | ||
226 | default: | ||
227 | printk(KERN_ERR "dm355_enable_clock:" | ||
228 | " Invalid selector: %d\n", clock_sel); | ||
229 | return -EINVAL; | ||
230 | } | ||
231 | |||
232 | spin_lock_irqsave(&oper_cfg.vpss_lock, flags); | ||
233 | utemp = vpss_regr(DM355_VPSSCLK_CLKCTRL); | ||
234 | if (!en) | ||
235 | utemp &= ~(mask << shift); | ||
236 | else | ||
237 | utemp |= (mask << shift); | ||
238 | |||
239 | vpss_regw(utemp, DM355_VPSSCLK_CLKCTRL); | ||
240 | spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static int dm365_enable_clock(enum vpss_clock_sel clock_sel, int en) | ||
245 | { | ||
246 | unsigned long flags; | ||
247 | u32 utemp, mask = 0x1, shift = 0, offset = DM365_ISP5_PCCR; | ||
248 | u32 (*read)(u32 offset) = isp5_read; | ||
249 | void(*write)(u32 val, u32 offset) = isp5_write; | ||
250 | |||
251 | switch (clock_sel) { | ||
252 | case VPSS_BL_CLOCK: | ||
253 | break; | ||
254 | case VPSS_CCDC_CLOCK: | ||
255 | shift = 1; | ||
256 | break; | ||
257 | case VPSS_H3A_CLOCK: | ||
258 | shift = 2; | ||
259 | break; | ||
260 | case VPSS_RSZ_CLOCK: | ||
261 | shift = 3; | ||
262 | break; | ||
263 | case VPSS_IPIPE_CLOCK: | ||
264 | shift = 4; | ||
265 | break; | ||
266 | case VPSS_IPIPEIF_CLOCK: | ||
267 | shift = 5; | ||
268 | break; | ||
269 | case VPSS_PCLK_INTERNAL: | ||
270 | shift = 6; | ||
271 | break; | ||
272 | case VPSS_PSYNC_CLOCK_SEL: | ||
273 | shift = 7; | ||
274 | break; | ||
275 | case VPSS_VPBE_CLOCK: | ||
276 | read = vpss_regr; | ||
277 | write = vpss_regw; | ||
278 | offset = DM365_VPBE_CLK_CTRL; | ||
279 | break; | ||
280 | case VPSS_VENC_CLOCK_SEL: | ||
281 | shift = 2; | ||
282 | read = vpss_regr; | ||
283 | write = vpss_regw; | ||
284 | offset = DM365_VPBE_CLK_CTRL; | ||
285 | break; | ||
286 | case VPSS_LDC_CLOCK: | ||
287 | shift = 3; | ||
288 | read = vpss_regr; | ||
289 | write = vpss_regw; | ||
290 | offset = DM365_VPBE_CLK_CTRL; | ||
291 | break; | ||
292 | case VPSS_FDIF_CLOCK: | ||
293 | shift = 4; | ||
294 | read = vpss_regr; | ||
295 | write = vpss_regw; | ||
296 | offset = DM365_VPBE_CLK_CTRL; | ||
297 | break; | ||
298 | case VPSS_OSD_CLOCK_SEL: | ||
299 | shift = 6; | ||
300 | read = vpss_regr; | ||
301 | write = vpss_regw; | ||
302 | offset = DM365_VPBE_CLK_CTRL; | ||
303 | break; | ||
304 | case VPSS_LDC_CLOCK_SEL: | ||
305 | shift = 7; | ||
306 | read = vpss_regr; | ||
307 | write = vpss_regw; | ||
308 | offset = DM365_VPBE_CLK_CTRL; | ||
309 | break; | ||
310 | default: | ||
311 | printk(KERN_ERR "dm365_enable_clock: Invalid selector: %d\n", | ||
312 | clock_sel); | ||
313 | return -1; | ||
314 | } | ||
315 | |||
316 | spin_lock_irqsave(&oper_cfg.vpss_lock, flags); | ||
317 | utemp = read(offset); | ||
318 | if (!en) { | ||
319 | mask = ~mask; | ||
320 | utemp &= (mask << shift); | ||
321 | } else | ||
322 | utemp |= (mask << shift); | ||
323 | |||
324 | write(utemp, offset); | ||
325 | spin_unlock_irqrestore(&oper_cfg.vpss_lock, flags); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | int vpss_enable_clock(enum vpss_clock_sel clock_sel, int en) | ||
331 | { | ||
332 | if (!oper_cfg.hw_ops.enable_clock) | ||
333 | return -EINVAL; | ||
334 | |||
335 | return oper_cfg.hw_ops.enable_clock(clock_sel, en); | ||
336 | } | ||
337 | EXPORT_SYMBOL(vpss_enable_clock); | ||
338 | |||
339 | void dm365_vpss_set_sync_pol(struct vpss_sync_pol sync) | ||
340 | { | ||
341 | int val = 0; | ||
342 | val = isp5_read(DM365_ISP5_CCDCMUX); | ||
343 | |||
344 | val |= (sync.ccdpg_hdpol << DM365_CCDC_PG_HD_POL_SHIFT); | ||
345 | val |= (sync.ccdpg_vdpol << DM365_CCDC_PG_VD_POL_SHIFT); | ||
346 | |||
347 | isp5_write(val, DM365_ISP5_CCDCMUX); | ||
348 | } | ||
349 | EXPORT_SYMBOL(dm365_vpss_set_sync_pol); | ||
350 | |||
351 | void dm365_vpss_set_pg_frame_size(struct vpss_pg_frame_size frame_size) | ||
352 | { | ||
353 | int current_reg = ((frame_size.hlpfr >> 1) - 1) << 16; | ||
354 | |||
355 | current_reg |= (frame_size.pplen - 1); | ||
356 | isp5_write(current_reg, DM365_ISP5_PG_FRAME_SIZE); | ||
357 | } | ||
358 | EXPORT_SYMBOL(dm365_vpss_set_pg_frame_size); | ||
359 | |||
360 | static int __init vpss_probe(struct platform_device *pdev) | ||
361 | { | ||
362 | struct resource *r1, *r2; | ||
363 | char *platform_name; | ||
364 | int status; | ||
365 | |||
366 | if (!pdev->dev.platform_data) { | ||
367 | dev_err(&pdev->dev, "no platform data\n"); | ||
368 | return -ENOENT; | ||
369 | } | ||
370 | |||
371 | platform_name = pdev->dev.platform_data; | ||
372 | if (!strcmp(platform_name, "dm355_vpss")) | ||
373 | oper_cfg.platform = DM355; | ||
374 | else if (!strcmp(platform_name, "dm365_vpss")) | ||
375 | oper_cfg.platform = DM365; | ||
376 | else if (!strcmp(platform_name, "dm644x_vpss")) | ||
377 | oper_cfg.platform = DM644X; | ||
378 | else { | ||
379 | dev_err(&pdev->dev, "vpss driver not supported on" | ||
380 | " this platform\n"); | ||
381 | return -ENODEV; | ||
382 | } | ||
383 | |||
384 | dev_info(&pdev->dev, "%s vpss probed\n", platform_name); | ||
385 | r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
386 | if (!r1) | ||
387 | return -ENOENT; | ||
388 | |||
389 | r1 = request_mem_region(r1->start, resource_size(r1), r1->name); | ||
390 | if (!r1) | ||
391 | return -EBUSY; | ||
392 | |||
393 | oper_cfg.vpss_regs_base0 = ioremap(r1->start, resource_size(r1)); | ||
394 | if (!oper_cfg.vpss_regs_base0) { | ||
395 | status = -EBUSY; | ||
396 | goto fail1; | ||
397 | } | ||
398 | |||
399 | if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { | ||
400 | r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
401 | if (!r2) { | ||
402 | status = -ENOENT; | ||
403 | goto fail2; | ||
404 | } | ||
405 | r2 = request_mem_region(r2->start, resource_size(r2), r2->name); | ||
406 | if (!r2) { | ||
407 | status = -EBUSY; | ||
408 | goto fail2; | ||
409 | } | ||
410 | |||
411 | oper_cfg.vpss_regs_base1 = ioremap(r2->start, | ||
412 | resource_size(r2)); | ||
413 | if (!oper_cfg.vpss_regs_base1) { | ||
414 | status = -EBUSY; | ||
415 | goto fail3; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | if (oper_cfg.platform == DM355) { | ||
420 | oper_cfg.hw_ops.enable_clock = dm355_enable_clock; | ||
421 | oper_cfg.hw_ops.select_ccdc_source = dm355_select_ccdc_source; | ||
422 | /* Setup vpss interrupts */ | ||
423 | bl_regw(DM355_VPSSBL_INTSEL_DEFAULT, DM355_VPSSBL_INTSEL); | ||
424 | bl_regw(DM355_VPSSBL_EVTSEL_DEFAULT, DM355_VPSSBL_EVTSEL); | ||
425 | } else if (oper_cfg.platform == DM365) { | ||
426 | oper_cfg.hw_ops.enable_clock = dm365_enable_clock; | ||
427 | oper_cfg.hw_ops.select_ccdc_source = dm365_select_ccdc_source; | ||
428 | /* Setup vpss interrupts */ | ||
429 | isp5_write(DM365_ISP5_INTSEL1_DEFAULT, DM365_ISP5_INTSEL1); | ||
430 | isp5_write(DM365_ISP5_INTSEL2_DEFAULT, DM365_ISP5_INTSEL2); | ||
431 | isp5_write(DM365_ISP5_INTSEL3_DEFAULT, DM365_ISP5_INTSEL3); | ||
432 | } else | ||
433 | oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; | ||
434 | |||
435 | spin_lock_init(&oper_cfg.vpss_lock); | ||
436 | dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); | ||
437 | return 0; | ||
438 | |||
439 | fail3: | ||
440 | release_mem_region(r2->start, resource_size(r2)); | ||
441 | fail2: | ||
442 | iounmap(oper_cfg.vpss_regs_base0); | ||
443 | fail1: | ||
444 | release_mem_region(r1->start, resource_size(r1)); | ||
445 | return status; | ||
446 | } | ||
447 | |||
448 | static int __devexit vpss_remove(struct platform_device *pdev) | ||
449 | { | ||
450 | struct resource *res; | ||
451 | |||
452 | iounmap(oper_cfg.vpss_regs_base0); | ||
453 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
454 | release_mem_region(res->start, resource_size(res)); | ||
455 | if (oper_cfg.platform == DM355 || oper_cfg.platform == DM365) { | ||
456 | iounmap(oper_cfg.vpss_regs_base1); | ||
457 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
458 | release_mem_region(res->start, resource_size(res)); | ||
459 | } | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static struct platform_driver vpss_driver = { | ||
464 | .driver = { | ||
465 | .name = "vpss", | ||
466 | .owner = THIS_MODULE, | ||
467 | }, | ||
468 | .remove = __devexit_p(vpss_remove), | ||
469 | .probe = vpss_probe, | ||
470 | }; | ||
471 | |||
472 | static void vpss_exit(void) | ||
473 | { | ||
474 | platform_driver_unregister(&vpss_driver); | ||
475 | } | ||
476 | |||
477 | static int __init vpss_init(void) | ||
478 | { | ||
479 | return platform_driver_register(&vpss_driver); | ||
480 | } | ||
481 | subsys_initcall(vpss_init); | ||
482 | module_exit(vpss_exit); | ||