?? virtex.c
字號:
/*!****************************************************************************!*! 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 constructionstatic 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 intvirtex_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 intvirtex_release(struct inode *inode, struct file *filp){ open_count--; if(bytes_written!=0)stop_virtex_program(); return 0;}// FPGA programming interfacestatic 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 intvirtex_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 __initvirtex_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 ********************************/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -