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
= 0;
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
);
354 uiState
= STATE_BOOT_DWNLD
;
358 case STATE_BOOT_DWNLD
:
359 handshake
= get_handshake(dev
, HANDSHAKE_REQUEST
);
360 if (handshake
== HANDSHAKE_REQUEST
) {
362 * Get type associated with the request.
364 request
= get_request_type(dev
);
366 case REQUEST_RUN_ADDRESS
:
367 put_request_value(dev
,
368 loader_code_address
);
370 case REQUEST_CODE_LENGTH
:
371 put_request_value(dev
,
374 case REQUEST_DONE_BL
:
375 /* Reposition ptrs to beginning of code section */
376 pUsFile
= (u16
*) ((long)pBootEnd
);
377 pUcFile
= (u8
*) ((long)pBootEnd
);
378 uiState
= STATE_CODE_DWNLD
;
380 case REQUEST_CODE_SEGMENT
:
381 word_length
= get_request_value(dev
);
382 if (word_length
> MAX_LENGTH
) {
386 if ((word_length
* 2 + (long)pUcFile
) >
389 * Error, beyond boot code range.
394 // Provide mutual exclusive access while reading ASIC registers.
395 spin_lock_irqsave(&info
->dpram_lock
,
398 * Position ASIC DPRAM auto-increment pointer.
400 outw(DWNLD_MAG_PS_HDR_LOC
,
402 FT1000_REG_DPRAM_ADDR
);
403 if (word_length
& 0x01)
405 word_length
= word_length
/ 2;
407 for (; word_length
> 0; word_length
--) { /* In words */
408 templong
= *pUsFile
++;
414 FT1000_REG_MAG_DPDATAL
);
416 spin_unlock_irqrestore(&info
->
424 put_handshake(dev
, HANDSHAKE_RESPONSE
);
431 case STATE_CODE_DWNLD
:
432 handshake
= get_handshake(dev
, HANDSHAKE_REQUEST
);
433 if (handshake
== HANDSHAKE_REQUEST
) {
435 * Get type associated with the request.
437 request
= get_request_type(dev
);
439 case REQUEST_FILE_CHECKSUM
:
441 "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
442 put_request_value(dev
, image_chksum
);
444 case REQUEST_RUN_ADDRESS
:
446 put_request_value(dev
,
453 case REQUEST_CODE_LENGTH
:
455 put_request_value(dev
,
462 case REQUEST_DONE_CL
:
463 /* Reposition ptrs to beginning of provisioning section */
464 pUsFile
= (u16
*) ((long)pFileStart
+ pFileHdr5
->commands_offset
);
465 pUcFile
= (u8
*) ((long)pFileStart
+ pFileHdr5
->commands_offset
);
466 uiState
= STATE_DONE_DWNLD
;
468 case REQUEST_CODE_SEGMENT
:
473 word_length
= get_request_value(dev
);
474 if (word_length
> MAX_LENGTH
) {
478 if ((word_length
* 2 + (long)pUcFile
) >
481 * Error, beyond boot code range.
487 * Position ASIC DPRAM auto-increment pointer.
489 outw(DWNLD_MAG_PS_HDR_LOC
,
491 FT1000_REG_DPRAM_ADDR
);
492 if (word_length
& 0x01)
494 word_length
= word_length
/ 2;
496 for (; word_length
> 0; word_length
--) { /* In words */
497 templong
= *pUsFile
++;
503 FT1000_REG_MAG_DPDATAL
);
507 case REQUEST_MAILBOX_DATA
:
508 // Convert length from byte count to word count. Make sure we round up.
510 (long)(info
->DSPInfoBlklen
+ 1) / 2;
511 put_request_value(dev
, word_length
);
513 (struct drv_msg
*) & info
->DSPInfoBlk
[0];
515 (u16
*) & pMailBoxData
->data
[0];
516 // Provide mutual exclusive access while reading ASIC registers.
517 spin_lock_irqsave(&info
->dpram_lock
,
519 if (file_version
== 5) {
521 * Position ASIC DPRAM auto-increment pointer.
523 ft1000_write_reg(dev
,
524 FT1000_REG_DPRAM_ADDR
,
527 for (; word_length
> 0; word_length
--) { /* In words */
528 temp
= ntohs(*pUsData
);
529 ft1000_write_reg(dev
,
530 FT1000_REG_DPRAM_DATA
,
536 * Position ASIC DPRAM auto-increment pointer.
538 outw(DWNLD_MAG_PS_HDR_LOC
,
540 FT1000_REG_DPRAM_ADDR
);
541 if (word_length
& 0x01) {
544 word_length
= word_length
/ 2;
546 for (; word_length
> 0; word_length
--) { /* In words */
547 templong
= *pUsData
++;
552 FT1000_REG_MAG_DPDATAL
);
555 spin_unlock_irqrestore(&info
->
560 case REQUEST_VERSION_INFO
:
562 pFileHdr5
->version_data_size
;
563 put_request_value(dev
, word_length
);
565 (u16
*) ((long)pFileStart
+
567 version_data_offset
);
568 // Provide mutual exclusive access while reading ASIC registers.
569 spin_lock_irqsave(&info
->dpram_lock
,
572 * Position ASIC DPRAM auto-increment pointer.
574 outw(DWNLD_MAG_PS_HDR_LOC
,
576 FT1000_REG_DPRAM_ADDR
);
577 if (word_length
& 0x01)
579 word_length
= word_length
/ 2;
581 for (; word_length
> 0; word_length
--) { /* In words */
590 FT1000_REG_MAG_DPDATAL
);
592 spin_unlock_irqrestore(&info
->
597 case REQUEST_CODE_BY_VERSION
:
598 bGoodVersion
= false;
600 get_request_value(dev
);
602 (struct dsp_image_info
*) ((long)
606 (struct dsp_file_hdr
));
609 pFileHdr5
->nDspImages
;
656 "ft1000_dnld: image_chksum = 0x%8x\n",
666 * Error, beyond boot code range.
677 put_handshake(dev
, HANDSHAKE_RESPONSE
);
684 case STATE_DONE_DWNLD
:
685 if (((unsigned long) (pUcFile
) - (unsigned long) pFileStart
) >=
686 (unsigned long) FileLength
) {
687 uiState
= STATE_DONE_FILE
;
691 pHdr
= (struct pseudo_hdr
*) pUsFile
;
693 if (pHdr
->portdest
== 0x80 /* DspOAM */
694 && (pHdr
->portsrc
== 0x00 /* Driver */
695 || pHdr
->portsrc
== 0x10 /* FMM */ )) {
696 uiState
= STATE_SECTION_PROV
;
699 "FT1000:download:Download error: Bad Port IDs in Pseudo Record\n");
700 DEBUG(1, "\t Port Source = 0x%2.2x\n",
702 DEBUG(1, "\t Port Destination = 0x%2.2x\n",
709 case STATE_SECTION_PROV
:
711 pHdr
= (struct pseudo_hdr
*) pUcFile
;
713 if (pHdr
->checksum
== hdr_checksum(pHdr
)) {
714 if (pHdr
->portdest
!= 0x80 /* Dsp OAM */ ) {
715 uiState
= STATE_DONE_PROV
;
718 usHdrLength
= ntohs(pHdr
->length
); /* Byte length for PROV records */
720 // Get buffer for provisioning data
722 kmalloc((usHdrLength
+ sizeof(struct pseudo_hdr
)),
725 memcpy(pbuffer
, (void *)pUcFile
,
727 sizeof(struct pseudo_hdr
)));
728 // link provisioning data
730 kmalloc(sizeof(struct prov_record
),
733 pprov_record
->pprov_data
=
735 list_add_tail(&pprov_record
->
738 // Move to next entry if available
740 (u8
*) ((unsigned long) pUcFile
+
741 (unsigned long) ((usHdrLength
+ 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr
));
742 if ((unsigned long) (pUcFile
) -
743 (unsigned long) (pFileStart
) >=
744 (unsigned long) FileLength
) {
756 /* Checksum did not compute */
762 case STATE_DONE_PROV
:
763 uiState
= STATE_DONE_FILE
;