Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c4015bd authored by Simon Farnsworth's avatar Simon Farnsworth Committed by David Woodhouse
Browse files

solos: FPGA and firmware update support.



This is just a straight pull in of changes, syncing us up to 0.07 from
openadsl.sf.net

Signed-off-by: default avatarNathan Williams <nathan@traverse.com.au>
Signed-off-by: default avatarSimon Farnsworth <simon@farnz.org.uk>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 4306cad6
Loading
Loading
Loading
Loading
+169 −2
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
 *
 * Authors: Nathan Williams <nathan@traverse.com.au>
 *          David Woodhouse <dwmw2@infradead.org>
 *          Treker Chen <treker@xrio.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
@@ -36,8 +37,9 @@
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/kobject.h>
#include <linux/firmware.h>

#define VERSION "0.04"
#define VERSION "0.07"
#define PTAG "solos-pci"

#define CONFIG_RAM_SIZE	128
@@ -45,16 +47,27 @@
#define IRQ_EN_ADDR	0x78
#define FPGA_VER	0x74
#define IRQ_CLEAR	0x70
#define BUG_FLAG	0x6C
#define WRITE_FLASH	0x6C
#define PORTS		0x68
#define FLASH_BLOCK	0x64
#define FLASH_BUSY	0x60
#define FPGA_MODE	0x5C
#define FLASH_MODE	0x58

#define DATA_RAM_SIZE	32768
#define BUF_SIZE	4096
#define FPGA_PAGE	528 /* FPGA flash page size*/
#define SOLOS_PAGE	512 /* Solos flash page size*/
#define FPGA_BLOCK	(FPGA_PAGE * 8) /* FPGA flash block size*/
#define SOLOS_BLOCK	(SOLOS_PAGE * 8) /* Solos flash block size*/

#define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2)
#define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE)

static int debug = 0;
static int atmdebug = 0;
static int firmware_upgrade = 0;
static int fpga_upgrade = 0;

struct pkt_hdr {
	__le16 size;
@@ -80,6 +93,7 @@ struct solos_card {
	spinlock_t cli_queue_lock;
	struct sk_buff_head tx_queue[4];
	struct sk_buff_head cli_queue[4];
	int flash_chip;
};

#define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
@@ -90,11 +104,19 @@ MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_PARM_DESC(debug, "Enable Loopback");
MODULE_PARM_DESC(atmdebug, "Print ATM data");
MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade");
module_param(debug, int, 0444);
module_param(atmdebug, int, 0644);
module_param(firmware_upgrade, int, 0444);
module_param(fpga_upgrade, int, 0444);

static int opens;
static struct firmware *fw;
static int flash_offset;

void flash_upgrade(struct solos_card *);
void flash_write(struct solos_card *);
static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
		       struct atm_vcc *vcc);
static int fpga_tx(struct solos_card *);
@@ -180,6 +202,131 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,

static DEVICE_ATTR(console, 0644, console_show, console_store);

void flash_upgrade(struct solos_card *card){
	uint32_t data32 = 0;
	int blocksize = 0;
	int numblocks = 0;
	dev_info(&card->dev->dev, "Flash upgrade started\n");
	if (card->flash_chip == 0) {
		if (request_firmware((const struct firmware **)&fw,
				"solos-FPGA.bin",&card->dev->dev))
		{
			dev_info(&card->dev->dev,
					"Failed to find firmware\n");
			return;
		}
		blocksize = FPGA_BLOCK;
	} else {
		if (request_firmware((const struct firmware **)&fw,
				"solos-Firmware.bin",&card->dev->dev))
		{
			dev_info(&card->dev->dev,
					"Failed to find firmware\n");
			return;
		}
		blocksize = SOLOS_BLOCK;
	}
	numblocks = fw->size/blocksize;
	dev_info(&card->dev->dev, "Firmware size: %d\n", fw->size);
	dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
	
		
	dev_info(&card->dev->dev, "Changing FPGA to Update mode\n");
	iowrite32(1, card->config_regs + FPGA_MODE);
	data32 = ioread32(card->config_regs + FPGA_MODE); 
	/*Set mode to Chip Erase*/
	if (card->flash_chip == 0) {
		dev_info(&card->dev->dev, 
				"Set FPGA Flash mode to FPGA Chip Erase\n");
	} else {
		dev_info(&card->dev->dev, 
				"Set FPGA Flash mode to Solos Chip Erase\n");
	}
	iowrite32((card->flash_chip * 2), card->config_regs + FLASH_MODE);
	flash_offset = 0;
	iowrite32(1, card->config_regs + WRITE_FLASH);
	return;
}

