virtex.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
- /*!***************************************************************************
- *!
- *! 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 FPGAn");
- 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, abortingn");
- 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 %dn",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 writtenn",bytes_written_cnt);
- if(READ_DONE) {
- printk("FPGA-configuration completed, no errorsn");
- } else {
- printk("Error, FPGA-configuration failedn");
- }
- 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, abortingn");
- 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 %dn", count));
-
- ptr=kmalloc(count, GFP_KERNEL);
- if(!ptr) {
- printk("FPGA device, kernel malloc failed (%d) bytesn",count);
- return -EFAULT;
- }
- if(copy_from_user(ptr, buf, count)) {
- printk("copy_from_user failedn");
- 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 %dn",
- 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("= %dn", 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 ABn");
-
- return 0;
- }
- /* this makes sure that virtex_init is called during boot */
- module_init(virtex_init);
- /****************** END OF FILE virtex.c ********************************/