patch-2.4.20 linux-2.4.20/arch/cris/drivers/virtex.c
Next file: linux-2.4.20/arch/cris/drivers/virtex.h
Previous file: linux-2.4.20/arch/cris/drivers/usb-host.c
Back to the patch index
Back to the overall index
- Lines: 406
- Date:
Thu Nov 28 15:53:09 2002
- Orig file:
linux-2.4.19/arch/cris/drivers/virtex.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -urN linux-2.4.19/arch/cris/drivers/virtex.c linux-2.4.20/arch/cris/drivers/virtex.c
@@ -0,0 +1,405 @@
+/*!***************************************************************************
+*!
+*! FILE NAME : vertex.c
+*!
+*! DESCRIPTION: Implements an interface towards virtex FPGA (mounted on one of our
+*! evaluation boards) from userspace using ioctl()'s
+*!
+*! The FPGA can be programmed by copying the bit-file to /dev/fpga.
+*!
+*! cp fpga.bit > /dev/fpga
+*!
+*! Kernel log should look like:
+*! 69900 bytes written
+*! FPGA-configuration completed, no errors
+*!
+*! Number of bytes written depends on the FPGA
+*!
+*! From Xilinx data sheet:
+*! XCV50 559,200 bits
+*! XCV100 781,216 bits
+*! XCV800 4,715,616 bits
+*!
+*! Accepted file type is the design.bit generated by Alliance
+*! Design Manager.
+*! This software just sends the bitfile into the device without
+*! checking device type etc.
+*!
+*! Sync-header 0xff 0xff 0xff 0xff defines the start for the
+*! byte stream, everything from that position is written to the FPGA.
+*!
+*!
+*! Jul 19 2002 Stefan Lundberg Initial version.
+*! $Log: virtex.c,v $
+*! Revision 1.1 2002/06/25 09:58:58 stefanl
+*! New FPGA driver for Platoon
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 2002 Axis Communications AB, LUND, SWEDEN
+*!
+*!***************************************************************************/
+/* $Id: virtex.c,v 1.1 2002/06/25 09:58:58 stefanl Exp $ */
+/****************** INCLUDE FILES SECTION ***********************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/config.h>
+
+#include <linux/hdreg.h>
+#include <linux/mm.h>
+
+#include <asm/etraxvirtex.h>
+
+#include <asm/system.h>
+#include <asm/svinto.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/delay.h>
+
+#include "virtex.h"
+
+/******************* VIRTEX DEFINITION SECTION **************************/
+
+#define VIRTEX_DEBUG(x)
+
+#define VIRTEX_MAJOR 246 /* EXPERIMENTAL */
+
+static const char virtex_name[] = "virtex";
+
+/****************** FUNCTION DEFINITION SECTION *************************/
+
+
+
+//
+// Read register interface for FPGA programming:
+//
+// FPGA_DONE is connected to S1CD_N G28
+// FPGA_INIT_N is connected to S1IO_N G27
+//
+
+// Write register interface for FPGA programming:
+//
+// Bit: 15 14 13 12 9 8 7 0
+// ____________________________________________________
+// | fpga_write | program | cclk | reserved | cs | data |
+// |____________|_________|______|__________|____|______|
+//
+
+
+// csp0 = cs_fpga1 = FPGA programming interface
+// csr0 = cs_fpga2 = register interface towards FPGA construction
+
+static volatile short *port_csp0_word_addr;
+static volatile short *port_csr0_word_addr;
+
+static volatile unsigned char open_count;
+static volatile unsigned char bytes_written;
+static volatile unsigned long bytes_written_cnt;
+static volatile unsigned char sync_found;
+static volatile unsigned char sync_count;
+static volatile unsigned char sync_ff_count;
+
+#define WRITE_FPGA_PROG_REG(data) *port_csp0_word_addr=(data)
+#define SET_PROGRAM_BIT(data) (data)|(1<<14)
+
+#define SET_WRITE_BIT(data) (data)|(1<<15)
+#define CLR_WRITE_BIT(data) (data)&(~(1<<15))
+
+#define SET_CS_BIT(data) (data)|(1<<8)
+#define CLR_CS_BIT(data) (data)&(~(1<<8))
+
+#define SET_CCLK_BIT(data) (data)|(1<<13)
+#define CLR_CCLK_BIT(data) (data)&(~(1<<13))
+
+// Bit in read port G (always inputs)
+#define READ_INIT (*R_PORT_G_DATA)&(1<<27)
+#define READ_DONE (*R_PORT_G_DATA)&(1<<28)
+
+
+void start_virtex_program(void)
+{
+ unsigned short reg_data=0;
+
+ printk("Start writing to FPGA\n");
+ reg_data = SET_CS_BIT(reg_data); // FPGA unselected
+
+ reg_data = SET_PROGRAM_BIT(reg_data);
+ WRITE_FPGA_PROG_REG(reg_data);
+
+ while(!READ_INIT); // Wait for init
+
+ reg_data = SET_WRITE_BIT(reg_data);
+ WRITE_FPGA_PROG_REG(reg_data);
+
+ reg_data = CLR_CS_BIT(reg_data); // FPGA selected, CS is active low
+ WRITE_FPGA_PROG_REG(reg_data);
+ return;
+}
+
+// According to datasheet, bytes should be reversed, it is unknown to me why.
+unsigned char bit_reverse(unsigned char data)
+{
+ unsigned char in=data;
+ unsigned short out=0;
+ unsigned int i=0;
+
+ for(i=0;i<8;i++) {
+ if(in&0x1) {
+ out|=0x1;
+ }
+ in=in>>1;
+ out=out<<1;
+ }
+
+ return(out>>1);
+
+}
+
+void virtex_program(char* ptr,size_t count)
+{
+ int c;
+ char *p;
+ unsigned char data;
+ unsigned short reg_data=0;
+// short tmp_cnt;
+
+ c=count;
+ p=ptr;
+
+ if(!sync_found) {
+ c=count;
+ p=ptr;
+ while(c--) {
+ data=(unsigned char)*p++;
+ sync_count++;
+
+ if(sync_count>=256) {
+ printk("Sync not found, aborting\n");
+ return;
+ }
+
+ if(data==0xff) {
+ sync_ff_count++;
+ } else {
+ sync_ff_count=0;
+ }
+ if(sync_ff_count==4) {
+ sync_found=1;
+ VIRTEX_DEBUG(printk("Sync found at offset %d\n",sync_count));
+ p--;p--;p--;p--;
+ c++;c++;c++;c++;
+ break;
+ }
+ }
+ }
+
+ if(sync_found) {
+ if(bytes_written==0) {
+ start_virtex_program();
+ }
+ bytes_written=1;
+
+ reg_data = SET_PROGRAM_BIT(reg_data);
+ reg_data = SET_WRITE_BIT(reg_data);
+ reg_data = CLR_CS_BIT(reg_data);
+
+// tmp_cnt=0;
+
+ printk("*");
+ while(c--) {
+ data=(unsigned char)*p++;
+ data=bit_reverse(data);
+
+/* debug
+ tmp_cnt++;
+ if(tmp_cnt<=32 || c<=32 ) {
+ printk("0x%x ",data);
+ }
+ if(tmp_cnt==32 || c==0 ) {
+ printk("\n");
+ }
+*/
+ bytes_written_cnt++;
+ reg_data = CLR_CCLK_BIT(reg_data);
+ WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+ reg_data = SET_CCLK_BIT(reg_data);
+ WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+ reg_data = CLR_CCLK_BIT(reg_data);
+ WRITE_FPGA_PROG_REG(reg_data|(data&0xff));
+
+ }
+ }
+
+ return;
+}
+
+void stop_virtex_program(void)
+{
+ unsigned short reg_data=0;
+
+ reg_data = SET_PROGRAM_BIT(reg_data);
+ reg_data = SET_WRITE_BIT(reg_data);
+ reg_data = CLR_CCLK_BIT(reg_data);
+
+ reg_data = SET_CS_BIT(reg_data); // release CS
+ WRITE_FPGA_PROG_REG(reg_data);
+
+ reg_data = CLR_WRITE_BIT(reg_data); // release write, important to do!
+ WRITE_FPGA_PROG_REG(reg_data);
+ printk("%d bytes written\n",bytes_written_cnt);
+ if(READ_DONE) {
+ printk("FPGA-configuration completed, no errors\n");
+ } else {
+ printk("Error, FPGA-configuration failed\n");
+ }
+ return;
+}
+
+static int
+virtex_open(struct inode *inode, struct file *filp)
+{
+ port_csp0_word_addr = port_csp0_addr;
+ if(open_count>=1) {
+ printk("FPGA Device busy, aborting\n");
+ return(-EBUSY);
+ }
+ open_count++;
+ bytes_written=0;
+ sync_found=0;
+ sync_count=0;
+ sync_ff_count=0;
+ bytes_written_cnt=0;
+ return(0);
+}
+
+static int
+virtex_release(struct inode *inode, struct file *filp)
+{
+ open_count--;
+ if(bytes_written!=0)stop_virtex_program();
+ return 0;
+}
+
+// FPGA programming interface
+
+static ssize_t virtex_write(struct file * file, const char * buf,
+ size_t count, loff_t *ppos)
+{
+ char *ptr;
+ VIRTEX_DEBUG(printk("Write FPGA count %d\n", count));
+
+ ptr=kmalloc(count, GFP_KERNEL);
+ if(!ptr) {
+ printk("FPGA device, kernel malloc failed (%d) bytes\n",count);
+ return -EFAULT;
+ }
+ if(copy_from_user(ptr, buf, count)) {
+ printk("copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ virtex_program(ptr,count);
+
+ kfree(ptr);
+ return count;
+}
+
+/* Main device API. ioctl's to write or read to/from registers.
+ */
+
+int virtex_writereg(unsigned short theReg, unsigned short theValue)
+{
+ port_csr0_word_addr[theReg]=theValue;
+ return(0);
+}
+
+unsigned short virtex_readreg(unsigned short theReg)
+{
+ return(port_csr0_word_addr[theReg]);
+}
+
+
+static int
+virtex_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ if(_IOC_TYPE(cmd) != ETRAXVIRTEX_FPGA_IOCTYPE) {
+ return -EINVAL;
+ }
+
+ switch (_IOC_NR(cmd)) {
+ case VIRTEX_FPGA_WRITEREG:
+ /* write to an FPGA register */
+ VIRTEX_DEBUG(printk("virtex wr %d %d\n",
+ VIRTEX_FPGA_ARGREG(arg),
+ VIRTEX_FPGA_ARGVALUE(arg)));
+
+ return virtex_writereg(VIRTEX_FPGA_ARGREG(arg),
+ VIRTEX_FPGA_ARGVALUE(arg));
+ case VIRTEX_FPGA_READREG:
+ {
+ unsigned char val;
+ /* read from an FPGA register */
+ VIRTEX_DEBUG(printk("virtex rd %d ",
+ VIRTEX_FPGA_ARGREG(arg)));
+ val = virtex_readreg(VIRTEX_FPGA_ARGREG(arg));
+ VIRTEX_DEBUG(printk("= %d\n", val));
+ return val;
+ }
+ default:
+ return -EINVAL;
+ }
+
+return 0;
+}
+
+static struct file_operations virtex_fops = {
+ owner: THIS_MODULE,
+ ioctl: virtex_ioctl,
+ open: virtex_open,
+ write: virtex_write,
+ release: virtex_release,
+};
+
+static int __init
+virtex_init(void)
+{
+ int res;
+
+ /* register char device */
+ res = register_chrdev(VIRTEX_MAJOR, virtex_name, &virtex_fops);
+ if(res < 0) {
+ printk(KERN_ERR "virtex: couldn't get a major number.\n");
+ return res;
+ }
+
+ port_csr0_word_addr = (volatile unsigned short *)
+ ioremap((unsigned long)(MEM_CSR0_START |
+ MEM_NON_CACHEABLE), 16);
+
+// see ~/platoon/rel2/platoon/os/linux/arch/cris/mm/init.c
+// port_csp0_addr = (volatile unsigned long *)
+// ioremap((unsigned long)(MEM_CSP0_START |
+// MEM_NON_CACHEABLE), 16);
+
+ open_count=0;
+
+ printk("VIRTEX(TM) FPGA driver v1.0, (c) 2002 Axis Communications AB\n");
+
+ return 0;
+}
+
+/* this makes sure that virtex_init is called during boot */
+
+module_init(virtex_init);
+
+/****************** END OF FILE virtex.c ********************************/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)