void flash_write(struct solos_card *card){
	int block;
	int block_num;
	int blocksize;
	int i;
	uint32_t data32 = 0;

	/*Clear write flag*/
	iowrite32(0, card->config_regs + WRITE_FLASH);
	/*Set mode to Block Write*/
	/*dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n");*/
	iowrite32(((card->flash_chip * 2) + 1), card->config_regs + FLASH_MODE);

	/*When finished programming flash, release firmware and exit*/
	if (fw->size - flash_offset == 0) {
		//release_firmware(fw); /* This crashes for some reason */
		iowrite32(0, card->config_regs + WRITE_FLASH);
		iowrite32(0, card->config_regs + FPGA_MODE);
		iowrite32(0, card->config_regs + FLASH_MODE);
		dev_info(&card->dev->dev, "Returning FPGA to Data mode\n");
		return;
	}
	if (card->flash_chip == 0) {
		blocksize = FPGA_BLOCK;
	} else {
		blocksize = SOLOS_BLOCK;
	}
	
	/*Calculate block size*/
	if ((fw->size - flash_offset) > blocksize) {
		block = blocksize;
	} else {
		block = fw->size - flash_offset;
	}
	block_num = flash_offset / blocksize;
	//dev_info(&card->dev->dev, "block %d/%d\n",block_num + 1,(fw->size/512/8));

	/*Copy block into RAM*/
	for(i=0;i<block;i++){
		if(i%4 == 0){
			//dev_info(&card->dev->dev, "i: %d\n", i);
			data32=0x00000000;
		}
		
		switch(i%4){
		case 0:
			data32 |= 0x0000FF00 & 
				(*(fw->data + i + flash_offset)	<< 8);
			break;
		case 1:
			data32 |= 0x000000FF & *(fw->data + i + flash_offset);
			break;
		case 2:
			data32 |= 0xFF000000 &
					(*(fw->data + i + flash_offset)	<< 24);
			break;
		case 3:
			data32 |= 0x00FF0000 &
					(*(fw->data + i + flash_offset)	<< 16);
			break;
		}

		if (i%4 == 3) {
			iowrite32(data32, RX_BUF(card, 3) + i - 3);
		}
	}
	i--;
	if (i%4 != 3) {
		iowrite32(data32, RX_BUF(card, 3) + i - (i%4));
	}

	/*Specify block number and then trigger flash write*/
	iowrite32(block_num, card->config_regs + FLASH_BLOCK);
	iowrite32(1, card->config_regs + WRITE_FLASH);
//	iowrite32(0, card->config_regs + WRITE_FLASH);
	flash_offset += block;
	return;
}

static irqreturn_t solos_irq(int irq, void *dev_id)
{
	struct solos_card *card = dev_id;
@@ -207,6 +354,17 @@ void solos_bh(unsigned long card_arg)
	uint32_t card_flags;
	uint32_t tx_mask;
	uint32_t rx_done = 0;
	uint32_t data32;

	data32 = ioread32(card->config_regs + FPGA_MODE); 
	if (data32 != 0) {
		data32 = ioread32(card->config_regs + FLASH_BUSY); 
		if (data32 == 0) {
			flash_write(card);
		}	
		return;
	}
		

	card_flags = ioread32(card->config_regs + FLAGS_ADDR);

@@ -680,6 +838,15 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
	// Enable IRQs
	iowrite32(1, card->config_regs + IRQ_EN_ADDR);

	if(firmware_upgrade != 0){
		card->flash_chip = 1;
		flash_upgrade(card);
	} else {
		if(fpga_upgrade != 0){
			card->flash_chip = 0;
			flash_upgrade(card);
		}
	}
	return 0;

 out_unmap_both: