blob: febbf85f76fddef9c1b7876438baef7f9b077b35 [file] [log] [blame]
/*!***************************************************************************
*!
*! 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.
*!
*! cat 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.2 2003/02/24 07:50:30 fredriko
*! Bugfixes and cleanups.
*!
*! 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.2 2003/02/24 07:50:30 fredriko 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)
{
volatile unsigned int i=0;
unsigned short reg_data=0;
printk("Start writing to FPGA\n");
reg_data = SET_CS_BIT(reg_data); // FPGA unselected, PROGRAM bit not set
WRITE_FPGA_PROG_REG(reg_data);
for(i=0;i<10;i++) { } // at least 300 ns loop
reg_data = SET_PROGRAM_BIT(reg_data);
WRITE_FPGA_PROG_REG(reg_data);
for(i=0;i<10;i++) { } // at least 300 ns loop
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");
kfree(ptr);
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 0x%x = 0x%x\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 short val;
/* read from an FPGA register */
VIRTEX_DEBUG(printk("virtex rd 0x%x ",
VIRTEX_FPGA_ARGREG(arg)));
val = virtex_readreg(VIRTEX_FPGA_ARGREG(arg));
VIRTEX_DEBUG(printk("= 0x%x\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 ********************************/