[U-Boot-Users] FPGA loading question
Ben Warren
bwarren at qstreams.com
Thu Sep 27 20:31:39 CEST 2007
E Robertson wrote:
> On 9/27/07, Ben Warren <bwarren at qstreams.com> wrote:
>
>> E Robertson wrote:
>>
>>> On 9/27/07, Stefan Roese <sr at 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
More information about the U-Boot
mailing list