
E Robertson wrote:
On 9/27/07, Ben Warren bwarren@qstreams.com wrote:
E Robertson wrote:
On 9/27/07, Stefan Roese sr@denx.de wrote:
Hi Matthias,
On Thursday 27 September 2007, Matthias Fuchs wrote:
What kind of CPU are you using? Please note that 4xx U-Boot ports have the cache disabled. Without cache booting a Spartan 3E in SS-mode may take very very :-(
Only 44x have cache disabled. 40x has icache enabled.
BTW: I'm still waiting for the patch to enable the cache on 44x systems... ;)
Viele Grüße, Stefan
I'm using an NXP ARM9 'A404 and can disable cache on my platform. Due to my hardware fool-up, I'll have to use a bit banging method. I'm also concern about loading error and recovery and I'm considering instead to do the programming in the kernel. If there is a problem for some reason and the FPGA needs to be reloaded, I'll have to do it in the kernel anyway. I'm not sure about embedding a bin file in the kernel driver either but It's worth pursuing.
If your design can wait until Linux is booted before programming the FPGA, you have a world of possibilities available. In my designs, I have a simple char driver with a 'write' method that bit-bangs the image in. This way you can keep your image as a file in the file system and can add whatever encryption, wrapper or whatever your heart desires. It makes trying different FPGA images a breeze.
I'm actually in the middle of doing that with a simple char device driver. I have'n't got to the bit banging write part yet but I'll appreciate a code snip that actually parses the file for the bits. I'm assuming it'll be some sort of shift right for a char read increment or some sort of XOR operation. I haven't thought through that part yet but is that how is normally done?
/*** Here's my implementation. I'm sure it could be much better, but it seems to work. Note that all the programming bits are routed through a CPLD, that's what all the 'cpld*' function calls are for. We use this on a Virtex II, but Spartan's probably the same. The main structure of the write function is lifted by Rubini LDD3. I don't really have time to genericize it for you, but please feel free to ask questions/make suggestions for improvement. ***/
ssize_t fpga_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { int i,j; unsigned char *page_ptr; struct fpga_dev *dev = filp->private_data; u8 index = dev->index; u16 val; int rc = 0;
if (!(page_ptr = (unsigned char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; if (copy_from_user(page_ptr, buf, count)) rc = -EFAULT;
/* First page of data, we set up the programming environment */ if (*f_pos == 0) { /* First, enable FPGA programming */ cpld_fpga_prog_enable(1);
/* Next, driver nPROG low for 300 ns */ cpld_fpga_write_prog(index, 0); ndelay(300); cpld_fpga_write_prog(index, 1); i = 1000; while (!cpld_fpga_check_init(index) && --i) {;} if (count <= 0) { printk(KERN_ALERT "fpga_write: timed out waiting \n"); return -EFAULT; } } /* Process a byte at a time */ for (i=0;i<count;i++) { for (j=7;j>=0;j--) { /* Shift each bit through */ if (page_ptr[i] & (1 << j)) cpld_fpga_write_data(index, 1); else cpld_fpga_write_data(index, 0); } }
if (cpld_fpga_check_done(index) != 0) { val = (u16)readFpgaReg(dev->virtAddr + FPGA_ADDR_REV_DBG/2); printk(KERN_INFO "FPGA%d loaded with version 0x%02x\n", index, val & 0xff); } if (page_ptr) free_page((u32)page_ptr); *f_pos += count; return count; }
/*** Here's the code from my CPLD driver, that writes the various control bits (FPGA_DONE, FPGA_PROG, FPGA_DONE, FPGA_INIT) that are memory mapped into a CPLD register. We have 2 FPGAs, that's what the device index is for: ***/
u8 cpld_fpga_check_init(u8 device) { return (readCpldReg(device == 0 ? &cpld_device->regs->clFpgaStat : &cpld_device->regs->liFpgaStat) & FPGA_INIT); }
EXPORT_SYMBOL(cpld_fpga_check_init);
u8 cpld_fpga_check_done(u8 device) { return (readCpldReg(device == 0 ? &cpld_device->regs->clFpgaStat : &cpld_device->regs->liFpgaStat) & FPGA_DONE); }
EXPORT_SYMBOL(cpld_fpga_check_done);
int cpld_fpga_write_prog(u8 device, u8 enable) { u16 *addr = (device == 0 ? &cpld_device->regs->clFpgaCtrl : &cpld_device->regs->liFpgaCtrl); writeCpldRegRaw(addr, enable ? FPGA_PROG : 0); return 0; }
EXPORT_SYMBOL(cpld_fpga_write_prog);
int cpld_fpga_write_clock(u8 device, u8 enable) { u16 *addr = (device == 0 ? &cpld_device->regs->clFpgaCtrl : &cpld_device->regs->liFpgaCtrl); writeCpldReg(addr, enable ? FPGA_CLK : ~FPGA_CLK, FPGA_CLK); return 0; }
EXPORT_SYMBOL(cpld_fpga_write_clock);
int cpld_fpga_write_data(u8 device, u8 bit) { u16 *addr = (device == 0 ? &cpld_device->regs->clFpgaCtrl : &cpld_device->regs->liFpgaCtrl); /* Write data & low clock together */ u16 val = bit ? FPGA_PROG | FPGA_DOUT : FPGA_PROG; writeCpldRegRaw(addr, val); /* Drive the clock high */ val |= FPGA_CLK; writeCpldRegRaw(addr, val); return 0; }
EXPORT_SYMBOL(cpld_fpga_write_data)
regards, Ben