[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