All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Warren <bwarren@qstreams.com>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] FPGA loading question
Date: Thu, 27 Sep 2007 14:31:39 -0400	[thread overview]
Message-ID: <46FBF70B.9060605@qstreams.com> (raw)
In-Reply-To: <3972542e0709271101n4929c08bp381e7d75c3ce72e8@mail.gmail.com>

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@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

      reply	other threads:[~2007-09-27 18:31 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-09-26 20:48 [U-Boot-Users] FPGA loading question E Robertson
2007-09-27 13:21 ` Matthias Fuchs
2007-09-27 15:47   ` Stefan Roese
2007-09-27 16:10     ` E Robertson
2007-09-27 17:36       ` Ben Warren
2007-09-27 18:01         ` E Robertson
2007-09-27 18:31           ` Ben Warren [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=46FBF70B.9060605@qstreams.com \
    --to=bwarren@qstreams.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.