]>
Commit | Line | Data |
---|---|---|
606b69e9 MH |
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. | |
606b69e9 MH |
12 | */ |
13 | #include <linux/module.h> | |
14 | #include <linux/kernel.h> | |
15 | #include <linux/init.h> | |
16 | #include <linux/ctype.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/device.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/videodev2.h> | |
22 | #include <linux/slab.h> | |
23 | ||
24 | #include <mach/hardware.h> | |
25 | #include <mach/mux.h> | |
ec2a0833 | 26 | #include <linux/platform_data/i2c-davinci.h> |
606b69e9 MH |
27 | |
28 | #include <linux/io.h> | |
29 | ||
30 | #include <media/davinci/vpbe_types.h> | |
31 | #include <media/davinci/vpbe_venc.h> | |
32 | #include <media/davinci/vpss.h> | |
33 | #include <media/v4l2-device.h> | |
34 | ||
35 | #include "vpbe_venc_regs.h" | |
36 | ||
caff80c3 LP |
37 | #define MODULE_NAME "davinci-vpbe-venc" |
38 | ||
39 | static struct platform_device_id vpbe_venc_devtype[] = { | |
40 | { | |
41 | .name = DM644X_VPBE_VENC_SUBDEV_NAME, | |
42 | .driver_data = VPBE_VERSION_1, | |
43 | }, { | |
44 | .name = DM365_VPBE_VENC_SUBDEV_NAME, | |
45 | .driver_data = VPBE_VERSION_2, | |
46 | }, { | |
47 | .name = DM355_VPBE_VENC_SUBDEV_NAME, | |
48 | .driver_data = VPBE_VERSION_3, | |
49 | }, | |
0ea21a52 LP |
50 | { |
51 | /* sentinel */ | |
52 | } | |
caff80c3 LP |
53 | }; |
54 | ||
55 | MODULE_DEVICE_TABLE(platform, vpbe_venc_devtype); | |
606b69e9 MH |
56 | |
57 | static int debug = 2; | |
58 | module_param(debug, int, 0644); | |
59 | MODULE_PARM_DESC(debug, "Debug level 0-2"); | |
60 | ||
61 | struct venc_state { | |
62 | struct v4l2_subdev sd; | |
63 | struct venc_callback *callback; | |
64 | struct venc_platform_data *pdata; | |
65 | struct device *pdev; | |
66 | u32 output; | |
67 | v4l2_std_id std; | |
68 | spinlock_t lock; | |
69 | void __iomem *venc_base; | |
70 | void __iomem *vdaccfg_reg; | |
caff80c3 | 71 | enum vpbe_version venc_type; |
606b69e9 MH |
72 | }; |
73 | ||
74 | static inline struct venc_state *to_state(struct v4l2_subdev *sd) | |
75 | { | |
76 | return container_of(sd, struct venc_state, sd); | |
77 | } | |
78 | ||
79 | static inline u32 venc_read(struct v4l2_subdev *sd, u32 offset) | |
80 | { | |
81 | struct venc_state *venc = to_state(sd); | |
82 | ||
83 | return readl(venc->venc_base + offset); | |
84 | } | |
85 | ||
86 | static inline u32 venc_write(struct v4l2_subdev *sd, u32 offset, u32 val) | |
87 | { | |
88 | struct venc_state *venc = to_state(sd); | |
89 | ||
90 | writel(val, (venc->venc_base + offset)); | |
91 | ||
92 | return val; | |
93 | } | |
94 | ||
95 | static inline u32 venc_modify(struct v4l2_subdev *sd, u32 offset, | |
96 | u32 val, u32 mask) | |
97 | { | |
98 | u32 new_val = (venc_read(sd, offset) & ~mask) | (val & mask); | |
99 | ||
100 | venc_write(sd, offset, new_val); | |
101 | ||
102 | return new_val; | |
103 | } | |
104 | ||
105 | static inline u32 vdaccfg_write(struct v4l2_subdev *sd, u32 val) | |
106 | { | |
107 | struct venc_state *venc = to_state(sd); | |
108 | ||
109 | writel(val, venc->vdaccfg_reg); | |
110 | ||
111 | val = readl(venc->vdaccfg_reg); | |
112 | ||
113 | return val; | |
114 | } | |
115 | ||
194ed219 MH |
116 | #define VDAC_COMPONENT 0x543 |
117 | #define VDAC_S_VIDEO 0x210 | |
606b69e9 MH |
118 | /* This function sets the dac of the VPBE for various outputs |
119 | */ | |
120 | static int venc_set_dac(struct v4l2_subdev *sd, u32 out_index) | |
121 | { | |
122 | switch (out_index) { | |
123 | case 0: | |
124 | v4l2_dbg(debug, 1, sd, "Setting output to Composite\n"); | |
125 | venc_write(sd, VENC_DACSEL, 0); | |
126 | break; | |
127 | case 1: | |
194ed219 MH |
128 | v4l2_dbg(debug, 1, sd, "Setting output to Component\n"); |
129 | venc_write(sd, VENC_DACSEL, VDAC_COMPONENT); | |
606b69e9 | 130 | break; |
194ed219 MH |
131 | case 2: |
132 | v4l2_dbg(debug, 1, sd, "Setting output to S-video\n"); | |
133 | venc_write(sd, VENC_DACSEL, VDAC_S_VIDEO); | |
606b69e9 MH |
134 | break; |
135 | default: | |
136 | return -EINVAL; | |
137 | } | |
138 | ||
139 | return 0; | |
140 | } | |
141 | ||
142 | static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) | |
143 | { | |
194ed219 | 144 | struct venc_state *venc = to_state(sd); |
caff80c3 | 145 | |
606b69e9 MH |
146 | v4l2_dbg(debug, 2, sd, "venc_enabledigitaloutput\n"); |
147 | ||
148 | if (benable) { | |
149 | venc_write(sd, VENC_VMOD, 0); | |
150 | venc_write(sd, VENC_CVBS, 0); | |
151 | venc_write(sd, VENC_LCDOUT, 0); | |
152 | venc_write(sd, VENC_HSPLS, 0); | |
153 | venc_write(sd, VENC_HSTART, 0); | |
154 | venc_write(sd, VENC_HVALID, 0); | |
155 | venc_write(sd, VENC_HINT, 0); | |
156 | venc_write(sd, VENC_VSPLS, 0); | |
157 | venc_write(sd, VENC_VSTART, 0); | |
158 | venc_write(sd, VENC_VVALID, 0); | |
159 | venc_write(sd, VENC_VINT, 0); | |
160 | venc_write(sd, VENC_YCCCTL, 0); | |
161 | venc_write(sd, VENC_DACSEL, 0); | |
162 | ||
163 | } else { | |
164 | venc_write(sd, VENC_VMOD, 0); | |
165 | /* disable VCLK output pin enable */ | |
166 | venc_write(sd, VENC_VIDCTL, 0x141); | |
167 | ||
168 | /* Disable output sync pins */ | |
169 | venc_write(sd, VENC_SYNCCTL, 0); | |
170 | ||
171 | /* Disable DCLOCK */ | |
172 | venc_write(sd, VENC_DCLKCTL, 0); | |
173 | venc_write(sd, VENC_DRGBX1, 0x0000057C); | |
174 | ||
175 | /* Disable LCD output control (accepting default polarity) */ | |
176 | venc_write(sd, VENC_LCDOUT, 0); | |
caff80c3 | 177 | if (venc->venc_type != VPBE_VERSION_3) |
194ed219 | 178 | venc_write(sd, VENC_CMPNT, 0x100); |
606b69e9 MH |
179 | venc_write(sd, VENC_HSPLS, 0); |
180 | venc_write(sd, VENC_HINT, 0); | |
181 | venc_write(sd, VENC_HSTART, 0); | |
182 | venc_write(sd, VENC_HVALID, 0); | |
183 | ||
184 | venc_write(sd, VENC_VSPLS, 0); | |
185 | venc_write(sd, VENC_VINT, 0); | |
186 | venc_write(sd, VENC_VSTART, 0); | |
187 | venc_write(sd, VENC_VVALID, 0); | |
188 | ||
189 | venc_write(sd, VENC_HSDLY, 0); | |
190 | venc_write(sd, VENC_VSDLY, 0); | |
191 | ||
192 | venc_write(sd, VENC_YCCCTL, 0); | |
193 | venc_write(sd, VENC_VSTARTA, 0); | |
194 | ||
195 | /* Set OSD clock and OSD Sync Adavance registers */ | |
196 | venc_write(sd, VENC_OSDCLK0, 1); | |
197 | venc_write(sd, VENC_OSDCLK1, 2); | |
198 | } | |
199 | } | |
200 | ||
08154695 LP |
201 | static void |
202 | venc_enable_vpss_clock(int venc_type, | |
203 | enum vpbe_enc_timings_type type, | |
204 | unsigned int pclock) | |
205 | { | |
206 | if (venc_type == VPBE_VERSION_1) | |
207 | return; | |
208 | ||
209 | if (venc_type == VPBE_VERSION_2 && (type == VPBE_ENC_STD || (type == | |
210 | VPBE_ENC_DV_TIMINGS && pclock <= 27000000))) { | |
211 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); | |
212 | vpss_enable_clock(VPSS_VPBE_CLOCK, 1); | |
213 | return; | |
214 | } | |
215 | ||
216 | if (venc_type == VPBE_VERSION_3 && type == VPBE_ENC_STD) | |
217 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 0); | |
218 | } | |
219 | ||
194ed219 MH |
220 | #define VDAC_CONFIG_SD_V3 0x0E21A6B6 |
221 | #define VDAC_CONFIG_SD_V2 0x081141CF | |
606b69e9 MH |
222 | /* |
223 | * setting NTSC mode | |
224 | */ | |
225 | static int venc_set_ntsc(struct v4l2_subdev *sd) | |
226 | { | |
194ed219 | 227 | u32 val; |
606b69e9 MH |
228 | struct venc_state *venc = to_state(sd); |
229 | struct venc_platform_data *pdata = venc->pdata; | |
230 | ||
231 | v4l2_dbg(debug, 2, sd, "venc_set_ntsc\n"); | |
232 | ||
233 | /* Setup clock at VPSS & VENC for SD */ | |
234 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); | |
235 | if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) | |
236 | return -EINVAL; | |
237 | ||
08154695 | 238 | venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_525_60); |
606b69e9 MH |
239 | venc_enabledigitaloutput(sd, 0); |
240 | ||
caff80c3 | 241 | if (venc->venc_type == VPBE_VERSION_3) { |
194ed219 MH |
242 | venc_write(sd, VENC_CLKCTL, 0x01); |
243 | venc_write(sd, VENC_VIDCTL, 0); | |
244 | val = vdaccfg_write(sd, VDAC_CONFIG_SD_V3); | |
caff80c3 | 245 | } else if (venc->venc_type == VPBE_VERSION_2) { |
194ed219 MH |
246 | venc_write(sd, VENC_CLKCTL, 0x01); |
247 | venc_write(sd, VENC_VIDCTL, 0); | |
248 | vdaccfg_write(sd, VDAC_CONFIG_SD_V2); | |
249 | } else { | |
250 | /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ | |
251 | venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); | |
252 | /* Set REC656 Mode */ | |
253 | venc_write(sd, VENC_YCCCTL, 0x1); | |
254 | venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAFRQ); | |
255 | venc_modify(sd, VENC_VDPRO, 0, VENC_VDPRO_DAUPS); | |
256 | } | |
606b69e9 MH |
257 | |
258 | venc_write(sd, VENC_VMOD, 0); | |
259 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | |
260 | VENC_VMOD_VIE); | |
261 | venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); | |
262 | venc_modify(sd, VENC_VMOD, (0 << VENC_VMOD_TVTYP_SHIFT), | |
263 | VENC_VMOD_TVTYP); | |
264 | venc_write(sd, VENC_DACTST, 0x0); | |
265 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | /* | |
271 | * setting PAL mode | |
272 | */ | |
273 | static int venc_set_pal(struct v4l2_subdev *sd) | |
274 | { | |
275 | struct venc_state *venc = to_state(sd); | |
276 | ||
277 | v4l2_dbg(debug, 2, sd, "venc_set_pal\n"); | |
278 | ||
279 | /* Setup clock at VPSS & VENC for SD */ | |
280 | vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); | |
281 | if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) | |
282 | return -EINVAL; | |
283 | ||
08154695 | 284 | venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_625_50); |
606b69e9 MH |
285 | venc_enabledigitaloutput(sd, 0); |
286 | ||
caff80c3 | 287 | if (venc->venc_type == VPBE_VERSION_3) { |
194ed219 MH |
288 | venc_write(sd, VENC_CLKCTL, 0x1); |
289 | venc_write(sd, VENC_VIDCTL, 0); | |
290 | vdaccfg_write(sd, VDAC_CONFIG_SD_V3); | |
caff80c3 | 291 | } else if (venc->venc_type == VPBE_VERSION_2) { |
194ed219 MH |
292 | venc_write(sd, VENC_CLKCTL, 0x1); |
293 | venc_write(sd, VENC_VIDCTL, 0); | |
294 | vdaccfg_write(sd, VDAC_CONFIG_SD_V2); | |
295 | } else { | |
296 | /* to set VENC CLK DIV to 1 - final clock is 54 MHz */ | |
297 | venc_modify(sd, VENC_VIDCTL, 0, 1 << 1); | |
298 | /* Set REC656 Mode */ | |
299 | venc_write(sd, VENC_YCCCTL, 0x1); | |
300 | } | |
606b69e9 MH |
301 | |
302 | venc_modify(sd, VENC_SYNCCTL, 1 << VENC_SYNCCTL_OVD_SHIFT, | |
303 | VENC_SYNCCTL_OVD); | |
304 | venc_write(sd, VENC_VMOD, 0); | |
305 | venc_modify(sd, VENC_VMOD, | |
306 | (1 << VENC_VMOD_VIE_SHIFT), | |
307 | VENC_VMOD_VIE); | |
308 | venc_modify(sd, VENC_VMOD, | |
309 | (0 << VENC_VMOD_VMD), VENC_VMOD_VMD); | |
310 | venc_modify(sd, VENC_VMOD, | |
311 | (1 << VENC_VMOD_TVTYP_SHIFT), | |
312 | VENC_VMOD_TVTYP); | |
313 | venc_write(sd, VENC_DACTST, 0x0); | |
314 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | |
315 | ||
316 | return 0; | |
317 | } | |
318 | ||
194ed219 | 319 | #define VDAC_CONFIG_HD_V2 0x081141EF |
606b69e9 MH |
320 | /* |
321 | * venc_set_480p59_94 | |
322 | * | |
323 | * This function configures the video encoder to EDTV(525p) component setting. | |
324 | */ | |
325 | static int venc_set_480p59_94(struct v4l2_subdev *sd) | |
326 | { | |
327 | struct venc_state *venc = to_state(sd); | |
328 | struct venc_platform_data *pdata = venc->pdata; | |
329 | ||
330 | v4l2_dbg(debug, 2, sd, "venc_set_480p59_94\n"); | |
caff80c3 LP |
331 | if (venc->venc_type != VPBE_VERSION_1 && |
332 | venc->venc_type != VPBE_VERSION_2) | |
194ed219 | 333 | return -EINVAL; |
606b69e9 MH |
334 | |
335 | /* Setup clock at VPSS & VENC for SD */ | |
ef2d41b1 | 336 | if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) |
606b69e9 MH |
337 | return -EINVAL; |
338 | ||
08154695 | 339 | venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); |
606b69e9 MH |
340 | venc_enabledigitaloutput(sd, 0); |
341 | ||
caff80c3 | 342 | if (venc->venc_type == VPBE_VERSION_2) |
194ed219 | 343 | vdaccfg_write(sd, VDAC_CONFIG_HD_V2); |
606b69e9 MH |
344 | venc_write(sd, VENC_OSDCLK0, 0); |
345 | venc_write(sd, VENC_OSDCLK1, 1); | |
194ed219 | 346 | |
caff80c3 | 347 | if (venc->venc_type == VPBE_VERSION_1) { |
194ed219 MH |
348 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, |
349 | VENC_VDPRO_DAFRQ); | |
350 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, | |
351 | VENC_VDPRO_DAUPS); | |
352 | } | |
353 | ||
606b69e9 MH |
354 | venc_write(sd, VENC_VMOD, 0); |
355 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | |
356 | VENC_VMOD_VIE); | |
357 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | |
358 | venc_modify(sd, VENC_VMOD, (HDTV_525P << VENC_VMOD_TVTYP_SHIFT), | |
359 | VENC_VMOD_TVTYP); | |
360 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << | |
361 | VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); | |
362 | ||
363 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | |
364 | ||
365 | return 0; | |
366 | } | |
367 | ||
368 | /* | |
369 | * venc_set_625p | |
370 | * | |
371 | * This function configures the video encoder to HDTV(625p) component setting | |
372 | */ | |
373 | static int venc_set_576p50(struct v4l2_subdev *sd) | |
374 | { | |
375 | struct venc_state *venc = to_state(sd); | |
376 | struct venc_platform_data *pdata = venc->pdata; | |
377 | ||
378 | v4l2_dbg(debug, 2, sd, "venc_set_576p50\n"); | |
379 | ||
caff80c3 LP |
380 | if (venc->venc_type != VPBE_VERSION_1 && |
381 | venc->venc_type != VPBE_VERSION_2) | |
194ed219 | 382 | return -EINVAL; |
606b69e9 | 383 | /* Setup clock at VPSS & VENC for SD */ |
ef2d41b1 | 384 | if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) |
606b69e9 MH |
385 | return -EINVAL; |
386 | ||
08154695 | 387 | venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); |
606b69e9 MH |
388 | venc_enabledigitaloutput(sd, 0); |
389 | ||
caff80c3 | 390 | if (venc->venc_type == VPBE_VERSION_2) |
194ed219 MH |
391 | vdaccfg_write(sd, VDAC_CONFIG_HD_V2); |
392 | ||
606b69e9 MH |
393 | venc_write(sd, VENC_OSDCLK0, 0); |
394 | venc_write(sd, VENC_OSDCLK1, 1); | |
395 | ||
caff80c3 | 396 | if (venc->venc_type == VPBE_VERSION_1) { |
194ed219 MH |
397 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAFRQ, |
398 | VENC_VDPRO_DAFRQ); | |
399 | venc_modify(sd, VENC_VDPRO, VENC_VDPRO_DAUPS, | |
400 | VENC_VDPRO_DAUPS); | |
401 | } | |
606b69e9 MH |
402 | |
403 | venc_write(sd, VENC_VMOD, 0); | |
404 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | |
405 | VENC_VMOD_VIE); | |
406 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | |
407 | venc_modify(sd, VENC_VMOD, (HDTV_625P << VENC_VMOD_TVTYP_SHIFT), | |
408 | VENC_VMOD_TVTYP); | |
409 | ||
410 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VDMD_YCBCR8 << | |
411 | VENC_VMOD_VDMD_SHIFT, VENC_VMOD_VDMD); | |
412 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | |
413 | ||
414 | return 0; | |
415 | } | |
416 | ||
194ed219 MH |
417 | /* |
418 | * venc_set_720p60_internal - Setup 720p60 in venc for dm365 only | |
419 | */ | |
420 | static int venc_set_720p60_internal(struct v4l2_subdev *sd) | |
421 | { | |
422 | struct venc_state *venc = to_state(sd); | |
423 | struct venc_platform_data *pdata = venc->pdata; | |
424 | ||
ef2d41b1 | 425 | if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) |
194ed219 MH |
426 | return -EINVAL; |
427 | ||
08154695 | 428 | venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); |
194ed219 MH |
429 | venc_enabledigitaloutput(sd, 0); |
430 | ||
431 | venc_write(sd, VENC_OSDCLK0, 0); | |
432 | venc_write(sd, VENC_OSDCLK1, 1); | |
433 | ||
434 | venc_write(sd, VENC_VMOD, 0); | |
435 | /* DM365 component HD mode */ | |
436 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | |
437 | VENC_VMOD_VIE); | |
438 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | |
439 | venc_modify(sd, VENC_VMOD, (HDTV_720P << VENC_VMOD_TVTYP_SHIFT), | |
440 | VENC_VMOD_TVTYP); | |
441 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | |
442 | venc_write(sd, VENC_XHINTVL, 0); | |
443 | return 0; | |
444 | } | |
445 | ||
446 | /* | |
447 | * venc_set_1080i30_internal - Setup 1080i30 in venc for dm365 only | |
448 | */ | |
449 | static int venc_set_1080i30_internal(struct v4l2_subdev *sd) | |
450 | { | |
451 | struct venc_state *venc = to_state(sd); | |
452 | struct venc_platform_data *pdata = venc->pdata; | |
453 | ||
ef2d41b1 | 454 | if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) |
194ed219 MH |
455 | return -EINVAL; |
456 | ||
08154695 | 457 | venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); |
194ed219 MH |
458 | venc_enabledigitaloutput(sd, 0); |
459 | ||
460 | venc_write(sd, VENC_OSDCLK0, 0); | |
461 | venc_write(sd, VENC_OSDCLK1, 1); | |
462 | ||
463 | ||
464 | venc_write(sd, VENC_VMOD, 0); | |
465 | /* DM365 component HD mode */ | |
466 | venc_modify(sd, VENC_VMOD, (1 << VENC_VMOD_VIE_SHIFT), | |
467 | VENC_VMOD_VIE); | |
468 | venc_modify(sd, VENC_VMOD, VENC_VMOD_HDMD, VENC_VMOD_HDMD); | |
469 | venc_modify(sd, VENC_VMOD, (HDTV_1080I << VENC_VMOD_TVTYP_SHIFT), | |
470 | VENC_VMOD_TVTYP); | |
471 | venc_modify(sd, VENC_VMOD, VENC_VMOD_VENC, VENC_VMOD_VENC); | |
472 | venc_write(sd, VENC_XHINTVL, 0); | |
473 | return 0; | |
474 | } | |
475 | ||
606b69e9 MH |
476 | static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) |
477 | { | |
478 | v4l2_dbg(debug, 1, sd, "venc_s_std_output\n"); | |
479 | ||
480 | if (norm & V4L2_STD_525_60) | |
481 | return venc_set_ntsc(sd); | |
482 | else if (norm & V4L2_STD_625_50) | |
483 | return venc_set_pal(sd); | |
484 | ||
485 | return -EINVAL; | |
486 | } | |
487 | ||
36864082 HV |
488 | static int venc_s_dv_timings(struct v4l2_subdev *sd, |
489 | struct v4l2_dv_timings *dv_timings) | |
606b69e9 | 490 | { |
194ed219 | 491 | struct venc_state *venc = to_state(sd); |
36864082 | 492 | u32 height = dv_timings->bt.height; |
194ed219 MH |
493 | int ret; |
494 | ||
36864082 | 495 | v4l2_dbg(debug, 1, sd, "venc_s_dv_timings\n"); |
606b69e9 | 496 | |
36864082 | 497 | if (height == 576) |
606b69e9 | 498 | return venc_set_576p50(sd); |
36864082 | 499 | else if (height == 480) |
606b69e9 | 500 | return venc_set_480p59_94(sd); |
36864082 | 501 | else if ((height == 720) && |
caff80c3 | 502 | (venc->venc_type == VPBE_VERSION_2)) { |
194ed219 MH |
503 | /* TBD setup internal 720p mode here */ |
504 | ret = venc_set_720p60_internal(sd); | |
505 | /* for DM365 VPBE, there is DAC inside */ | |
506 | vdaccfg_write(sd, VDAC_CONFIG_HD_V2); | |
507 | return ret; | |
36864082 | 508 | } else if ((height == 1080) && |
caff80c3 | 509 | (venc->venc_type == VPBE_VERSION_2)) { |
194ed219 MH |
510 | /* TBD setup internal 1080i mode here */ |
511 | ret = venc_set_1080i30_internal(sd); | |
512 | /* for DM365 VPBE, there is DAC inside */ | |
513 | vdaccfg_write(sd, VDAC_CONFIG_HD_V2); | |
514 | return ret; | |
515 | } | |
606b69e9 MH |
516 | return -EINVAL; |
517 | } | |
518 | ||
519 | static int venc_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, | |
520 | u32 config) | |
521 | { | |
522 | struct venc_state *venc = to_state(sd); | |
523 | int ret; | |
524 | ||
525 | v4l2_dbg(debug, 1, sd, "venc_s_routing\n"); | |
526 | ||
527 | ret = venc_set_dac(sd, output); | |
528 | if (!ret) | |
529 | venc->output = output; | |
530 | ||
531 | return ret; | |
532 | } | |
533 | ||
534 | static long venc_ioctl(struct v4l2_subdev *sd, | |
535 | unsigned int cmd, | |
536 | void *arg) | |
537 | { | |
538 | u32 val; | |
539 | ||
540 | switch (cmd) { | |
541 | case VENC_GET_FLD: | |
542 | val = venc_read(sd, VENC_VSTAT); | |
543 | *((int *)arg) = ((val & VENC_VSTAT_FIDST) == | |
544 | VENC_VSTAT_FIDST); | |
545 | break; | |
546 | default: | |
547 | v4l2_err(sd, "Wrong IOCTL cmd\n"); | |
548 | break; | |
549 | } | |
550 | ||
551 | return 0; | |
552 | } | |
553 | ||
554 | static const struct v4l2_subdev_core_ops venc_core_ops = { | |
555 | .ioctl = venc_ioctl, | |
556 | }; | |
557 | ||
558 | static const struct v4l2_subdev_video_ops venc_video_ops = { | |
559 | .s_routing = venc_s_routing, | |
560 | .s_std_output = venc_s_std_output, | |
36864082 | 561 | .s_dv_timings = venc_s_dv_timings, |
606b69e9 MH |
562 | }; |
563 | ||
564 | static const struct v4l2_subdev_ops venc_ops = { | |
565 | .core = &venc_core_ops, | |
566 | .video = &venc_video_ops, | |
567 | }; | |
568 | ||
569 | static int venc_initialize(struct v4l2_subdev *sd) | |
570 | { | |
571 | struct venc_state *venc = to_state(sd); | |
572 | int ret; | |
573 | ||
574 | /* Set default to output to composite and std to NTSC */ | |
575 | venc->output = 0; | |
576 | venc->std = V4L2_STD_525_60; | |
577 | ||
578 | ret = venc_s_routing(sd, 0, venc->output, 0); | |
579 | if (ret < 0) { | |
580 | v4l2_err(sd, "Error setting output during init\n"); | |
581 | return -EINVAL; | |
582 | } | |
583 | ||
584 | ret = venc_s_std_output(sd, venc->std); | |
585 | if (ret < 0) { | |
586 | v4l2_err(sd, "Error setting std during init\n"); | |
587 | return -EINVAL; | |
588 | } | |
589 | ||
590 | return ret; | |
591 | } | |
592 | ||
593 | static int venc_device_get(struct device *dev, void *data) | |
594 | { | |
595 | struct platform_device *pdev = to_platform_device(dev); | |
596 | struct venc_state **venc = data; | |
597 | ||
caff80c3 | 598 | if (strstr(pdev->name, "vpbe-venc") != NULL) |
606b69e9 MH |
599 | *venc = platform_get_drvdata(pdev); |
600 | ||
601 | return 0; | |
602 | } | |
603 | ||
604 | struct v4l2_subdev *venc_sub_dev_init(struct v4l2_device *v4l2_dev, | |
605 | const char *venc_name) | |
606 | { | |
607 | struct venc_state *venc; | |
608 | int err; | |
609 | ||
610 | err = bus_for_each_dev(&platform_bus_type, NULL, &venc, | |
611 | venc_device_get); | |
612 | if (venc == NULL) | |
613 | return NULL; | |
614 | ||
615 | v4l2_subdev_init(&venc->sd, &venc_ops); | |
616 | ||
617 | strcpy(venc->sd.name, venc_name); | |
618 | if (v4l2_device_register_subdev(v4l2_dev, &venc->sd) < 0) { | |
619 | v4l2_err(v4l2_dev, | |
620 | "vpbe unable to register venc sub device\n"); | |
621 | return NULL; | |
622 | } | |
623 | if (venc_initialize(&venc->sd)) { | |
624 | v4l2_err(v4l2_dev, | |
625 | "vpbe venc initialization failed\n"); | |
626 | return NULL; | |
627 | } | |
628 | ||
629 | return &venc->sd; | |
630 | } | |
631 | EXPORT_SYMBOL(venc_sub_dev_init); | |
632 | ||
633 | static int venc_probe(struct platform_device *pdev) | |
634 | { | |
caff80c3 | 635 | const struct platform_device_id *pdev_id; |
606b69e9 MH |
636 | struct venc_state *venc; |
637 | struct resource *res; | |
606b69e9 | 638 | |
371376d2 LP |
639 | if (!pdev->dev.platform_data) { |
640 | dev_err(&pdev->dev, "No platform data for VENC sub device"); | |
641 | return -EINVAL; | |
642 | } | |
643 | ||
644 | pdev_id = platform_get_device_id(pdev); | |
645 | if (!pdev_id) | |
646 | return -EINVAL; | |
647 | ||
648 | venc = devm_kzalloc(&pdev->dev, sizeof(struct venc_state), GFP_KERNEL); | |
606b69e9 MH |
649 | if (venc == NULL) |
650 | return -ENOMEM; | |
651 | ||
caff80c3 | 652 | venc->venc_type = pdev_id->driver_data; |
606b69e9 MH |
653 | venc->pdev = &pdev->dev; |
654 | venc->pdata = pdev->dev.platform_data; | |
371376d2 | 655 | |
606b69e9 | 656 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
606b69e9 | 657 | |
371376d2 LP |
658 | venc->venc_base = devm_ioremap_resource(&pdev->dev, res); |
659 | if (IS_ERR(venc->venc_base)) | |
660 | return PTR_ERR(venc->venc_base); | |
606b69e9 | 661 | |
caff80c3 | 662 | if (venc->venc_type != VPBE_VERSION_1) { |
194ed219 | 663 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
371376d2 LP |
664 | |
665 | venc->vdaccfg_reg = devm_ioremap_resource(&pdev->dev, res); | |
666 | if (IS_ERR(venc->vdaccfg_reg)) | |
667 | return PTR_ERR(venc->vdaccfg_reg); | |
194ed219 | 668 | } |
606b69e9 MH |
669 | spin_lock_init(&venc->lock); |
670 | platform_set_drvdata(pdev, venc); | |
671 | dev_notice(venc->pdev, "VENC sub device probe success\n"); | |
606b69e9 | 672 | |
371376d2 | 673 | return 0; |
606b69e9 MH |
674 | } |
675 | ||
676 | static int venc_remove(struct platform_device *pdev) | |
677 | { | |
606b69e9 MH |
678 | return 0; |
679 | } | |
680 | ||
681 | static struct platform_driver venc_driver = { | |
682 | .probe = venc_probe, | |
683 | .remove = venc_remove, | |
684 | .driver = { | |
685 | .name = MODULE_NAME, | |
606b69e9 | 686 | }, |
caff80c3 | 687 | .id_table = vpbe_venc_devtype |
606b69e9 MH |
688 | }; |
689 | ||
1d6629b1 | 690 | module_platform_driver(venc_driver); |
606b69e9 MH |
691 | |
692 | MODULE_LICENSE("GPL"); | |
693 | MODULE_DESCRIPTION("VPBE VENC Driver"); | |
694 | MODULE_AUTHOR("Texas Instruments"); |