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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25 #define __KERNEL_SYSCALLS__
27 #include <linux/module.h>
30 #include <linux/slab.h>
31 #include <linux/unistd.h>
32 #include <linux/netdevice.h>
33 #include <linux/timer.h>
34 #include <linux/delay.h>
36 #include <linux/uaccess.h>
37 #include <linux/vmalloc.h>
42 #define MAX_DSP_WAIT_LOOPS 100
43 #define DSP_WAIT_SLEEP_TIME 1 /* 1 millisecond */
45 #define MAX_LENGTH 0x7f0
47 #define DWNLD_MAG_HANDSHAKE_LOC 0x00
48 #define DWNLD_MAG_TYPE_LOC 0x01
49 #define DWNLD_MAG_SIZE_LOC 0x02
50 #define DWNLD_MAG_PS_HDR_LOC 0x03
52 #define DWNLD_HANDSHAKE_LOC 0x02
53 #define DWNLD_TYPE_LOC 0x04
54 #define DWNLD_SIZE_MSW_LOC 0x06
55 #define DWNLD_SIZE_LSW_LOC 0x08
56 #define DWNLD_PS_HDR_LOC 0x0A
58 #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
59 #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
60 #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
61 #define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
62 #define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
64 #define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
65 #define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
67 #define REQUEST_CODE_LENGTH 0x0000
68 #define REQUEST_RUN_ADDRESS 0x0001
69 #define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
70 #define REQUEST_DONE_BL 0x0003
71 #define REQUEST_DONE_CL 0x0004
72 #define REQUEST_VERSION_INFO 0x0005
73 #define REQUEST_CODE_BY_VERSION 0x0006
74 #define REQUEST_MAILBOX_DATA 0x0007
75 #define REQUEST_FILE_CHECKSUM 0x0008
77 #define STATE_START_DWNLD 0x01
78 #define STATE_BOOT_DWNLD 0x02
79 #define STATE_CODE_DWNLD 0x03
80 #define STATE_DONE_DWNLD 0x04
81 #define STATE_SECTION_PROV 0x05
82 #define STATE_DONE_PROV 0x06
83 #define STATE_DONE_FILE 0x07
85 u16 get_handshake(struct net_device *dev, u16 expected_value);
86 void put_handshake(struct net_device *dev, u16 handshake_value);
87 u16 get_request_type(struct net_device *dev);
88 long get_request_value(struct net_device *dev);
89 void put_request_value(struct net_device *dev, long lvalue);
90 u16 hdr_checksum(struct pseudo_hdr *pHdr);
93 u32 version_id; /* Version ID of this image format. */
94 u32 package_id; /* Package ID of code release. */
95 u32 build_date; /* Date/time stamp when file was built. */
96 u32 commands_offset; /* Offset to attached commands in Pseudo Hdr format. */
97 u32 loader_offset; /* Offset to bootloader code. */
98 u32 loader_code_address; /* Start address of bootloader. */
99 u32 loader_code_end; /* Where bootloader code ends. */
100 u32 loader_code_size;
101 u32 version_data_offset; /* Offset were scrambled version data begins. */
102 u32 version_data_size; /* Size, in words, of scrambled version data. */
103 u32 nDspImages; /* Number of DSP images in file. */
106 struct dsp_image_info {
107 u32 coff_date; /* Date/time when DSP Coff image was built. */
108 u32 begin_offset; /* Offset in file where image begins. */
109 u32 end_offset; /* Offset in file where image begins. */
110 u32 run_address; /* On chip Start address of DSP code. */
111 u32 image_size; /* Size of image. */
112 u32 version; /* Embedded version # of DSP code. */
113 unsigned short checksum; /* Dsp File checksum */
117 void card_bootload(struct net_device *dev)
119 struct ft1000_info *info = netdev_priv(dev);
126 netdev_dbg(dev, "card_bootload is called\n");
128 pdata = (u32 *)bootimage;
129 size = sizeof(bootimage);
131 /* check for odd word */
135 /* Provide mutual exclusive access while reading ASIC registers. */
136 spin_lock_irqsave(&info->dpram_lock, flags);
138 /* need to set i/o base address initially and hardware will autoincrement */
139 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, FT1000_DPRAM_BASE);
141 for (i = 0; i < (size >> 2); i++) {
143 outl(templong, dev->base_addr + FT1000_REG_MAG_DPDATA);
146 spin_unlock_irqrestore(&info->dpram_lock, flags);
149 u16 get_handshake(struct net_device *dev, u16 expected_value)
151 struct ft1000_info *info = netdev_priv(dev);
157 while (loopcnt < MAX_DSP_WAIT_LOOPS) {
158 if (info->AsicID == ELECTRABUZZ_ID) {
159 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
160 DWNLD_HANDSHAKE_LOC);
162 handshake = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
165 ntohl(ft1000_read_dpram_mag_32
166 (dev, DWNLD_MAG_HANDSHAKE_LOC));
167 handshake = (u16)tempx;
170 if ((handshake == expected_value)
171 || (handshake == HANDSHAKE_RESET_VALUE)) {
175 mdelay(DSP_WAIT_SLEEP_TIME);
179 return HANDSHAKE_TIMEOUT_VALUE;
183 void put_handshake(struct net_device *dev, u16 handshake_value)
185 struct ft1000_info *info = netdev_priv(dev);
188 if (info->AsicID == ELECTRABUZZ_ID) {
189 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
190 DWNLD_HANDSHAKE_LOC);
191 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, handshake_value); /* Handshake */
193 tempx = (u32)handshake_value;
194 tempx = ntohl(tempx);
195 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_HANDSHAKE_LOC, tempx); /* Handshake */
199 u16 get_request_type(struct net_device *dev)
201 struct ft1000_info *info = netdev_priv(dev);
205 if (info->AsicID == ELECTRABUZZ_ID) {
206 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, DWNLD_TYPE_LOC);
207 request_type = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
209 tempx = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_TYPE_LOC);
210 tempx = ntohl(tempx);
211 request_type = (u16)tempx;
218 long get_request_value(struct net_device *dev)
220 struct ft1000_info *info = netdev_priv(dev);
224 if (info->AsicID == ELECTRABUZZ_ID) {
225 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
228 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
230 value = (long)(w_val << 16);
232 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
235 w_val = ft1000_read_reg(dev, FT1000_REG_DPRAM_DATA);
237 value = (long)(value | w_val);
239 value = ft1000_read_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC);
240 value = ntohl(value);
247 void put_request_value(struct net_device *dev, long lvalue)
249 struct ft1000_info *info = netdev_priv(dev);
253 if (info->AsicID == ELECTRABUZZ_ID) {
254 size = (u16) (lvalue >> 16);
256 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
259 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
261 size = (u16) (lvalue);
263 ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR,
266 ft1000_write_reg(dev, FT1000_REG_DPRAM_DATA, size);
268 tempx = ntohl(lvalue);
269 ft1000_write_dpram_mag_32(dev, DWNLD_MAG_SIZE_LOC, tempx); /* Handshake */
274 u16 hdr_checksum(struct pseudo_hdr *pHdr)
276 u16 *usPtr = (u16 *)pHdr;
279 chksum = (((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
280 usPtr[4]) ^ usPtr[5]) ^ usPtr[6];
285 int card_download(struct net_device *dev, const u8 *pFileStart,
288 struct ft1000_info *info = netdev_priv(dev);
289 int Status = SUCCESS;
292 struct pseudo_hdr *pHdr;
297 struct prov_record *pprov_record;
299 struct dsp_file_hdr *pFileHdr5;
300 struct dsp_image_info *pDspImageInfoV6 = NULL;
301 long requested_version;
302 bool bGoodVersion = false;
303 struct drv_msg *pMailBoxData;
311 long loader_code_address = 0;
312 long loader_code_size = 0;
313 long run_address = 0;
316 unsigned long templong;
317 unsigned long image_chksum = 0;
319 file_version = *(long *)pFileStart;
320 if (file_version != 6) {
321 pr_err("unsupported firmware version %ld\n", file_version);
325 uiState = STATE_START_DWNLD;
327 pFileHdr5 = (struct dsp_file_hdr *)pFileStart;
329 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->loader_offset);
330 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->loader_offset);
331 pBootEnd = (u8 *) ((long)pFileStart + pFileHdr5->loader_code_end);
332 loader_code_address = pFileHdr5->loader_code_address;
333 loader_code_size = pFileHdr5->loader_code_size;
334 bGoodVersion = false;
336 while ((Status == SUCCESS) && (uiState != STATE_DONE_FILE)) {
339 case STATE_START_DWNLD:
341 handshake = get_handshake(dev, HANDSHAKE_DSP_BL_READY);
343 if (handshake == HANDSHAKE_DSP_BL_READY)
344 put_handshake(dev, HANDSHAKE_DRIVER_READY);
348 uiState = STATE_BOOT_DWNLD;
352 case STATE_BOOT_DWNLD:
353 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
354 if (handshake == HANDSHAKE_REQUEST) {
356 * Get type associated with the request.
358 request = get_request_type(dev);
360 case REQUEST_RUN_ADDRESS:
361 put_request_value(dev,
362 loader_code_address);
364 case REQUEST_CODE_LENGTH:
365 put_request_value(dev,
368 case REQUEST_DONE_BL:
369 /* Reposition ptrs to beginning of code section */
370 pUsFile = (u16 *) ((long)pBootEnd);
371 pUcFile = (u8 *) ((long)pBootEnd);
372 uiState = STATE_CODE_DWNLD;
374 case REQUEST_CODE_SEGMENT:
375 word_length = get_request_value(dev);
376 if (word_length > MAX_LENGTH) {
380 if ((word_length * 2 + (long)pUcFile) >
383 * Error, beyond boot code range.
388 /* Provide mutual exclusive access while reading ASIC registers. */
389 spin_lock_irqsave(&info->dpram_lock,
392 * Position ASIC DPRAM auto-increment pointer.
394 outw(DWNLD_MAG_PS_HDR_LOC,
396 FT1000_REG_DPRAM_ADDR);
397 if (word_length & 0x01)
399 word_length = word_length / 2;
401 for (; word_length > 0; word_length--) { /* In words */
402 templong = *pUsFile++;
408 FT1000_REG_MAG_DPDATAL);
410 spin_unlock_irqrestore(&info->
418 put_handshake(dev, HANDSHAKE_RESPONSE);
425 case STATE_CODE_DWNLD:
426 handshake = get_handshake(dev, HANDSHAKE_REQUEST);
427 if (handshake == HANDSHAKE_REQUEST) {
429 * Get type associated with the request.
431 request = get_request_type(dev);
433 case REQUEST_FILE_CHECKSUM:
435 "ft1000_dnld: REQUEST_FOR_CHECKSUM\n");
436 put_request_value(dev, image_chksum);
438 case REQUEST_RUN_ADDRESS:
440 put_request_value(dev,
447 case REQUEST_CODE_LENGTH:
449 put_request_value(dev,
456 case REQUEST_DONE_CL:
457 /* Reposition ptrs to beginning of provisioning section */
458 pUsFile = (u16 *) ((long)pFileStart + pFileHdr5->commands_offset);
459 pUcFile = (u8 *) ((long)pFileStart + pFileHdr5->commands_offset);
460 uiState = STATE_DONE_DWNLD;
462 case REQUEST_CODE_SEGMENT:
467 word_length = get_request_value(dev);
468 if (word_length > MAX_LENGTH) {
472 if ((word_length * 2 + (long)pUcFile) >
475 * Error, beyond boot code range.
481 * Position ASIC DPRAM auto-increment pointer.
483 outw(DWNLD_MAG_PS_HDR_LOC,
485 FT1000_REG_DPRAM_ADDR);
486 if (word_length & 0x01)
488 word_length = word_length / 2;
490 for (; word_length > 0; word_length--) { /* In words */
491 templong = *pUsFile++;
497 FT1000_REG_MAG_DPDATAL);
501 case REQUEST_MAILBOX_DATA:
502 /* Convert length from byte count to word count. Make sure we round up. */
504 (long)(info->DSPInfoBlklen + 1) / 2;
505 put_request_value(dev, word_length);
507 (struct drv_msg *)&info->DSPInfoBlk[0];
509 (u16 *)&pMailBoxData->data[0];
510 /* Provide mutual exclusive access while reading ASIC registers. */
511 spin_lock_irqsave(&info->dpram_lock,
513 if (file_version == 5) {
515 * Position ASIC DPRAM auto-increment pointer.
517 ft1000_write_reg(dev,
518 FT1000_REG_DPRAM_ADDR,
521 for (; word_length > 0; word_length--) { /* In words */
522 temp = ntohs(*pUsData);
523 ft1000_write_reg(dev,
524 FT1000_REG_DPRAM_DATA,
530 * Position ASIC DPRAM auto-increment pointer.
532 outw(DWNLD_MAG_PS_HDR_LOC,
534 FT1000_REG_DPRAM_ADDR);
535 if (word_length & 0x01)
538 word_length = word_length / 2;
540 for (; word_length > 0; word_length--) { /* In words */
541 templong = *pUsData++;
546 FT1000_REG_MAG_DPDATAL);
549 spin_unlock_irqrestore(&info->
554 case REQUEST_VERSION_INFO:
556 pFileHdr5->version_data_size;
557 put_request_value(dev, word_length);
559 (u16 *) ((long)pFileStart +
561 version_data_offset);
562 /* Provide mutual exclusive access while reading ASIC registers. */
563 spin_lock_irqsave(&info->dpram_lock,
566 * Position ASIC DPRAM auto-increment pointer.
568 outw(DWNLD_MAG_PS_HDR_LOC,
570 FT1000_REG_DPRAM_ADDR);
571 if (word_length & 0x01)
573 word_length = word_length / 2;
575 for (; word_length > 0; word_length--) { /* In words */
584 FT1000_REG_MAG_DPDATAL);
586 spin_unlock_irqrestore(&info->
591 case REQUEST_CODE_BY_VERSION:
592 bGoodVersion = false;
594 get_request_value(dev);
596 (struct dsp_image_info *) ((long)
600 (struct dsp_file_hdr));
603 pFileHdr5->nDspImages;
650 "ft1000_dnld: image_chksum = 0x%8x\n",
660 * Error, beyond boot code range.
671 put_handshake(dev, HANDSHAKE_RESPONSE);
678 case STATE_DONE_DWNLD:
679 if (((unsigned long)(pUcFile) - (unsigned long) pFileStart) >=
680 (unsigned long)FileLength) {
681 uiState = STATE_DONE_FILE;
685 pHdr = (struct pseudo_hdr *)pUsFile;
687 if (pHdr->portdest == 0x80 /* DspOAM */
688 && (pHdr->portsrc == 0x00 /* Driver */
689 || pHdr->portsrc == 0x10 /* FMM */)) {
690 uiState = STATE_SECTION_PROV;
693 "Download error: Bad Port IDs in Pseudo Record\n");
694 netdev_dbg(dev, "\t Port Source = 0x%2.2x\n",
696 netdev_dbg(dev, "\t Port Destination = 0x%2.2x\n",
703 case STATE_SECTION_PROV:
705 pHdr = (struct pseudo_hdr *)pUcFile;
707 if (pHdr->checksum == hdr_checksum(pHdr)) {
708 if (pHdr->portdest != 0x80 /* Dsp OAM */) {
709 uiState = STATE_DONE_PROV;
712 usHdrLength = ntohs(pHdr->length); /* Byte length for PROV records */
714 /* Get buffer for provisioning data */
716 kmalloc(usHdrLength + sizeof(struct pseudo_hdr),
719 memcpy(pbuffer, pUcFile,
721 sizeof(struct pseudo_hdr)));
722 /* link provisioning data */
724 kmalloc(sizeof(struct prov_record),
727 pprov_record->pprov_data =
729 list_add_tail(&pprov_record->
732 /* Move to next entry if available */
734 (u8 *)((unsigned long) pUcFile +
735 (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
736 if ((unsigned long) (pUcFile) -
737 (unsigned long) (pFileStart) >=
738 (unsigned long)FileLength) {
750 /* Checksum did not compute */
756 case STATE_DONE_PROV:
757 uiState = STATE_DONE_FILE;