diff options
author | Simon Farnsworth <simon@farnz.org.uk> | 2009-01-21 15:45:49 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-01-26 22:18:32 -0500 |
commit | 7c4015bdffed7c961b6df46c6326cc65962e6594 (patch) | |
tree | b5b043ac75cb9bd696f8a563919f14eb8394d429 /drivers/atm/solos-pci.c | |
parent | 4306cad6fe02e2946183ab29e510f94190b8fff3 (diff) |
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: Nathan Williams <nathan@traverse.com.au>
Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/atm/solos-pci.c')
-rw-r--r-- | drivers/atm/solos-pci.c | 171 |
1 files changed, 169 insertions, 2 deletions
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 3daa3a374313..2b472c898c85 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * | 9 | * |
10 | * Authors: Nathan Williams <nathan@traverse.com.au> | 10 | * Authors: Nathan Williams <nathan@traverse.com.au> |
11 | * David Woodhouse <dwmw2@infradead.org> | 11 | * David Woodhouse <dwmw2@infradead.org> |
12 | * Treker Chen <treker@xrio.com> | ||
12 | * | 13 | * |
13 | * This program is free software; you can redistribute it and/or | 14 | * This program is free software; you can redistribute it and/or |
14 | * modify it under the terms of the GNU General Public License | 15 | * modify it under the terms of the GNU General Public License |
@@ -36,8 +37,9 @@ | |||
36 | #include <linux/sysfs.h> | 37 | #include <linux/sysfs.h> |
37 | #include <linux/device.h> | 38 | #include <linux/device.h> |
38 | #include <linux/kobject.h> | 39 | #include <linux/kobject.h> |
40 | #include <linux/firmware.h> | ||
39 | 41 | ||
40 | #define VERSION "0.04" | 42 | #define VERSION "0.07" |
41 | #define PTAG "solos-pci" | 43 | #define PTAG "solos-pci" |
42 | 44 | ||
43 | #define CONFIG_RAM_SIZE 128 | 45 | #define CONFIG_RAM_SIZE 128 |
@@ -45,16 +47,27 @@ | |||
45 | #define IRQ_EN_ADDR 0x78 | 47 | #define IRQ_EN_ADDR 0x78 |
46 | #define FPGA_VER 0x74 | 48 | #define FPGA_VER 0x74 |
47 | #define IRQ_CLEAR 0x70 | 49 | #define IRQ_CLEAR 0x70 |
48 | #define BUG_FLAG 0x6C | 50 | #define WRITE_FLASH 0x6C |
51 | #define PORTS 0x68 | ||
52 | #define FLASH_BLOCK 0x64 | ||
53 | #define FLASH_BUSY 0x60 | ||
54 | #define FPGA_MODE 0x5C | ||
55 | #define FLASH_MODE 0x58 | ||
49 | 56 | ||
50 | #define DATA_RAM_SIZE 32768 | 57 | #define DATA_RAM_SIZE 32768 |
51 | #define BUF_SIZE 4096 | 58 | #define BUF_SIZE 4096 |
59 | #define FPGA_PAGE 528 /* FPGA flash page size*/ | ||
60 | #define SOLOS_PAGE 512 /* Solos flash page size*/ | ||
61 | #define FPGA_BLOCK (FPGA_PAGE * 8) /* FPGA flash block size*/ | ||
62 | #define SOLOS_BLOCK (SOLOS_PAGE * 8) /* Solos flash block size*/ | ||
52 | 63 | ||
53 | #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2) | 64 | #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2) |
54 | #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE) | 65 | #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE) |
55 | 66 | ||
56 | static int debug = 0; | 67 | static int debug = 0; |
57 | static int atmdebug = 0; | 68 | static int atmdebug = 0; |
69 | static int firmware_upgrade = 0; | ||
70 | static int fpga_upgrade = 0; | ||
58 | 71 | ||
59 | struct pkt_hdr { | 72 | struct pkt_hdr { |
60 | __le16 size; | 73 | __le16 size; |
@@ -80,6 +93,7 @@ struct solos_card { | |||
80 | spinlock_t cli_queue_lock; | 93 | spinlock_t cli_queue_lock; |
81 | struct sk_buff_head tx_queue[4]; | 94 | struct sk_buff_head tx_queue[4]; |
82 | struct sk_buff_head cli_queue[4]; | 95 | struct sk_buff_head cli_queue[4]; |
96 | int flash_chip; | ||
83 | }; | 97 | }; |
84 | 98 | ||
85 | #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) | 99 | #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) |
@@ -90,11 +104,19 @@ MODULE_VERSION(VERSION); | |||
90 | MODULE_LICENSE("GPL"); | 104 | MODULE_LICENSE("GPL"); |
91 | MODULE_PARM_DESC(debug, "Enable Loopback"); | 105 | MODULE_PARM_DESC(debug, "Enable Loopback"); |
92 | MODULE_PARM_DESC(atmdebug, "Print ATM data"); | 106 | MODULE_PARM_DESC(atmdebug, "Print ATM data"); |
107 | MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade"); | ||
108 | MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade"); | ||
93 | module_param(debug, int, 0444); | 109 | module_param(debug, int, 0444); |
94 | module_param(atmdebug, int, 0644); | 110 | module_param(atmdebug, int, 0644); |
111 | module_param(firmware_upgrade, int, 0444); | ||
112 | module_param(fpga_upgrade, int, 0444); | ||
95 | 113 | ||
96 | static int opens; | 114 | static int opens; |
115 | static struct firmware *fw; | ||
116 | static int flash_offset; | ||
97 | 117 | ||
118 | void flash_upgrade(struct solos_card *); | ||
119 | void flash_write(struct solos_card *); | ||
98 | static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, | 120 | static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, |
99 | struct atm_vcc *vcc); | 121 | struct atm_vcc *vcc); |
100 | static int fpga_tx(struct solos_card *); | 122 | static int fpga_tx(struct solos_card *); |
@@ -180,6 +202,131 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr, | |||
180 | 202 | ||
181 | static DEVICE_ATTR(console, 0644, console_show, console_store); | 203 | static DEVICE_ATTR(console, 0644, console_show, console_store); |
182 | 204 | ||
205 | void flash_upgrade(struct solos_card *card){ | ||
206 | uint32_t data32 = 0; | ||
207 | int blocksize = 0; | ||
208 | int numblocks = 0; | ||
209 | dev_info(&card->dev->dev, "Flash upgrade started\n"); | ||
210 | if (card->flash_chip == 0) { | ||
211 | if (request_firmware((const struct firmware **)&fw, | ||
212 | "solos-FPGA.bin",&card->dev->dev)) | ||
213 | { | ||
214 | dev_info(&card->dev->dev, | ||
215 | "Failed to find firmware\n"); | ||
216 | return; | ||
217 | } | ||
218 | blocksize = FPGA_BLOCK; | ||
219 | } else { | ||
220 | if (request_firmware((const struct firmware **)&fw, | ||
221 | "solos-Firmware.bin",&card->dev->dev)) | ||
222 | { | ||
223 | dev_info(&card->dev->dev, | ||
224 | "Failed to find firmware\n"); | ||
225 | return; | ||
226 | } | ||
227 | blocksize = SOLOS_BLOCK; | ||
228 | } | ||
229 | numblocks = fw->size/blocksize; | ||
230 | dev_info(&card->dev->dev, "Firmware size: %d\n", fw->size); | ||
231 | dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks); | ||
232 | |||
233 | |||
234 | dev_info(&card->dev->dev, "Changing FPGA to Update mode\n"); | ||
235 | iowrite32(1, card->config_regs + FPGA_MODE); | ||
236 | data32 = ioread32(card->config_regs + FPGA_MODE); | ||
237 | /*Set mode to Chip Erase*/ | ||
238 | if (card->flash_chip == 0) { | ||
239 | dev_info(&card->dev->dev, | ||
240 | "Set FPGA Flash mode to FPGA Chip Erase\n"); | ||
241 | } else { | ||
242 | dev_info(&card->dev->dev, | ||
243 | "Set FPGA Flash mode to Solos Chip Erase\n"); | ||
244 | } | ||
245 | iowrite32((card->flash_chip * 2), card->config_regs + FLASH_MODE); | ||
246 | flash_offset = 0; | ||
247 | iowrite32(1, card->config_regs + WRITE_FLASH); | ||
248 | return; | ||
249 | } | ||
250 | |||
251 | void flash_write(struct solos_card *card){ | ||
252 | int block; | ||
253 | int block_num; | ||
254 | int blocksize; | ||
255 | int i; | ||
256 | uint32_t data32 = 0; | ||
257 | |||
258 | /*Clear write flag*/ | ||
259 | iowrite32(0, card->config_regs + WRITE_FLASH); | ||
260 | /*Set mode to Block Write*/ | ||
261 | /*dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n");*/ | ||
262 | iowrite32(((card->flash_chip * 2) + 1), card->config_regs + FLASH_MODE); | ||
263 | |||
264 | /*When finished programming flash, release firmware and exit*/ | ||
265 | if (fw->size - flash_offset == 0) { | ||
266 | //release_firmware(fw); /* This crashes for some reason */ | ||
267 | iowrite32(0, card->config_regs + WRITE_FLASH); | ||
268 | iowrite32(0, card->config_regs + FPGA_MODE); | ||
269 | iowrite32(0, card->config_regs + FLASH_MODE); | ||
270 | dev_info(&card->dev->dev, "Returning FPGA to Data mode\n"); | ||
271 | return; | ||
272 | } | ||
273 | if (card->flash_chip == 0) { | ||
274 | blocksize = FPGA_BLOCK; | ||
275 | } else { | ||
276 | blocksize = SOLOS_BLOCK; | ||
277 | } | ||
278 | |||
279 | /*Calculate block size*/ | ||
280 | if ((fw->size - flash_offset) > blocksize) { | ||
281 | block = blocksize; | ||
282 | } else { | ||
283 | block = fw->size - flash_offset; | ||
284 | } | ||
285 | block_num = flash_offset / blocksize; | ||
286 | //dev_info(&card->dev->dev, "block %d/%d\n",block_num + 1,(fw->size/512/8)); | ||
287 | |||
288 | /*Copy block into RAM*/ | ||
289 | for(i=0;i<block;i++){ | ||
290 | if(i%4 == 0){ | ||
291 | //dev_info(&card->dev->dev, "i: %d\n", i); | ||
292 | data32=0x00000000; | ||
293 | } | ||
294 | |||
295 | switch(i%4){ | ||
296 | case 0: | ||
297 | data32 |= 0x0000FF00 & | ||
298 | (*(fw->data + i + flash_offset) << 8); | ||
299 | break; | ||
300 | case 1: | ||
301 | data32 |= 0x000000FF & *(fw->data + i + flash_offset); | ||
302 | break; | ||
303 | case 2: | ||
304 | data32 |= 0xFF000000 & | ||
305 | (*(fw->data + i + flash_offset) << 24); | ||
306 | break; | ||
307 | case 3: | ||
308 | data32 |= 0x00FF0000 & | ||
309 | (*(fw->data + i + flash_offset) << 16); | ||
310 | break; | ||
311 | } | ||
312 | |||
313 | if (i%4 == 3) { | ||
314 | iowrite32(data32, RX_BUF(card, 3) + i - 3); | ||
315 | } | ||
316 | } | ||
317 | i--; | ||
318 | if (i%4 != 3) { | ||
319 | iowrite32(data32, RX_BUF(card, 3) + i - (i%4)); | ||
320 | } | ||
321 | |||
322 | /*Specify block number and then trigger flash write*/ | ||
323 | iowrite32(block_num, card->config_regs + FLASH_BLOCK); | ||
324 | iowrite32(1, card->config_regs + WRITE_FLASH); | ||
325 | // iowrite32(0, card->config_regs + WRITE_FLASH); | ||
326 | flash_offset += block; | ||
327 | return; | ||
328 | } | ||
329 | |||
183 | static irqreturn_t solos_irq(int irq, void *dev_id) | 330 | static irqreturn_t solos_irq(int irq, void *dev_id) |
184 | { | 331 | { |
185 | struct solos_card *card = dev_id; | 332 | struct solos_card *card = dev_id; |
@@ -207,6 +354,17 @@ void solos_bh(unsigned long card_arg) | |||
207 | uint32_t card_flags; | 354 | uint32_t card_flags; |
208 | uint32_t tx_mask; | 355 | uint32_t tx_mask; |
209 | uint32_t rx_done = 0; | 356 | uint32_t rx_done = 0; |
357 | uint32_t data32; | ||
358 | |||
359 | data32 = ioread32(card->config_regs + FPGA_MODE); | ||
360 | if (data32 != 0) { | ||
361 | data32 = ioread32(card->config_regs + FLASH_BUSY); | ||
362 | if (data32 == 0) { | ||
363 | flash_write(card); | ||
364 | } | ||
365 | return; | ||
366 | } | ||
367 | |||
210 | 368 | ||
211 | card_flags = ioread32(card->config_regs + FLAGS_ADDR); | 369 | card_flags = ioread32(card->config_regs + FLAGS_ADDR); |
212 | 370 | ||
@@ -680,6 +838,15 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
680 | // Enable IRQs | 838 | // Enable IRQs |
681 | iowrite32(1, card->config_regs + IRQ_EN_ADDR); | 839 | iowrite32(1, card->config_regs + IRQ_EN_ADDR); |
682 | 840 | ||
841 | if(firmware_upgrade != 0){ | ||
842 | card->flash_chip = 1; | ||
843 | flash_upgrade(card); | ||
844 | } else { | ||
845 | if(fpga_upgrade != 0){ | ||
846 | card->flash_chip = 0; | ||
847 | flash_upgrade(card); | ||
848 | } | ||
849 | } | ||
683 | return 0; | 850 | return 0; |
684 | 851 | ||
685 | out_unmap_both: | 852 | out_unmap_both: |