From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ben Warren Date: Thu, 27 Sep 2007 14:31:39 -0400 Subject: [U-Boot-Users] FPGA loading question In-Reply-To: <3972542e0709271101n4929c08bp381e7d75c3ce72e8@mail.gmail.com> References: <3972542e0709261348j2895ea66vb906f1fee761b559@mail.gmail.com> <200709271521.55586.matthias.fuchs@esd-electronics.com> <200709271747.28229.sr@denx.de> <3972542e0709270910m2ab84a80td1017771b81af2bb@mail.gmail.com> <46FBEA2A.3070806@qstreams.com> <3972542e0709271101n4929c08bp381e7d75c3ce72e8@mail.gmail.com> Message-ID: <46FBF70B.9060605@qstreams.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de E Robertson wrote: > On 9/27/07, Ben Warren wrote: > >> E Robertson wrote: >> >>> On 9/27/07, Stefan Roese 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@a time */ for (i=0;i=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