linux-davinci-git : Update recipe so it builds for sffsdr board.
[vuplus_openembedded] / packages / linux / linux-davinci / davinci-sffsdr / 0011-Add-lyrvpss-example-driver-for-the-SFFSDR-board.patch
1 From 25a91bba1bcc8d9f120e8b85b0ec53a18ccec244 Mon Sep 17 00:00:00 2001
2 From: Hugo Villeneuve <hugo@hugovil.com>
3 Date: Thu, 5 Mar 2009 16:04:23 -0500
4 Subject: [PATCH 11/12] Add lyrvpss example driver for the SFFSDR board
5
6 Currently there is only a VPFE driver in lyrvpss, and it is called luyrvpfe.
7 It works with a FPGA bitstream that generates a ramp and sends it over the
8 VPFE interface. The lyrvpfe driver receives an interrupt each time the HSYNC
9 line is pulsed (even if the VDINT0 interrupt line is used), and stores and
10 checks the data to make sure that it is valid. The driver will request a new
11 frame from the FPGA each time there is a read from /proc/lyrvpfe. For example,
12 to receive a new frame, issue the following:
13
14   $> cat /proc/lyrvpfe
15
16 This will send a request to the FPGA (using the GPIO line) to send a new frame,
17 wait one second then display the contents of the PING and PONG reception buffers.
18
19 Signed-off-by: Hugo Villeneuve <hugo@hugovil.com>
20 ---
21  .../arm/mach-davinci/include/mach/sffsdr-lyrvpfe.h |   32 +
22  drivers/char/Kconfig                               |    2 +
23  drivers/char/Makefile                              |    2 +
24  drivers/char/lyrvpss/Kconfig                       |   42 ++
25  drivers/char/lyrvpss/Makefile                      |    8 +
26  drivers/char/lyrvpss/vpfe.c                        |  753 ++++++++++++++++++++
27  6 files changed, 839 insertions(+), 0 deletions(-)
28  create mode 100644 arch/arm/mach-davinci/include/mach/sffsdr-lyrvpfe.h
29  create mode 100644 drivers/char/lyrvpss/Kconfig
30  create mode 100644 drivers/char/lyrvpss/Makefile
31  create mode 100644 drivers/char/lyrvpss/vpfe.c
32
33 diff --git a/arch/arm/mach-davinci/include/mach/sffsdr-lyrvpfe.h b/arch/arm/mach-davinci/include/mach/sffsdr-lyrvpfe.h
34 new file mode 100644
35 index 0000000..fb47851
36 --- /dev/null
37 +++ b/arch/arm/mach-davinci/include/mach/sffsdr-lyrvpfe.h
38 @@ -0,0 +1,32 @@
39 +/*
40 + * lyrvpfe.h
41 + *
42 + * This program is free software; you can redistribute it and/or modify it
43 + * under the terms of the GNU General Public License as published by the
44 + * Free Software Foundation; either version 2 of the License, or (at your
45 + * option) any later version.
46 + *
47 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
48 + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
49 + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
50 + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
52 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
53 + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
54 + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
56 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 + *
58 + * You should have received a copy of the  GNU General Public License along
59 + * with this program; if not, write  to the Free Software Foundation, Inc.,
60 + * 675 Mass Ave, Cambridge, MA 02139, USA.
61 + */
62 +
63 +#ifndef __LYRVPFE_H
64 +#define __LYRVPFE_H
65 +
66 +struct lyrvpfe_platform_data {
67 +       unsigned ready_gpio;
68 +};
69 +
70 +#endif /* __LYRVPFE_H */
71 diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
72 index 43d6ba8..b98a8e2 100644
73 --- a/drivers/char/Kconfig
74 +++ b/drivers/char/Kconfig
75 @@ -1073,5 +1073,7 @@ config DEVPORT
76  
77  source "drivers/s390/char/Kconfig"
78  
79 +source "drivers/char/lyrvpss/Kconfig"
80 +
81  endmenu
82  
83 diff --git a/drivers/char/Makefile b/drivers/char/Makefile
84 index 438f713..8800b3f 100644
85 --- a/drivers/char/Makefile
86 +++ b/drivers/char/Makefile
87 @@ -109,6 +109,8 @@ obj-$(CONFIG_PS3_FLASH)             += ps3flash.o
88  obj-$(CONFIG_JS_RTC)           += js-rtc.o
89  js-rtc-y = rtc.o
90  
91 +obj-$(CONFIG_LYRTECH_VPSS)     += lyrvpss/
92 +
93  # Files generated that shall be removed upon make clean
94  clean-files := consolemap_deftbl.c defkeymap.c
95  
96 diff --git a/drivers/char/lyrvpss/Kconfig b/drivers/char/lyrvpss/Kconfig
97 new file mode 100644
98 index 0000000..80b1487
99 --- /dev/null
100 +++ b/drivers/char/lyrvpss/Kconfig
101 @@ -0,0 +1,42 @@
102 +#
103 +# Lyrtech VPSS drivers
104 +#
105 +
106 +menuconfig LYRTECH_VPSS
107 +       bool 'Lyrtech SFFSDR VPSS drivers'
108 +       depends on ARCH_DAVINCI && MACH_SFFSDR
109 +       help
110 +         This enables support for Lyrtech SFFSDR VPSS drivers.
111 +
112 +         If unsure, say N.
113 +
114 +if LYRTECH_VPSS
115 +
116 +config LYRTECH_VPFE
117 +       tristate "Lyrtech VPFE Driver Support"
118 +       help
119 +         This option enables support for the Lyrtech VPFE driver
120 +         for FPGA to DaVinci data transfers.
121 +
122 +         To compile this driver as a module, choose M here: the
123 +         module will be called lyrvpfe.
124 +
125 +         If unsure, say N.
126 +
127 +config LYRTECH_VPBE
128 +       tristate "Lyrtech VPBE Driver Support"
129 +       help
130 +         This option enables support for the Lyrtech VPBE driver
131 +         for DaVinci to FPGA data transfers.
132 +
133 +         To compile this driver as a module, choose M here: the
134 +         module will be called lyrvpbe.
135 +
136 +         If unsure, say N.
137 +
138 +config LYRVPSS_DEBUG
139 +       boolean "Debug support for LYRVPSSS drivers"
140 +       help
141 +         Say "yes" to enable verbose debug messaging.
142 +
143 +endif # LYRTECH_VPSS
144 diff --git a/drivers/char/lyrvpss/Makefile b/drivers/char/lyrvpss/Makefile
145 new file mode 100644
146 index 0000000..ac36807
147 --- /dev/null
148 +++ b/drivers/char/lyrvpss/Makefile
149 @@ -0,0 +1,8 @@
150 +#
151 +# Makefile for the Lyrtech SFFSDR VPSS driver
152 +#
153 +
154 +obj-$(CONFIG_LYRTECH_VPFE) += lyrvpfe.o
155 +obj-$(CONFIG_LYRTECH_VPBE) += lyrvpbe.o
156 +lyrvpfe-objs := vpfe.o
157 +lyrvpbe-objs := vpbe.o
158 diff --git a/drivers/char/lyrvpss/vpfe.c b/drivers/char/lyrvpss/vpfe.c
159 new file mode 100644
160 index 0000000..45e2853
161 --- /dev/null
162 +++ b/drivers/char/lyrvpss/vpfe.c
163 @@ -0,0 +1,753 @@
164 +/*
165 + * lyrvpfe driver
166 + *
167 + * Copyright (C) 2008 Lyrtech <www.lyrtech.com>
168 + *
169 + * This program is free software; you can redistribute it and/or modify
170 + * it under the terms of the GNU General Public License as published by
171 + * the Free Software Foundation; either version 2 of the License, or
172 + * (at your option) any later version.
173 + *
174 + * This program is distributed in the hope that it will be useful,
175 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
176 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
177 + * GNU General Public License for more details.
178 + *
179 + * You should have received a copy of the GNU General Public License
180 + * along with this program; if not, write to the Free Software
181 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
182 + */
183 +
184 +#include <linux/kernel.h>
185 +#include <linux/module.h>
186 +#include <linux/init.h>
187 +#include <linux/device.h>
188 +#include <linux/platform_device.h>
189 +#include <linux/string.h>
190 +#include <linux/delay.h>
191 +#include <linux/firmware.h>
192 +#include <linux/interrupt.h>
193 +#include <linux/jiffies.h>
194 +#include <linux/err.h>
195 +#include <linux/fs.h>
196 +#include <linux/io.h>
197 +#include <linux/irq.h>
198 +
199 +#ifdef CONFIG_PROC_FS
200 +#include <linux/proc_fs.h>
201 +#include <linux/seq_file.h>
202 +#include <asm/uaccess.h>
203 +#endif /* CONFIG_PROC_FS */
204 +
205 +#include <asm/gpio.h>
206 +
207 +#include <mach/sffsdr-fpga.h>
208 +#include <mach/sffsdr-lyrvpfe.h>
209 +#include <mach/mux.h>
210 +#include <mach/irqs.h>
211 +
212 +#define MODULE_NAME "lyrvpfe"
213 +
214 +#ifdef CONFIG_LYRVPSS_DEBUG
215 +#define DBGMSG(fmt, args...)                           \
216 +       printk(KERN_INFO "%s: "fmt"\n" , MODULE_NAME, ## args)
217 +#else
218 +#define DBGMSG(fmt, args...)
219 +#endif
220 +
221 +#define FAILMSG(fmt, args...)                                  \
222 +       printk(KERN_ERR "%s: "fmt"\n" , MODULE_NAME, ## args)
223 +
224 +#define DAVINCI_CCDC_REGS_OFFSET       0x400
225 +
226 +/* This word is written at index 0 to mark a buffer as invalid. */
227 +#define INVALIDATE_BUFFER_CODE 0x11222211
228 +
229 +/* Default values for our driver. */
230 +#define LYRVPFE_LINES_PER_FRAME        2
231 +#define LYRVPFE_WORDS_PER_LINE 8 /* Minimum is 8 words */
232 +
233 +/* SFFSDR VPSS limits */
234 +#define LYRVPFE_MAX_WORDS_PER_LINE     1024
235 +#define LYRVPFE_MAX_LINES_PER_FRAME    10
236 +#define LYRVPFE_MAX_BUFFER_SIZE                65536
237 +
238 +#define BUFFER_PING    0
239 +#define BUFFER_PONG    1
240 +
241 +struct ccdc_regs {
242 +       u32 pid;
243 +       u32 pcr;
244 +       u32 syn_mode;
245 +       u32 hd_vd_wid;
246 +       u32 pix_lines;
247 +       u32 horz_info;
248 +       u32 vert_start;
249 +       u32 vert_lines;
250 +       u32 culling;
251 +       u32 hsize_off;
252 +       u32 sdofst;
253 +       u32 sdr_addr;
254 +       u32 clamp;
255 +       u32 dcsub;
256 +       u32 colptn;
257 +       u32 blkcmp;
258 +       u32 fpc;
259 +       u32 fpc_addr;
260 +       u32 vdint;
261 +       u32 alaw;
262 +       u32 rec656if;
263 +       u32 ccdcfg;
264 +       u32 fmtcfg;
265 +       u32 fmt_horz;
266 +       u32 fmt_vert;
267 +       u32 unused[48];
268 +       u32 vp_out;
269 +};
270 +
271 +#define CCDC_REGS_COUNT 38
272 +
273 +#define CCDC_WEN_BIT   (1 << 17)
274 +#define CCDC_VDHDEN_BIT        (1 << 16)
275 +#define CCDC_VDPOL_NEG (1 <<  2)
276 +
277 +/* Structure containing driver informations. */
278 +struct lyrvpfe_private {
279 +       enum {
280 +               LYRVPFE_INIT_START,
281 +               LYRVPFE_INIT_HAVE_REGS,
282 +               LYRVPFE_INIT_HAVE_IRQ,
283 +               LYRVPFE_INIT_HAVE_GPIO,
284 +               LYRVPFE_INIT_VPFE,
285 +               LYRVPFE_INIT_HAVE_PING_BUFFER,
286 +               LYRVPFE_INIT_HAVE_PONG_BUFFER,
287 +               LYRVPFE_INIT_HAVE_PROC
288 +       } init_state;
289 +       u32 id;
290 +       unsigned ready_gpio;
291 +       unsigned int irq;
292 +       void *regs;
293 +       volatile struct ccdc_regs *ccdc_regs;
294 +       u32 ramp_index;
295 +       u32 lines_per_frame;
296 +       u32 words_per_line;
297 +       int line_size;
298 +       int bufsize;
299 +       int wrid; /* 0 (ping) or 1 (pong) */
300 +       u32 *data_buffers[2];
301 +       struct device dev;
302 +};
303 +
304 +static struct lyrvpfe_private lyrvpfe;
305 +
306 +/* Informs the FPGA that the DaVinci can receive a new frame. */
307 +static void lyrvpfe_set_ready(void)
308 +{
309 +       int value;
310 +
311 +       /* Read current pin state */
312 +       value = gpio_get_value(lyrvpfe.ready_gpio);
313 +
314 +       /* Toggle state. */
315 +       value ^= 1;
316 +
317 +       /* Toggle pin. */
318 +       gpio_set_value(lyrvpfe.ready_gpio, value);
319 +}
320 +
321 +#ifdef CONFIG_PROC_FS
322 +
323 +#define LYRVPFE_PROC_NAME      "lyrvpfe"
324 +
325 +static void *lyrvpfe_start(struct seq_file *m, loff_t *pos)
326 +{
327 +       return *pos < 1 ? (void *)1 : NULL;
328 +}
329 +
330 +static void *lyrvpfe_next(struct seq_file *m, void *v, loff_t *pos)
331 +{
332 +       ++*pos;
333 +       return NULL;
334 +}
335 +
336 +static void lyrvpfe_stop(struct seq_file *m, void *v)
337 +{
338 +}
339 +
340 +static void lyrvpfe_display_regs(char *msg, u32 *regs, int size,
341 +                                struct seq_file *m)
342 +{
343 +       int k;
344 +
345 +       seq_printf(m, "%s:", msg);
346 +       for (k = 0; k < size; k++) {
347 +               if ((k % 4) == 0)
348 +                       seq_printf(m, "\n");
349 +
350 +               seq_printf(m, "  [$%02X] $%08X", k * 4, regs[k]);
351 +       }
352 +       seq_printf(m, "\n");
353 +}
354 +
355 +static int lyrvpfe_show(struct seq_file *m, void *v)
356 +{
357 +       u32 *regs;
358 +       unsigned long jtarget, jcurrent;
359 +
360 +       /* Toggle pin to receive next frame */
361 +       lyrvpfe_set_ready();
362 +
363 +       jtarget = jiffies + (1 * HZ);
364 +
365 +       /* Wait 1 second for data to arrive. */
366 +       do {
367 +               jcurrent = jiffies;
368 +               cpu_relax();
369 +       } while (time_before(jcurrent, jtarget));
370 +
371 +       regs = (u32 *) lyrvpfe.ccdc_regs;
372 +       lyrvpfe_display_regs("CCDC registers", regs, CCDC_REGS_COUNT, m);
373 +
374 +       seq_printf(m, "FPGA registers:\n");
375 +
376 +       seq_printf(m, "  [$%04X] $%04X  [$%04X] $%04X" \
377 +                  "  [$%04X] $%04X  [$%04X] $%04X\n",
378 +                  SFFSDR_FPGA_REVISION,
379 +                  sffsdr_fpga_regread(SFFSDR_FPGA_REVISION),
380 +                  SFFSDR_FPGA_VPSS_CONTROL,
381 +                  sffsdr_fpga_regread(SFFSDR_FPGA_VPSS_CONTROL),
382 +                  SFFSDR_FPGA_VPSS_TO_DSP_FIFO,
383 +                  sffsdr_fpga_regread(SFFSDR_FPGA_VPSS_TO_DSP_FIFO),
384 +                  SFFSDR_FPGA_VPSS_LINES_PER_FRAME,
385 +                  sffsdr_fpga_regread(SFFSDR_FPGA_VPSS_LINES_PER_FRAME));
386 +
387 +       regs = lyrvpfe.data_buffers[BUFFER_PING];
388 +       lyrvpfe_display_regs("PING buffer", regs, 64, m);
389 +
390 +       regs = lyrvpfe.data_buffers[BUFFER_PONG];
391 +       lyrvpfe_display_regs("PONG buffer", regs, 64, m);
392 +
393 +       return 0;
394 +}
395 +
396 +static const struct seq_operations lyrvpfe_op = {
397 +       .start  = lyrvpfe_start,
398 +       .next   = lyrvpfe_next,
399 +       .stop   = lyrvpfe_stop,
400 +       .show   = lyrvpfe_show
401 +};
402 +
403 +static int lyrvpfe_open(struct inode *inode, struct file *file)
404 +{
405 +       struct seq_file *m;
406 +       int ret;
407 +
408 +       DBGMSG("lyrvpfe_open");
409 +
410 +       ret = seq_open(file, &lyrvpfe_op);
411 +       if (ret < 0)
412 +               return ret;
413 +
414 +       m = file->private_data;
415 +
416 +       return 0;
417 +}
418 +
419 +static const struct file_operations proc_lyrvpfe_operations = {
420 +       .open           = lyrvpfe_open,
421 +       .read           = seq_read,
422 +       .llseek         = seq_lseek,
423 +       .release        = seq_release,
424 +       .owner          = THIS_MODULE,
425 +};
426 +
427 +static int lyrvpfe_proc_init(void)
428 +{
429 +       struct proc_dir_entry *entry;
430 +
431 +       entry = create_proc_entry(LYRVPFE_PROC_NAME, 0, NULL);
432 +       if (!entry) {
433 +               FAILMSG("Error creating proc entry");
434 +               return -EFAULT;
435 +       }
436 +
437 +       entry->proc_fops = &proc_lyrvpfe_operations;
438 +       entry->data = &lyrvpfe;
439 +
440 +       return 0;
441 +}
442 +
443 +#endif /* CONFIG_PROC_FS */
444 +
445 +static int lyrvpfe_validate_buffer(u32 *buffer)
446 +{
447 +       u8 xor, xnor;
448 +       u8 *cksum_data = (u8 *) buffer;
449 +
450 +       /* Compute XOR of bytes 4 and 5 */
451 +       xnor = ~(cksum_data[4] ^ cksum_data[5]);
452 +       xor = cksum_data[4] ^ cksum_data[5];
453 +
454 +       if ((xor != cksum_data[1]) || (xnor != cksum_data[0]))
455 +               return -1;
456 +       else
457 +               return 0;
458 +}
459 +
460 +static inline void lyrvpfe_invalidate_buffer(u32 *buffer)
461 +{
462 +       int line;
463 +       int offset;
464 +
465 +       for (line = 0; line < lyrvpfe.lines_per_frame; line++) {
466 +               /* Get offset of next line. */
467 +               offset = (line * lyrvpfe.ccdc_regs->hsize_off) / 4;
468 +
469 +               /* Mark buffer as invalid. */
470 +               buffer[offset] = INVALIDATE_BUFFER_CODE;
471 +       }
472 +}
473 +
474 +/*
475 + * Lyrtech SFFSDR custom VPFE format:
476 + *
477 + * Length is in u32 units
478 + *
479 + * Format for each line:
480 + *
481 + * | u32  |                bits               |
482 + * |offset| 31..24 | 23..16 | 15..08 | 07..00 |
483 + * ============================================
484 + *   0    | dummy    dummy    dummy    dummy
485 + *   1    | dummy    dummy    dummy    dummy
486 + *   2    | length   length   cksum    cksum
487 + *   3    | data0    data0    data0    data0
488 + *   4    | data1    data1    data1    data1
489 + *  ...      ...
490 + */
491 +static int vpfe_check_buffer(u32 *buffer)
492 +{
493 +       int k;
494 +       int line;
495 +       u16 length;
496 +       int offset;
497 +       int ret;
498 +
499 +       for (line = 0; line < lyrvpfe.lines_per_frame; line++) {
500 +               /* Get offset of next line. */
501 +               offset = (line * lyrvpfe.ccdc_regs->hsize_off) / 4;
502 +
503 +               if (buffer[offset] == INVALIDATE_BUFFER_CODE) {
504 +                       /* No error. Means that HD pulses generated the VDINT0
505 +                        * interruption, but VD was not asserted. */
506 +                       return -1;
507 +               }
508 +
509 +               /* First two words contain empty/dummy data. */
510 +               offset += 2;
511 +
512 +               if (line == 0) {
513 +                       if (lyrvpfe.wrid == BUFFER_PING)
514 +                               DBGMSG("VDINT: PING buffer");
515 +                       else
516 +                               DBGMSG("VDINT: PONG buffer");
517 +               }
518 +
519 +               ret = lyrvpfe_validate_buffer(&buffer[offset]);
520 +               if (ret < 0) {
521 +                       /* This may mean a checksum error, or that
522 +                        * the FPGA sent fewer lines than the maximum
523 +                        * configured. */
524 +                       FAILMSG("  Checksum error line %d", line);
525 +                       return -1;
526 +               }
527 +
528 +               length = buffer[offset] >> 16;
529 +
530 +               /* Points to first data word. */
531 +               offset++;
532 +
533 +               for (k = 0; k < length; k++) {
534 +                       if (buffer[offset + k] != (lyrvpfe.ramp_index + k)) {
535 +                               FAILMSG("    Ramp error at index %d, line %d",
536 +                                       lyrvpfe.ramp_index, line);
537 +                               FAILMSG("    read:     $%08X",
538 +                                       buffer[offset + k]);
539 +                               FAILMSG("    expected: $%08X",
540 +                                       lyrvpfe.ramp_index + k);
541 +
542 +                               lyrvpfe_invalidate_buffer(buffer);
543 +                               return -1;
544 +                       }
545 +               }
546 +
547 +               lyrvpfe.ramp_index += length;
548 +       }
549 +
550 +       return 0;
551 +}
552 +
553 +static void lyrvpfe_set_ccdc_buffer(u32 *virt_address)
554 +{
555 +       lyrvpfe.ccdc_regs->sdr_addr = (u32) virt_to_phys(virt_address);
556 +}
557 +
558 +/*
559 + * The CCDC VDINT0 and VDINT1 HD counters begin counting HD pulses from the
560 + * rising edge of the external VD. The Lyrtech FPGA VPFE design only drives VD
561 + * when the ARM request data by toggling the SET_VPFE_READY GPIO. Unfortunately,
562 + * the FPGA never disable the HD line, and the ISR will be called all the time
563 + * with invalid data when VD is not driven. This is why we need to invalidate a
564 + * buffer once it has been read.
565 + */
566 +static irqreturn_t lyrvpfe_isr(int irq, void *dev_id)
567 +{
568 +       int ret;
569 +       int buffer_read_id;
570 +
571 +       /* Buffer index for reading data */
572 +       buffer_read_id = lyrvpfe.wrid;
573 +
574 +       ret = vpfe_check_buffer(lyrvpfe.data_buffers[buffer_read_id]);
575 +       if (ret) {
576 +               /* This could mean a real error or simply that we received a
577 +                * dummy HD interrupt. */
578 +               lyrvpfe_invalidate_buffer(lyrvpfe.data_buffers[buffer_read_id]);
579 +       } else {
580 +               /* Valid data was received. We can now switch the pong-pong
581 +                * buffers. */
582 +
583 +               /* Switch ping-pong buffers for writing. */
584 +               lyrvpfe.wrid ^= 1;
585 +               lyrvpfe_set_ccdc_buffer(lyrvpfe.data_buffers[lyrvpfe.wrid]);
586 +
587 +               /* Make sure to invalidate the new buffer */
588 +               lyrvpfe_invalidate_buffer(lyrvpfe.data_buffers[lyrvpfe.wrid]);
589 +       }
590 +
591 +       return IRQ_HANDLED;
592 +}
593 +
594 +/*
595 + * Configures the VPFE interface to receive data from the FPGA.
596 + *
597 + * lines_per_frame:  Lines per frame (within the VSYNC period).
598 + * words_per_line:   32-bits data words per line (within the HSYNC period).
599 + */
600 +static int lyrvpfe_init_vpfe(u16 lines_per_frame, u16 words_per_line)
601 +{
602 +       int bytes_per_buffer;
603 +
604 +       lyrvpfe.ramp_index = 0;
605 +       lyrvpfe.wrid = BUFFER_PING;
606 +
607 +       if (words_per_line > LYRVPFE_MAX_WORDS_PER_LINE) {
608 +               FAILMSG("VPFE init: invalid words_per_line (%d)",
609 +                       words_per_line);
610 +               return -1;
611 +       }
612 +
613 +       if (lines_per_frame > LYRVPFE_MAX_LINES_PER_FRAME) {
614 +               FAILMSG("VPFE init: invalid lines_per_frame (%d)",
615 +                       lines_per_frame);
616 +               return -1;
617 +       }
618 +
619 +       bytes_per_buffer = (words_per_line + 3) * 4 * lines_per_frame;
620 +       if (bytes_per_buffer > LYRVPFE_MAX_BUFFER_SIZE) {
621 +               FAILMSG("VPFE init: wrong bytes_per_buffer (%d)",
622 +                       bytes_per_buffer);
623 +               return -1;
624 +       }
625 +
626 +       DBGMSG("  words_per_line  = $%04X", words_per_line);
627 +       DBGMSG("  lines_per_frame = $%04X", lines_per_frame);
628 +
629 +       /* Setup FPGA parameters */
630 +       sffsdr_fpga_regwrite(SFFSDR_FPGA_VPSS_TO_DSP_FIFO,
631 +                            (words_per_line & 0x3ff) |
632 +                            (lines_per_frame << 10));
633 +
634 +       /* 2 additional for blanking and 1 for header (length and checksum). */
635 +       words_per_line = words_per_line + 3;
636 +
637 +       lyrvpfe.words_per_line = words_per_line;
638 +       lyrvpfe.lines_per_frame = lines_per_frame;
639 +
640 +       /************************************************/
641 +       /* Setup Fix VPFE parameter                     */
642 +       /************************************************/
643 +       /* Setup VPFE Hardware */
644 +       lyrvpfe.ccdc_regs->syn_mode = CCDC_WEN_BIT | CCDC_VDHDEN_BIT |
645 +               CCDC_VDPOL_NEG;
646 +
647 +       /* Start at Line 0 */
648 +       lyrvpfe.ccdc_regs->vert_start = 0;
649 +
650 +       /* Disable culling */
651 +       lyrvpfe.ccdc_regs->culling = 0xFFFF00FF;
652 +
653 +       lyrvpfe.ccdc_regs->sdofst   = 0;
654 +       lyrvpfe.ccdc_regs->clamp    = 0;
655 +       lyrvpfe.ccdc_regs->dcsub    = 0;
656 +       lyrvpfe.ccdc_regs->colptn   = 0;
657 +       lyrvpfe.ccdc_regs->blkcmp   = 0;
658 +       lyrvpfe.ccdc_regs->fpc      = 0;
659 +       lyrvpfe.ccdc_regs->vdint    = 0;
660 +       lyrvpfe.ccdc_regs->alaw     = 0;
661 +       lyrvpfe.ccdc_regs->rec656if = 0;
662 +
663 +       /* Disable shadowing as recommended in silicon errata. Very important,
664 +        * if not set, a lot of problems may occur. */
665 +       /* VDLC: Not latched on VSYNC. */
666 +       lyrvpfe.ccdc_regs->ccdcfg = (1 << 15);
667 +
668 +       /************************************************/
669 +       /* Setup variable VPFE parameter                */
670 +       /************************************************/
671 +       /* Max. length of a line */
672 +       lyrvpfe.ccdc_regs->horz_info = words_per_line * 4;
673 +
674 +       /* Max. number of lines per frame - 1 */
675 +       lyrvpfe.ccdc_regs->vert_lines = lines_per_frame - 1;
676 +
677 +       /* Offset of a line in memory (in bytes).
678 +        * Must be on 32 bytes boundary */
679 +       lyrvpfe.line_size = ((words_per_line * sizeof(u32)) + 31) & ~31;
680 +       lyrvpfe.ccdc_regs->hsize_off = lyrvpfe.line_size;
681 +
682 +       /* Enable CCDC */
683 +       lyrvpfe.ccdc_regs->pcr = 0x1;
684 +
685 +       return 0;
686 +}
687 +
688 +static void lyrvpfe_disable_vpfe(void)
689 +{
690 +       /* Disable CCDC */
691 +       lyrvpfe.ccdc_regs->pcr = 0;
692 +}
693 +
694 +static void lyrvpfe_dev_cleanup(void)
695 +{
696 +       DBGMSG("lyrvpfe_dev_cleanup()");
697 +
698 +       switch (lyrvpfe.init_state) {
699 +       case LYRVPFE_INIT_HAVE_PROC:
700 +#ifdef CONFIG_PROC_FS
701 +               remove_proc_entry(LYRVPFE_PROC_NAME, NULL);
702 +#endif
703 +       case LYRVPFE_INIT_HAVE_IRQ:
704 +               free_irq(lyrvpfe.irq, &lyrvpfe);
705 +       case LYRVPFE_INIT_HAVE_PONG_BUFFER:
706 +               kfree(lyrvpfe.data_buffers[BUFFER_PONG]);
707 +       case LYRVPFE_INIT_HAVE_PING_BUFFER:
708 +               kfree(lyrvpfe.data_buffers[BUFFER_PING]);
709 +       case LYRVPFE_INIT_VPFE:
710 +               lyrvpfe_disable_vpfe();
711 +       case LYRVPFE_INIT_HAVE_GPIO:
712 +               gpio_free(lyrvpfe.ready_gpio);
713 +       case LYRVPFE_INIT_HAVE_REGS:
714 +               iounmap(lyrvpfe.regs);
715 +       case LYRVPFE_INIT_START:
716 +               break;
717 +       }
718 +}
719 +
720 +struct bus_type lyrvpfe_bus_type = {
721 +       .name = "lyrvpfe",
722 +};
723 +EXPORT_SYMBOL(lyrvpfe_bus_type);
724 +
725 +static int lyrvpfe_probe(struct platform_device *pdev)
726 +{
727 +       struct lyrvpfe_platform_data *pdata;
728 +       struct resource *regs_res;
729 +       struct resource *irq_res;
730 +       int result;
731 +       void *buf;
732 +
733 +       DBGMSG("lyrvpfe_probe()");
734 +
735 +       /* We Should enable the VPFE with the PSC controller and PINMUX0. */
736 +
737 +       lyrvpfe.id = pdev->id;
738 +       lyrvpfe.dev.bus = &lyrvpfe_bus_type;
739 +       lyrvpfe.dev.parent = &pdev->dev;
740 +       snprintf(lyrvpfe.dev.bus_id, BUS_ID_SIZE, "lyrvpfe%d", lyrvpfe.id);
741 +       lyrvpfe.dev.bus_id[BUS_ID_SIZE - 1] = 0;
742 +       lyrvpfe.init_state = LYRVPFE_INIT_START;
743 +
744 +       regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
745 +       if (!regs_res) {
746 +               FAILMSG("Error getting REGS ressource");
747 +               result = -ENODEV;
748 +               goto error;
749 +       }
750 +
751 +       lyrvpfe.regs = ioremap(regs_res->start,
752 +                              regs_res->end - regs_res->start);
753 +       if (!lyrvpfe.regs) {
754 +               FAILMSG("Can't remap CCDC registers");
755 +               result = -ENXIO;
756 +               goto error;
757 +       }
758 +       lyrvpfe.ccdc_regs = (struct ccdc_regs *)
759 +               (lyrvpfe.regs + DAVINCI_CCDC_REGS_OFFSET);
760 +
761 +       lyrvpfe.init_state = LYRVPFE_INIT_HAVE_REGS;
762 +
763 +       pdata = pdev->dev.platform_data;
764 +       if (!pdata) {
765 +               FAILMSG("Error getting platform data");
766 +               result = -ENODEV;
767 +               goto error;
768 +       }
769 +       lyrvpfe.dev.platform_data = pdata;
770 +
771 +       /* Configure VPFE SET READY GPIO. */
772 +       lyrvpfe.ready_gpio = pdata->ready_gpio;
773 +
774 +       result = gpio_request(lyrvpfe.ready_gpio, "vpfe_ready");
775 +       if (result == 0) {
776 +               /* Must start at 1, if not gives errors. */
777 +               result = gpio_direction_output(lyrvpfe.ready_gpio, 1);
778 +       }
779 +       if (result != 0)
780 +               goto error;
781 +
782 +       lyrvpfe.init_state = LYRVPFE_INIT_HAVE_GPIO;
783 +
784 +       result = lyrvpfe_init_vpfe(LYRVPFE_LINES_PER_FRAME,
785 +                                  LYRVPFE_WORDS_PER_LINE);
786 +       if (result < 0) {
787 +               FAILMSG("lyrvpfe_init_vpfe() failed (%d)", result);
788 +               goto error;
789 +       }
790 +       lyrvpfe.init_state = LYRVPFE_INIT_VPFE;
791 +
792 +       /* Adding 256 to compensate for 256 bytes alignment */
793 +       lyrvpfe.bufsize = lyrvpfe.line_size * lyrvpfe.lines_per_frame + 256;
794 +
795 +       buf = kmalloc(lyrvpfe.bufsize /*LYRVPFE_BUFFER_SIZE*/, GFP_KERNEL);
796 +       if (!buf) {
797 +               result = -ENOMEM;
798 +               goto error;
799 +       }
800 +       /* Buffer must be 32 bytes aligned for the hardware but must be
801 +        * 256 bytes aligned to cope with cache line size. */
802 +       lyrvpfe.data_buffers[BUFFER_PING] =
803 +               (u32 *) (((u32) buf + 255) & 0xFFFFFF00);
804 +       lyrvpfe.data_buffers[BUFFER_PING][0] = 0x11111111;
805 +       lyrvpfe.data_buffers[BUFFER_PING][1] = 0x22222222;
806 +       lyrvpfe_invalidate_buffer(lyrvpfe.data_buffers[BUFFER_PING]);
807 +       lyrvpfe.init_state = LYRVPFE_INIT_HAVE_PING_BUFFER;
808 +
809 +       buf = kmalloc(lyrvpfe.bufsize /*LYRVPFE_BUFFER_SIZE*/, GFP_KERNEL);
810 +       if (!buf) {
811 +               result = -ENOMEM;
812 +               goto error;
813 +       }
814 +       /* Buffer must be 32 bytes aligned for the hardware but must be
815 +        * 256 bytes aligned to cope with cache line size. */
816 +       lyrvpfe.data_buffers[BUFFER_PONG] =
817 +               (u32 *) (((u32) buf + 255) & 0xFFFFFF00);
818 +       lyrvpfe.data_buffers[BUFFER_PONG][0] = 0x33333333;
819 +       lyrvpfe.data_buffers[BUFFER_PONG][1] = 0x44444444;
820 +       lyrvpfe_invalidate_buffer(lyrvpfe.data_buffers[BUFFER_PONG]);
821 +       lyrvpfe.init_state = LYRVPFE_INIT_HAVE_PONG_BUFFER;
822 +
823 +       lyrvpfe_set_ccdc_buffer(lyrvpfe.data_buffers[lyrvpfe.wrid]);
824 +
825 +       /* setup interrupt handling */
826 +       irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
827 +       if (!irq_res) {
828 +               FAILMSG("Error getting IRQ ressource");
829 +               result = -ENODEV;
830 +               goto error;
831 +       }
832 +
833 +       lyrvpfe.irq = irq_res->start;
834 +       result = request_irq(lyrvpfe.irq, lyrvpfe_isr,
835 +                            IRQF_SHARED /*IRQF_DISABLED*/,
836 +                            MODULE_NAME, &lyrvpfe);
837 +       if (result) {
838 +               FAILMSG("Error requesting IRQ ressource");
839 +               result = -ENODEV; /* To check */
840 +               goto error;
841 +       }
842 +
843 +       lyrvpfe.init_state = LYRVPFE_INIT_HAVE_IRQ;
844 +
845 +#ifdef CONFIG_PROC_FS
846 +       result = lyrvpfe_proc_init();
847 +       if (result < 0) {
848 +               FAILMSG("Error creating proc entry");
849 +               goto error;
850 +       }
851 +#endif
852 +
853 +       lyrvpfe.init_state = LYRVPFE_INIT_HAVE_PROC;
854 +
855 +       return 0;
856 +
857 +error:
858 +       lyrvpfe_dev_cleanup();
859 +       return result;
860 +}
861 +
862 +static int __devexit lyrvpfe_remove(struct platform_device *pdev)
863 +{
864 +       DBGMSG("lyrvpfe_remove()");
865 +
866 +       lyrvpfe_dev_cleanup();
867 +       return 0;
868 +}
869 +
870 +static struct platform_driver lyrvpfe_pdriver = {
871 +       .driver         = {
872 +               .name   = MODULE_NAME,
873 +               .owner  = THIS_MODULE,
874 +       },
875 +       .remove = lyrvpfe_remove,
876 +};
877 +
878 +static int __init lyrvpfe_init(void)
879 +{
880 +       int res = 0;
881 +
882 +       DBGMSG("lyrvpfe_init()");
883 +
884 +       res = bus_register(&lyrvpfe_bus_type);
885 +       if (res) {
886 +               FAILMSG("bus_register() failed");
887 +               goto fail_bus;
888 +       }
889 +
890 +       res = platform_driver_probe(&lyrvpfe_pdriver, lyrvpfe_probe);
891 +       if (res) {
892 +               FAILMSG("platform_driver_probe() failed");
893 +               goto fail_platform;
894 +       }
895 +
896 +       return 0;
897 +
898 +fail_platform:
899 +       bus_unregister(&lyrvpfe_bus_type);
900 +fail_bus:
901 +       return res;
902 +}
903 +module_init(lyrvpfe_init);
904 +
905 +static void __exit lyrvpfe_exit(void)
906 +{
907 +       DBGMSG("lyrvpfe_exit()");
908 +
909 +       platform_driver_unregister(&lyrvpfe_pdriver);
910 +       bus_unregister(&lyrvpfe_bus_type);
911 +}
912 +module_exit(lyrvpfe_exit);
913 +
914 +MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@lyrtech.com>");
915 +MODULE_DESCRIPTION("Lyrtech SFFSDR VPFE driver");
916 +MODULE_LICENSE("GPL");
917 -- 
918 1.5.4.5
919