1 /*---------------------------------------------------------------------------
2 FT1000 driver for Flarion Flash OFDM NIC Device
4 Copyright (C) 2002 Flarion Technologies, All rights reserved.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option) any
9 later version. This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 more details. You should have received a copy of the GNU General Public
13 License along with this program; if not, write to the
14 Free Software Foundation, Inc., 59 Temple Place -
15 Suite 330, Boston, MA 02111-1307, USA.
16 --------------------------------------------------------------------------
18 Description: This module will handshake with the DSP bootloader to
19 download the DSP runtime image.
21 ---------------------------------------------------------------------------*/
23 #define __KERNEL_SYSCALLS__
25 #include <linux/module.h>
28 #include <linux/slab.h>
29 #include <linux/unistd.h>
30 #include <linux/netdevice.h>
31 #include <linux/timer.h>
32 #include <linux/delay.h>
34 #include <asm/uaccess.h>
35 #include <linux/vmalloc.h>
41 #define DEBUG(n, args...) printk(KERN_DEBUG args);
43 #define DEBUG(n, args...)
46 #define MAX_DSP_WAIT_LOOPS 100
47 #define DSP_WAIT_SLEEP_TIME 1 /* 1 millisecond */
49 #define MAX_LENGTH 0x7f0
51 #define DWNLD_MAG_HANDSHAKE_LOC 0x00
52 #define DWNLD_MAG_TYPE_LOC 0x01
53 #define DWNLD_MAG_SIZE_LOC 0x02
54 #define DWNLD_MAG_PS_HDR_LOC 0x03
56 #define DWNLD_HANDSHAKE_LOC 0x02
57 #define DWNLD_TYPE_LOC 0x04
58 #define DWNLD_SIZE_MSW_LOC 0x06
59 #define DWNLD_SIZE_LSW_LOC 0x08
60 #define DWNLD_PS_HDR_LOC 0x0A
62 #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
63 #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
64 #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
65 #define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
66 #define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
68 #define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
69 #define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
71 #define REQUEST_CODE_LENGTH 0x0000
72 #define REQUEST_RUN_ADDRESS 0x0001
73 #define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
74 #define REQUEST_DONE_BL 0x0003
75 #define REQUEST_DONE_CL 0x0004
76 #define REQUEST_VERSION_INFO 0x0005
77 #define REQUEST_CODE_BY_VERSION 0x0006
78 #define REQUEST_MAILBOX_DATA 0x0007
79 #define REQUEST_FILE_CHECKSUM 0x0008
81 #define STATE_START_DWNLD 0x01
82 #define STATE_BOOT_DWNLD 0x02
83 #define STATE_CODE_DWNLD 0x03
84 #define STATE_DONE_DWNLD 0x04
85 #define STATE_SECTION_PROV 0x05
86 #define STATE_DONE_PROV 0x06
87 #define STATE_DONE_FILE 0x07
89 u16 get_handshake(struct net_device *dev, u16 expected_value);
90 void put_handshake(struct net_device *dev, u16 handshake_value);
91 u16 get_request_type(struct net_device *dev);
92 long get_request_value(struct net_device *dev);
93 void put_request_value(struct net_device *dev, long lvalue);
94 u16 hdr_checksum(struct pseudo_hdr *pHdr);
97 u32 version_id; /* Version ID of this image format. */
98 u32 package_id; /* Package ID of code release. */
99 u32 build_date; /* Date/time stamp when file was built. */
100 u32 commands_offset; /* Offset to attached commands in Pseudo Hdr format. */
101 u32 loader_offset; /* Offset to bootloader code. */
102 u32 loader_code_address; /* Start address of bootloader. */
103 u32 loader_code_end; /* Where bootloader code ends. */
104 u32 loader_code_size;
105 u32 version_data_offset; /* Offset were scrambled version data begins. */
106 u32 version_data_size; /* Size, in words, of scrambled version data. */
107 u32 nDspImages; /* Number of DSP images in file. */
108 } __attribute__ ((packed));
110 struct dsp_image_info {
111 u32 coff_date; /* Date/time when DSP Coff image was built. */
112 u32 begin_offset; /* Offset in file where image begins. */
113 u32 end_offset; /* Offset in file where image begins. */
114 u32 run_address; /* On chip Start address of DSP code. */
115 u32 image_size; /* Size of image. */
116 u32 version; /* Embedded version # of DSP code. */
117 unsigned short checksum; /* Dsp File checksum */
119 } __attribute__ ((packed));
121 void card_bootload(struct net_device *dev)
123 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
130 DEBUG(0, "card_bootload is called\n");
132 pdata = (u32 *) bootimage;
133 size = sizeof(bootimage);
135 /* check for odd word */
139 /* Provide mutual exclusive access while reading ASIC registers. */
140 spin_lock_irqsave(&info->dpram_lock, flags);
142 /* need to set i/o base address initially and hardware will autoincrement */
143 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
145 for (i = 0; i < (size >> 2); i++) {
147 outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
150 spin_unlock_irqrestore(&info->dpram_lock, flags);
153 u16 get_handshake(struct net_device *dev, u16 expected_value)
155 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
161 while (loopcnt < MAX_DSP_WAIT_LOOPS) {
162 if (info->AsicID == ELECTRABUZZ_ID) {
163 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
164 DWNLD_HANDSHAKE_LOC);
166 handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
169 ntohl(ft1000_read_dpram_mag_32
170 (dev, DWNLD_MAG_HANDSHAKE_LOC));
171 handshake = (u16) tempx;
174 if ((handshake == expected_value)
175 || (handshake == HANDSHAKE_RESET_VALUE)) {
179 mdelay(DSP_WAIT_SLEEP_TIME);
184 return HANDSHAKE_TIMEOUT_VALUE;
188 void put_handshake(struct net_device *dev, u16 handshake_value)
190 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
193 if (info->AsicID == ELECTRABUZZ_ID) {
194 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
195 DWNLD_HANDSHAKE_LOC);
196 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value); /* Handshake */
198 tempx = (u32) handshake_value;
199 tempx = ntohl(tempx);
200 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */
204 u16 get_request_type(struct net_device *dev)
206 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
210 if (info->AsicID == ELECTRABUZZ_ID) {
211 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
212 request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
214 tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
215 tempx = ntohl(tempx);
216 request_type = (u16) tempx;
223 long get_request_value(struct net_device *dev)
225 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
229 if (info->AsicID == ELECTRABUZZ_ID) {
230 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
233 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
235 value = (long)(w_val << 16);
237 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
240 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
242 value = (long)(value | w_val);
244 value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
245 value = ntohl(value);
252 void put_request_value(struct net_device *dev, long lvalue)
254 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
258 if (info->AsicID == ELECTRABUZZ_ID) {
259 size = (u16) (lvalue >> 16);
261 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
264 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
266 size = (u16) (lvalue);
268 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
271 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
273 tempx = ntohl(lvalue);
274 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx); /* Handshake */
279 u16 hdr_checksum(struct pseudo_hdr *pHdr)
281 u16 *usPtr = (u16 *) pHdr;
284 chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
285 usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
290 int card_download(struct net_device *dev, const u8 *pFileStart,
293 struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
294 int Status = SUCCESS;
297 struct pseudo_hdr *pHdr;
302 struct prov_record *pprov_record;
304 struct dsp_file_hdr *pFileHdr5;
305 struct dsp_image_info *pDspImageInfoV6 = NULL;
306 long requested_version;
307 bool bGoodVersion = false;
308 struct drv_msg *pMailBoxData;
316 long loader_code_address = 0;
317 long loader_code_size = 0;
318 long run_address = 0;
321 unsigned long templong;
322 unsigned long image_chksum = 0;
324 file_version = *(long *)pFileStart;
325 if (file_version != 6) {
326 printk(KERN_ERR "ft1000: unsupported firmware version %ld\n", file_version);
330 uiState = STATE_START_DWNLD;
332 pFileHdr5 = (struct dsp_file_hdr *) pFileStart;
334 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->loader_offset);
335 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->loader_offset);
336 pBootEnd = (u8 *) ((long)pFileStart + pFileHdr5->loader_code_end);
337 loader_code_address = pFileHdr5->loader_code_address;
338 loader_code_size = pFileHdr5->loader_code_size;
339 bGoodVersion = false;
341 while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
344 case STATE_START_DWNLD:
346 handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
348 if (handshake == HANDSHAKE_DSP_BL_READY)
349 put_handshake(dev, HANDSHAKE_DRIVER_READY);
353 uiState = STATE_BOOT_DWNLD;
357 case STATE_BOOT_DWNLD:
358 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
359 if (handshake == HANDSHAKE_REQUEST) {
361 * Get type associated with the request.
363 request = get_request_type(dev);
365 case REQUEST_RUN_ADDRESS:
366 put_request_value(dev,
367 loader_code_address);
369 case REQUEST_CODE_LENGTH:
370 put_request_value(dev,
373 case REQUEST_DONE_BL:
374 /* Reposition ptrs to beginning of code section */
375 pUsFile = (u16 *) ((long)pBootEnd);
376 pUcFile = (u8 *) ((long)pBootEnd);
377 uiState = STATE_CODE_DWNLD;
379 case REQUEST_CODE_SEGMENT:
380 word_length = get_request_value(dev);
381 if (word_length > MAX_LENGTH) {
385 if ((word_length * 2 + (long)pUcFile) >
388 * Error, beyond boot code range.
393 /* Provide mutual exclusive access while reading ASIC registers. */
394 spin_lock_irqsave(&info->dpram_lock,
397 * Position ASIC DPRAM auto-increment pointer.
399 outw(DWNLD_MAG_PS_HDR_LOC,
401 FT1000_REG_DPRAM_ADDR);
402 if (word_length & 0x01)
404 word_length = word_length / 2;
406 for (; word_length > 0; word_length--) { /* In words */
407 templong = *pUsFile++;
413 FT1000_REG_MAG_DPDATAL);
415 spin_unlock_irqrestore(&info->
423 put_handshake(dev, HANDSHAKE_RESPONSE);
430 case STATE_CODE_DWNLD:
431 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
432 if (handshake == HANDSHAKE_REQUEST) {
434 * Get type associated with the request.
436 request = get_request_type(dev);
438 case REQUEST_FILE_CHECKSUM:
440 "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
441 put_request_value(dev, image_chksum);
443 case REQUEST_RUN_ADDRESS:
445 put_request_value(dev,
452 case REQUEST_CODE_LENGTH:
454 put_request_value(dev,
461 case REQUEST_DONE_CL:
462 /* Reposition ptrs to beginning of provisioning section */
463 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->commands_offset);
464 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->commands_offset);
465 uiState = STATE_DONE_DWNLD;
467 case REQUEST_CODE_SEGMENT:
472 word_length = get_request_value(dev);
473 if (word_length > MAX_LENGTH) {
477 if ((word_length * 2 + (long)pUcFile) >
480 * Error, beyond boot code range.
486 * Position ASIC DPRAM auto-increment pointer.
488 outw(DWNLD_MAG_PS_HDR_LOC,
490 FT1000_REG_DPRAM_ADDR);
491 if (word_length & 0x01)
493 word_length = word_length / 2;
495 for (; word_length > 0; word_length--) { /* In words */
496 templong = *pUsFile++;
502 FT1000_REG_MAG_DPDATAL);
506 case REQUEST_MAILBOX_DATA:
507 /* Convert length from byte count to word count. Make sure we round up. */
509 (long)(info->DSPInfoBlklen + 1) / 2;
510 put_request_value(dev, word_length);
512 (struct drv_msg *) &info->DSPInfoBlk[0];
514 (u16 *) &pMailBoxData->data[0];
515 /* Provide mutual exclusive access while reading ASIC registers. */
516 spin_lock_irqsave(&info->dpram_lock,
518 if (file_version == 5) {
520 * Position ASIC DPRAM auto-increment pointer.
522 ft1000_write_reg(dev,
523 FT1000_REG_DPRAM_ADDR,
526 for (; word_length > 0; word_length--) { /* In words */
527 temp = ntohs(*pUsData);
528 ft1000_write_reg(dev,
529 FT1000_REG_DPRAM_DATA,
535 * Position ASIC DPRAM auto-increment pointer.
537 outw(DWNLD_MAG_PS_HDR_LOC,
539 FT1000_REG_DPRAM_ADDR);
540 if (word_length & 0x01)
543 word_length = word_length / 2;
545 for (; word_length > 0; word_length--) { /* In words */
546 templong = *pUsData++;
551 FT1000_REG_MAG_DPDATAL);
554 spin_unlock_irqrestore(&info->
559 case REQUEST_VERSION_INFO:
561 pFileHdr5->version_data_size;
562 put_request_value(dev, word_length);
564 (u16 *) ((long)pFileStart +
566 version_data_offset);
567 /* Provide mutual exclusive access while reading ASIC registers. */
568 spin_lock_irqsave(&info->dpram_lock,
571 * Position ASIC DPRAM auto-increment pointer.
573 outw(DWNLD_MAG_PS_HDR_LOC,
575 FT1000_REG_DPRAM_ADDR);
576 if (word_length & 0x01)
578 word_length = word_length / 2;
580 for (; word_length > 0; word_length--) { /* In words */
589 FT1000_REG_MAG_DPDATAL);
591 spin_unlock_irqrestore(&info->
596 case REQUEST_CODE_BY_VERSION:
597 bGoodVersion = false;
599 get_request_value(dev);
601 (struct dsp_image_info *) ((long)
605 (struct dsp_file_hdr));
608 pFileHdr5->nDspImages;
655 "ft1000_dnld: image_chksum = 0x%8x\n",
665 * Error, beyond boot code range.
676 put_handshake(dev, HANDSHAKE_RESPONSE);
683 case STATE_DONE_DWNLD:
684 if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >=
685 (unsigned long) FileLength) {
686 uiState = STATE_DONE_FILE;
690 pHdr = (struct pseudo_hdr *) pUsFile;
692 if (pHdr->portdest == 0x80 /* DspOAM */
693 && (pHdr->portsrc == 0x00 /* Driver */
694 || pHdr->portsrc == 0x10 /* FMM */)) {
695 uiState = STATE_SECTION_PROV;
698 "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
699 DEBUG(1, "\t Port Source = 0x%2.2x\n",
701 DEBUG(1, "\t Port Destination = 0x%2.2x\n",
708 case STATE_SECTION_PROV:
710 pHdr = (struct pseudo_hdr *) pUcFile;
712 if (pHdr->checksum == hdr_checksum(pHdr)) {
713 if (pHdr->portdest != 0x80 /* Dsp OAM */) {
714 uiState = STATE_DONE_PROV;
717 usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */
719 /* Get buffer for provisioning data */
721 kmalloc((usHdrLength + sizeof(struct pseudo_hdr)),
724 memcpy(pbuffer, (void *)pUcFile,
726 sizeof(struct pseudo_hdr)));
727 /* link provisioning data */
729 kmalloc(sizeof(struct prov_record),
732 pprov_record->pprov_data =
734 list_add_tail(&pprov_record->
737 /* Move to next entry if available */
739 (u8 *) ((unsigned long) pUcFile +
740 (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
741 if ((unsigned long) (pUcFile) -
742 (unsigned long) (pFileStart) >=
743 (unsigned long) FileLength) {
755 /* Checksum did not compute */
761 case STATE_DONE_PROV:
762 uiState = STATE_DONE_FILE;