blob: 4ac92eea389651ba4a8e4a66c9a91f38e8231199 [file] [log] [blame]
Kelley Nielsen89a03d32013-10-14 14:21:30 -07001/*
2* CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved.
3*
4* This file is part of Express Card USB Driver
5*/
Marek Beliskof7c1be02010-09-22 07:56:27 +02006
7#include <linux/init.h>
8#include <linux/kernel.h>
9#include <linux/module.h>
10#include <linux/netdevice.h>
11#include <linux/etherdevice.h>
12#include <linux/usb.h>
13#include <linux/vmalloc.h>
14#include "ft1000_usb.h"
15
Marek Beliskof7c1be02010-09-22 07:56:27 +020016
17#define DWNLD_HANDSHAKE_LOC 0x02
18#define DWNLD_TYPE_LOC 0x04
19#define DWNLD_SIZE_MSW_LOC 0x06
20#define DWNLD_SIZE_LSW_LOC 0x08
21#define DWNLD_PS_HDR_LOC 0x0A
22
23#define MAX_DSP_WAIT_LOOPS 40
24#define DSP_WAIT_SLEEP_TIME 1000 /* 1 millisecond */
25#define DSP_WAIT_DISPATCH_LVL 50 /* 50 usec */
26
27#define HANDSHAKE_TIMEOUT_VALUE 0xF1F1
28#define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */
29#define HANDSHAKE_RESET_VALUE_USB 0xFE7E /* When DSP requests startover */
30#define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */
31#define HANDSHAKE_DSP_BL_READY_USB 0xFE7E /* At start DSP writes this when bootloader ready */
32#define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */
33#define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */
34
35#define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */
36#define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */
37
38#define REQUEST_CODE_LENGTH 0x0000
39#define REQUEST_RUN_ADDRESS 0x0001
40#define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */
41#define REQUEST_DONE_BL 0x0003
42#define REQUEST_DONE_CL 0x0004
43#define REQUEST_VERSION_INFO 0x0005
44#define REQUEST_CODE_BY_VERSION 0x0006
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -070045#define REQUEST_MAILBOX_DATA 0x0007
Marek Beliskof7c1be02010-09-22 07:56:27 +020046#define REQUEST_FILE_CHECKSUM 0x0008
47
48#define STATE_START_DWNLD 0x01
49#define STATE_BOOT_DWNLD 0x02
50#define STATE_CODE_DWNLD 0x03
51#define STATE_DONE_DWNLD 0x04
52#define STATE_SECTION_PROV 0x05
53#define STATE_DONE_PROV 0x06
54#define STATE_DONE_FILE 0x07
55
56#define MAX_LENGTH 0x7f0
57
58// Temporary download mechanism for Magnemite
59#define DWNLD_MAG_TYPE_LOC 0x00
60#define DWNLD_MAG_LEN_LOC 0x01
61#define DWNLD_MAG_ADDR_LOC 0x02
62#define DWNLD_MAG_CHKSUM_LOC 0x03
63#define DWNLD_MAG_VAL_LOC 0x04
64
65#define HANDSHAKE_MAG_DSP_BL_READY 0xFEFE0000 /* At start DSP writes this when bootloader ready */
66#define HANDSHAKE_MAG_DSP_ENTRY 0x01000000 /* Dsp writes this to request for entry address */
67#define HANDSHAKE_MAG_DSP_DATA 0x02000000 /* Dsp writes this to request for data block */
68#define HANDSHAKE_MAG_DSP_DONE 0x03000000 /* Dsp writes this to indicate download done */
69
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -070070#define HANDSHAKE_MAG_DRV_READY 0xFFFF0000 /* Driver writes this to indicate ready to download */
Marek Beliskof7c1be02010-09-22 07:56:27 +020071#define HANDSHAKE_MAG_DRV_DATA 0x02FECDAB /* Driver writes this to indicate data available to DSP */
72#define HANDSHAKE_MAG_DRV_ENTRY 0x01FECDAB /* Driver writes this to indicate entry point to DSP */
73
74#define HANDSHAKE_MAG_TIMEOUT_VALUE 0xF1F1
75
76
77// New Magnemite downloader
78#define DWNLD_MAG1_HANDSHAKE_LOC 0x00
79#define DWNLD_MAG1_TYPE_LOC 0x01
80#define DWNLD_MAG1_SIZE_LOC 0x02
81#define DWNLD_MAG1_PS_HDR_LOC 0x03
82
Marek Belisko13da8f02010-10-12 10:26:43 +020083struct dsp_file_hdr {
Marek Beliskof7c1be02010-09-22 07:56:27 +020084 long version_id; // Version ID of this image format.
85 long package_id; // Package ID of code release.
86 long build_date; // Date/time stamp when file was built.
87 long commands_offset; // Offset to attached commands in Pseudo Hdr format.
88 long loader_offset; // Offset to bootloader code.
89 long loader_code_address; // Start address of bootloader.
90 long loader_code_end; // Where bootloader code ends.
91 long loader_code_size;
92 long version_data_offset; // Offset were scrambled version data begins.
93 long version_data_size; // Size, in words, of scrambled version data.
94 long nDspImages; // Number of DSP images in file.
Marek Belisko13da8f02010-10-12 10:26:43 +020095};
Marek Beliskof7c1be02010-09-22 07:56:27 +020096
Marek Belisko13da8f02010-10-12 10:26:43 +020097#pragma pack(1)
98struct dsp_image_info {
Marek Beliskof7c1be02010-09-22 07:56:27 +020099 long coff_date; // Date/time when DSP Coff image was built.
100 long begin_offset; // Offset in file where image begins.
101 long end_offset; // Offset in file where image begins.
102 long run_address; // On chip Start address of DSP code.
103 long image_size; // Size of image.
104 long version; // Embedded version # of DSP code.
105 unsigned short checksum; // DSP File checksum
106 unsigned short pad1;
Marek Belisko13da8f02010-10-12 10:26:43 +0200107};
108
Marek Beliskof7c1be02010-09-22 07:56:27 +0200109
Kelley Nielsende7a0cc2013-10-12 12:16:33 -0700110/* checks if the doorbell register is cleared */
Kelley Nielsene0722412013-10-11 23:08:28 -0700111static u32 check_usb_db(struct ft1000_usb *ft1000dev)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200112{
Marek Beliskoc5d680c2011-02-03 11:07:40 +0100113 int loopcnt;
114 u16 temp;
115 u32 status;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200116
Marek Beliskoc5d680c2011-02-03 11:07:40 +0100117 loopcnt = 0;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700118
Marek Beliskoc5d680c2011-02-03 11:07:40 +0100119 while (loopcnt < 10) {
120 status = ft1000_read_register(ft1000dev, &temp,
121 FT1000_REG_DOORBELL);
122 DEBUG("check_usb_db: read FT1000_REG_DOORBELL value is %x\n",
123 temp);
124 if (temp & 0x0080) {
125 DEBUG("FT1000:Got checkusb doorbell\n");
126 status = ft1000_write_register(ft1000dev, 0x0080,
127 FT1000_REG_DOORBELL);
128 status = ft1000_write_register(ft1000dev, 0x0100,
129 FT1000_REG_DOORBELL);
130 status = ft1000_write_register(ft1000dev, 0x8000,
131 FT1000_REG_DOORBELL);
132 break;
133 } else {
134 loopcnt++;
135 msleep(10);
136 }
Marek Beliskof7c1be02010-09-22 07:56:27 +0200137
Marek Beliskoc5d680c2011-02-03 11:07:40 +0100138 }
Marek Beliskof7c1be02010-09-22 07:56:27 +0200139
Marek Beliskoc5d680c2011-02-03 11:07:40 +0100140 loopcnt = 0;
141 while (loopcnt < 20) {
142 status = ft1000_read_register(ft1000dev, &temp,
143 FT1000_REG_DOORBELL);
144 DEBUG("FT1000:check_usb_db:Doorbell = 0x%x\n", temp);
145 if (temp & 0x8000) {
146 loopcnt++;
147 msleep(10);
148 } else {
149 DEBUG("check_usb_db: door bell is cleared, return 0\n");
150 return 0;
151 }
152 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700153
Marek Beliskoc5d680c2011-02-03 11:07:40 +0100154 return HANDSHAKE_MAG_TIMEOUT_VALUE;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200155}
156
Kelley Nielsen135a9ea2013-10-13 18:52:46 -0700157/* gets the handshake and compares it with the expected value */
Ondrej Zarydedbc932012-12-02 18:51:40 +0100158static u16 get_handshake(struct ft1000_usb *ft1000dev, u16 expected_value)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200159{
Marek Beliskod7a73182011-02-03 11:07:49 +0100160 u16 handshake;
161 int loopcnt;
162 u32 status = 0;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200163
Marek Beliskod7a73182011-02-03 11:07:49 +0100164 loopcnt = 0;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700165
Marek Beliskod7a73182011-02-03 11:07:49 +0100166 while (loopcnt < 100) {
167 /* Need to clear downloader doorbell if Hartley ASIC */
168 status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_RX,
169 FT1000_REG_DOORBELL);
Ondrej Zary3aa23032012-12-02 12:30:19 +0100170 if (ft1000dev->fcodeldr) {
Marek Beliskod7a73182011-02-03 11:07:49 +0100171 DEBUG(" get_handshake: fcodeldr is %d\n",
Ondrej Zary3aa23032012-12-02 12:30:19 +0100172 ft1000dev->fcodeldr);
173 ft1000dev->fcodeldr = 0;
Marek Beliskod7a73182011-02-03 11:07:49 +0100174 status = check_usb_db(ft1000dev);
175 if (status != STATUS_SUCCESS) {
176 DEBUG("get_handshake: check_usb_db failed\n");
177 status = STATUS_FAILURE;
178 break;
179 }
180 status = ft1000_write_register(ft1000dev,
181 FT1000_DB_DNLD_RX,
182 FT1000_REG_DOORBELL);
183 }
Marek Beliskof7c1be02010-09-22 07:56:27 +0200184
Marek Beliskod7a73182011-02-03 11:07:49 +0100185 status = ft1000_read_dpram16(ft1000dev,
186 DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
187 handshake = ntohs(handshake);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200188
Marek Beliskod7a73182011-02-03 11:07:49 +0100189 if (status)
190 return HANDSHAKE_TIMEOUT_VALUE;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200191
Marek Beliskod7a73182011-02-03 11:07:49 +0100192 if ((handshake == expected_value) ||
193 (handshake == HANDSHAKE_RESET_VALUE_USB)) {
194 return handshake;
195 } else {
196 loopcnt++;
197 msleep(10);
198 }
199 }
Marek Beliskof7c1be02010-09-22 07:56:27 +0200200
Marek Beliskod7a73182011-02-03 11:07:49 +0100201 return HANDSHAKE_TIMEOUT_VALUE;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200202}
203
Kelley Nielsenfafa4dc2013-10-14 14:40:01 -0700204/* write the handshake value to the handshake location */
Ondrej Zarydedbc932012-12-02 18:51:40 +0100205static void put_handshake(struct ft1000_usb *ft1000dev,u16 handshake_value)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200206{
Marek Beliskoa8d4d192011-02-03 11:07:41 +0100207 u32 tempx;
208 u16 tempword;
209 u32 status;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200210
Marek Beliskoa8d4d192011-02-03 11:07:41 +0100211 tempx = (u32)handshake_value;
212 tempx = ntohl(tempx);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200213
Marek Beliskoa8d4d192011-02-03 11:07:41 +0100214 tempword = (u16)(tempx & 0xffff);
215 status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC,
216 tempword, 0);
217 tempword = (u16)(tempx >> 16);
218 status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC,
219 tempword, 1);
220 status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX,
221 FT1000_REG_DOORBELL);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200222}
223
Ondrej Zarydedbc932012-12-02 18:51:40 +0100224static u16 get_handshake_usb(struct ft1000_usb *ft1000dev, u16 expected_value)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200225{
Marek Belisko5865a182011-02-03 11:07:42 +0100226 u16 handshake;
227 int loopcnt;
228 u16 temp;
229 u32 status = 0;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200230
Marek Belisko5865a182011-02-03 11:07:42 +0100231 loopcnt = 0;
232 handshake = 0;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200233
Marek Belisko5865a182011-02-03 11:07:42 +0100234 while (loopcnt < 100) {
Ondrej Zary3aa23032012-12-02 12:30:19 +0100235 if (ft1000dev->usbboot == 2) {
Marek Belisko5865a182011-02-03 11:07:42 +0100236 status = ft1000_read_dpram32(ft1000dev, 0,
Ondrej Zary3aa23032012-12-02 12:30:19 +0100237 (u8 *)&(ft1000dev->tempbuf[0]), 64);
Marek Belisko5865a182011-02-03 11:07:42 +0100238 for (temp = 0; temp < 16; temp++) {
239 DEBUG("tempbuf %d = 0x%x\n", temp,
Ondrej Zary3aa23032012-12-02 12:30:19 +0100240 ft1000dev->tempbuf[temp]);
Marek Belisko5865a182011-02-03 11:07:42 +0100241 }
242 status = ft1000_read_dpram16(ft1000dev,
243 DWNLD_MAG1_HANDSHAKE_LOC,
244 (u8 *)&handshake, 1);
245 DEBUG("handshake from read_dpram16 = 0x%x\n",
246 handshake);
Ondrej Zary3aa23032012-12-02 12:30:19 +0100247 if (ft1000dev->dspalive == ft1000dev->tempbuf[6]) {
Marek Belisko5865a182011-02-03 11:07:42 +0100248 handshake = 0;
249 } else {
Ondrej Zary3aa23032012-12-02 12:30:19 +0100250 handshake = ft1000dev->tempbuf[1];
251 ft1000dev->dspalive =
252 ft1000dev->tempbuf[6];
Marek Belisko5865a182011-02-03 11:07:42 +0100253 }
254 } else {
255 status = ft1000_read_dpram16(ft1000dev,
256 DWNLD_MAG1_HANDSHAKE_LOC,
257 (u8 *)&handshake, 1);
258 }
259
260 loopcnt++;
261 msleep(10);
262 handshake = ntohs(handshake);
263 if ((handshake == expected_value) ||
264 (handshake == HANDSHAKE_RESET_VALUE_USB))
265 return handshake;
266 }
267
268 return HANDSHAKE_TIMEOUT_VALUE;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200269}
270
Ondrej Zarydedbc932012-12-02 18:51:40 +0100271static void put_handshake_usb(struct ft1000_usb *ft1000dev,u16 handshake_value)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200272{
Marek Belisko5acc5392011-02-03 11:07:43 +0100273 int i;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200274
275 for (i=0; i<1000; i++);
276}
277
Ondrej Zarydedbc932012-12-02 18:51:40 +0100278static u16 get_request_type(struct ft1000_usb *ft1000dev)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200279{
Marek Belisko9b43f372011-02-03 11:07:44 +0100280 u16 request_type;
281 u32 status;
282 u16 tempword;
283 u32 tempx;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200284
Ondrej Zary3aa23032012-12-02 12:30:19 +0100285 if (ft1000dev->bootmode == 1) {
Marek Belisko9b43f372011-02-03 11:07:44 +0100286 status = fix_ft1000_read_dpram32(ft1000dev,
287 DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
288 tempx = ntohl(tempx);
289 } else {
290 tempx = 0;
291 status = ft1000_read_dpram16(ft1000dev,
292 DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1);
293 tempx |= (tempword << 16);
294 tempx = ntohl(tempx);
295 }
296 request_type = (u16)tempx;
Marek Belisko6e2c2dc2010-10-14 11:41:00 +0200297
Marek Belisko9b43f372011-02-03 11:07:44 +0100298 return request_type;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200299}
300
Ondrej Zarydedbc932012-12-02 18:51:40 +0100301static u16 get_request_type_usb(struct ft1000_usb *ft1000dev)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200302{
Marek Beliskoc3ed5d22011-02-03 11:07:45 +0100303 u16 request_type;
304 u32 status;
305 u16 tempword;
306 u32 tempx;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200307
Ondrej Zary3aa23032012-12-02 12:30:19 +0100308 if (ft1000dev->bootmode == 1) {
Marek Beliskoc3ed5d22011-02-03 11:07:45 +0100309 status = fix_ft1000_read_dpram32(ft1000dev,
310 DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
311 tempx = ntohl(tempx);
312 } else {
Ondrej Zary3aa23032012-12-02 12:30:19 +0100313 if (ft1000dev->usbboot == 2) {
314 tempx = ft1000dev->tempbuf[2];
315 tempword = ft1000dev->tempbuf[3];
Marek Beliskoc3ed5d22011-02-03 11:07:45 +0100316 } else {
317 tempx = 0;
318 status = ft1000_read_dpram16(ft1000dev,
319 DWNLD_MAG1_TYPE_LOC,
320 (u8 *)&tempword, 1);
321 }
322 tempx |= (tempword << 16);
323 tempx = ntohl(tempx);
324 }
325 request_type = (u16)tempx;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200326
Marek Beliskoc3ed5d22011-02-03 11:07:45 +0100327 return request_type;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200328}
329
Ondrej Zarydedbc932012-12-02 18:51:40 +0100330static long get_request_value(struct ft1000_usb *ft1000dev)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200331{
Marek Belisko114a06a2011-02-03 11:07:46 +0100332 u32 value;
333 u16 tempword;
334 u32 status;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200335
Ondrej Zary3aa23032012-12-02 12:30:19 +0100336 if (ft1000dev->bootmode == 1) {
Marek Belisko114a06a2011-02-03 11:07:46 +0100337 status = fix_ft1000_read_dpram32(ft1000dev,
338 DWNLD_MAG1_SIZE_LOC, (u8 *)&value);
339 value = ntohl(value);
340 } else {
341 status = ft1000_read_dpram16(ft1000dev,
342 DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0);
343 value = tempword;
344 status = ft1000_read_dpram16(ft1000dev,
345 DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1);
346 value |= (tempword << 16);
347 value = ntohl(value);
348 }
Marek Beliskof7c1be02010-09-22 07:56:27 +0200349
Marek Belisko114a06a2011-02-03 11:07:46 +0100350 return value;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200351}
352
Marek Beliskof7c1be02010-09-22 07:56:27 +0200353
Kelley Nielsen9e80d032013-10-15 14:05:09 -0700354/* writes a value to DWNLD_MAG1_SIZE_LOC */
Ondrej Zarydedbc932012-12-02 18:51:40 +0100355static void put_request_value(struct ft1000_usb *ft1000dev, long lvalue)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200356{
Marek Beliskocc4f65b2011-02-03 11:07:47 +0100357 u32 tempx;
358 u32 status;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200359
Marek Beliskocc4f65b2011-02-03 11:07:47 +0100360 tempx = ntohl(lvalue);
361 status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC,
362 (u8 *)&tempx);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200363}
364
365
366
Kelley Nielsenb30f4e22013-10-15 14:05:41 -0700367/* returns the checksum of the pseudo header */
Marek Beliskofc549a02010-11-03 11:19:50 +0100368static u16 hdr_checksum(struct pseudo_hdr *pHdr)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200369{
Marek Belisko78395f62011-02-03 11:07:48 +0100370 u16 *usPtr = (u16 *)pHdr;
371 u16 chksum;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200372
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700373
Marek Belisko78395f62011-02-03 11:07:48 +0100374 chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
375 usPtr[4]) ^ usPtr[5]) ^ usPtr[6]);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200376
Marek Belisko78395f62011-02-03 11:07:48 +0100377 return chksum;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200378}
379
Marek Beliskoe7af0782011-02-03 11:07:53 +0100380static int check_buffers(u16 *buff_w, u16 *buff_r, int len, int offset)
381{
382 int i;
383
384 for (i = 0; i < len; i++) {
385 if (buff_w[i] != buff_r[i + offset])
386 return -1;
387 }
388
389 return 0;
390}
Marek Beliskof7c1be02010-09-22 07:56:27 +0200391
Kelley Nielsen69f7be12013-10-15 14:06:12 -0700392/* writes a block of DSP image to DPRAM
393 * Parameters: struct ft1000_usb - device structure
394 * u16 **pUsFile - DSP image file pointer in u16
395 * u8 **pUcFile - DSP image file pointer in u8
396 * long word_length - length of the buffer to be written to DPRAM
397 */
Ondrej Zarydedbc932012-12-02 18:51:40 +0100398static u32 write_blk (struct ft1000_usb *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200399{
Marek Belisko84b78012010-11-03 11:19:52 +0100400 u32 Status = STATUS_SUCCESS;
Marek Beliskofc549a02010-11-03 11:19:50 +0100401 u16 dpram;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200402 int loopcnt, i, j;
Marek Beliskofc549a02010-11-03 11:19:50 +0100403 u16 tempword;
404 u16 tempbuffer[64];
405 u16 resultbuffer[64];
Marek Beliskof7c1be02010-09-22 07:56:27 +0200406
407 //DEBUG("FT1000:download:start word_length = %d\n",(int)word_length);
Marek Beliskofc549a02010-11-03 11:19:50 +0100408 dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200409 tempword = *(*pUsFile);
410 (*pUsFile)++;
411 Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0);
412 tempword = *(*pUsFile);
413 (*pUsFile)++;
414 Status = ft1000_write_dpram16(ft1000dev, dpram++, tempword, 1);
415
416 *pUcFile = *pUcFile + 4;
417 word_length--;
Marek Beliskofc549a02010-11-03 11:19:50 +0100418 tempword = (u16)word_length;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200419 word_length = (word_length / 16) + 1;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200420 for (; word_length > 0; word_length--) /* In words */
421 {
422 loopcnt = 0;
423
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700424 for (i=0; i<32; i++)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200425 {
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700426 if (tempword != 0)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200427 {
428 tempbuffer[i++] = *(*pUsFile);
429 (*pUsFile)++;
430 tempbuffer[i] = *(*pUsFile);
431 (*pUsFile)++;
432 *pUcFile = *pUcFile + 4;
433 loopcnt++;
434 tempword--;
435 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700436 else
Marek Beliskof7c1be02010-09-22 07:56:27 +0200437 {
438 tempbuffer[i++] = 0;
439 tempbuffer[i] = 0;
440 }
441 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700442
Marek Beliskof7c1be02010-09-22 07:56:27 +0200443 //DEBUG("write_blk: loopcnt is %d\n", loopcnt);
444 //DEBUG("write_blk: bootmode = %d\n", bootmode);
445 //DEBUG("write_blk: dpram = %x\n", dpram);
Ondrej Zary3aa23032012-12-02 12:30:19 +0100446 if (ft1000dev->bootmode == 0)
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700447 {
448 if (dpram >= 0x3F4)
Marek Beliskoe2cb7da2010-11-03 11:19:47 +0100449 Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 8);
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700450 else
Marek Beliskoe2cb7da2010-11-03 11:19:47 +0100451 Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200452 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700453 else
Marek Beliskof7c1be02010-09-22 07:56:27 +0200454 {
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700455 for (j=0; j<10; j++)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200456 {
Marek Beliskoe2cb7da2010-11-03 11:19:47 +0100457 Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700458 if (Status == STATUS_SUCCESS)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200459 {
460 // Work around for ASIC bit stuffing problem.
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700461 if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200462 {
Marek Beliskoe2cb7da2010-11-03 11:19:47 +0100463 Status = ft1000_write_dpram32(ft1000dev, dpram+12, (u8 *)&tempbuffer[24], 64);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200464 }
465 // Let's check the data written
Marek Beliskoe2cb7da2010-11-03 11:19:47 +0100466 Status = ft1000_read_dpram32 (ft1000dev, dpram, (u8 *)&resultbuffer[0], 64);
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700467 if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200468 {
Marek Beliskoe7af0782011-02-03 11:07:53 +0100469 if (check_buffers(tempbuffer, resultbuffer, 28, 0)) {
470 DEBUG("FT1000:download:DPRAM write failed 1 during bootloading\n");
471 msleep(10);
472 Status = STATUS_FAILURE;
473 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200474 }
Marek Beliskoe2cb7da2010-11-03 11:19:47 +0100475 Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (u8 *)&resultbuffer[0], 64);
Marek Beliskoe7af0782011-02-03 11:07:53 +0100476
477 if (check_buffers(tempbuffer, resultbuffer, 16, 24)) {
478 DEBUG("FT1000:download:DPRAM write failed 2 during bootloading\n");
479 msleep(10);
480 Status = STATUS_FAILURE;
481 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200482 }
Marek Beliskoe7af0782011-02-03 11:07:53 +0100483
Marek Beliskof7c1be02010-09-22 07:56:27 +0200484 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700485 else
Marek Beliskof7c1be02010-09-22 07:56:27 +0200486 {
Marek Beliskoe7af0782011-02-03 11:07:53 +0100487 if (check_buffers(tempbuffer, resultbuffer, 32, 0)) {
488 DEBUG("FT1000:download:DPRAM write failed 3 during bootloading\n");
489 msleep(10);
490 Status = STATUS_FAILURE;
491 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200492 }
Marek Beliskoe7af0782011-02-03 11:07:53 +0100493
Marek Beliskof7c1be02010-09-22 07:56:27 +0200494 }
495
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700496 if (Status == STATUS_SUCCESS)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200497 break;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700498
Marek Beliskof7c1be02010-09-22 07:56:27 +0200499 }
500 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700501
502 if (Status != STATUS_SUCCESS)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200503 {
504 DEBUG("FT1000:download:Write failed tempbuffer[31] = 0x%x\n", tempbuffer[31]);
505 break;
506 }
507
508 }
509 dpram = dpram + loopcnt;
510 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700511
Marek Beliskof7c1be02010-09-22 07:56:27 +0200512 return Status;
513}
514
515static void usb_dnld_complete (struct urb *urb)
516{
517 //DEBUG("****** usb_dnld_complete\n");
518}
519
Kelley Nielsen456ae7e2013-10-15 14:06:41 -0700520/* writes a block of DSP image to DPRAM
521 * Parameters: struct ft1000_usb - device structure
522 * u16 **pUsFile - DSP image file pointer in u16
523 * u8 **pUcFile - DSP image file pointer in u8
524 * long word_length - length of the buffer to be written to DPRAM
525 */
Ondrej Zarydedbc932012-12-02 18:51:40 +0100526static u32 write_blk_fifo(struct ft1000_usb *ft1000dev, u16 **pUsFile,
Marek Belisko857af452011-02-03 11:07:50 +0100527 u8 **pUcFile, long word_length)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200528{
Marek Belisko857af452011-02-03 11:07:50 +0100529 u32 Status = STATUS_SUCCESS;
530 int byte_length;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200531
Marek Belisko857af452011-02-03 11:07:50 +0100532 byte_length = word_length * 4;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200533
Marek Belisko857af452011-02-03 11:07:50 +0100534 if (byte_length && ((byte_length % 64) == 0))
535 byte_length += 4;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200536
Marek Belisko857af452011-02-03 11:07:50 +0100537 if (byte_length < 64)
538 byte_length = 68;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200539
Marek Belisko857af452011-02-03 11:07:50 +0100540 usb_init_urb(ft1000dev->tx_urb);
541 memcpy(ft1000dev->tx_buf, *pUcFile, byte_length);
542 usb_fill_bulk_urb(ft1000dev->tx_urb,
543 ft1000dev->dev,
544 usb_sndbulkpipe(ft1000dev->dev,
545 ft1000dev->bulk_out_endpointAddr),
546 ft1000dev->tx_buf, byte_length, usb_dnld_complete,
547 (void *)ft1000dev);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200548
Marek Belisko857af452011-02-03 11:07:50 +0100549 usb_submit_urb(ft1000dev->tx_urb, GFP_ATOMIC);
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700550
Marek Belisko857af452011-02-03 11:07:50 +0100551 *pUsFile = *pUsFile + (word_length << 1);
552 *pUcFile = *pUcFile + (word_length << 2);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200553
Marek Belisko857af452011-02-03 11:07:50 +0100554 return Status;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200555}
556
Kelley Nielseneb3836c2013-10-27 16:40:39 -0700557static int scram_start_dwnld(struct ft1000_usb *ft1000dev, u16 *hshake,
558 u32 *state)
559{
560 int status = STATUS_SUCCESS;
561
562 DEBUG("FT1000:STATE_START_DWNLD\n");
563 if (ft1000dev->usbboot)
564 *hshake = get_handshake_usb(ft1000dev, HANDSHAKE_DSP_BL_READY);
565 else
566 *hshake = get_handshake(ft1000dev, HANDSHAKE_DSP_BL_READY);
567 if (*hshake == HANDSHAKE_DSP_BL_READY) {
568 DEBUG("scram_dnldr: handshake is HANDSHAKE_DSP_BL_READY, call put_handshake(HANDSHAKE_DRIVER_READY)\n");
569 put_handshake(ft1000dev, HANDSHAKE_DRIVER_READY);
570 } else {
571 DEBUG("FT1000:download:Download error: Handshake failed\n");
572 status = STATUS_FAILURE;
573 }
574 *state = STATE_BOOT_DWNLD;
575 return status;
576}
577
Kelley Nielsen4b31e1f2013-10-15 14:07:09 -0700578/* Scramble downloader for Harley based ASIC via USB interface */
Ondrej Zarydedbc932012-12-02 18:51:40 +0100579u16 scram_dnldr(struct ft1000_usb *ft1000dev, void *pFileStart,
Marek Belisko6f953fb2011-02-03 11:07:51 +0100580 u32 FileLength)
Marek Beliskof7c1be02010-09-22 07:56:27 +0200581{
Marek Belisko6f953fb2011-02-03 11:07:51 +0100582 u16 status = STATUS_SUCCESS;
583 u32 state;
584 u16 handshake;
Marek Belisko0ce72ea2010-12-14 14:02:54 +0100585 struct pseudo_hdr *pseudo_header;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100586 u16 pseudo_header_len;
587 long word_length;
588 u16 request;
589 u16 temp;
590 u16 tempword;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200591
Marek Belisko0ce72ea2010-12-14 14:02:54 +0100592 struct dsp_file_hdr *file_hdr;
593 struct dsp_image_info *dsp_img_info = NULL;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100594 long requested_version;
595 bool correct_version;
Marek Belisko0ce72ea2010-12-14 14:02:54 +0100596 struct drv_msg *mailbox_data;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100597 u16 *data = NULL;
598 u16 *s_file = NULL;
599 u8 *c_file = NULL;
600 u8 *boot_end = NULL, *code_end = NULL;
601 int image;
602 long loader_code_address, loader_code_size = 0;
603 long run_address = 0, run_size = 0;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200604
Marek Belisko6f953fb2011-02-03 11:07:51 +0100605 u32 templong;
606 u32 image_chksum = 0;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200607
Marek Belisko6f953fb2011-02-03 11:07:51 +0100608 u16 dpram = 0;
609 u8 *pbuffer;
Marek Beliskoe27d96d2010-10-15 14:13:01 +0200610 struct prov_record *pprov_record;
Marek Belisko1a88a062010-10-16 22:37:27 +0200611 struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700612
Marek Belisko6f953fb2011-02-03 11:07:51 +0100613 DEBUG("Entered scram_dnldr...\n");
Marek Beliskof7c1be02010-09-22 07:56:27 +0200614
Ondrej Zary3aa23032012-12-02 12:30:19 +0100615 ft1000dev->fcodeldr = 0;
616 ft1000dev->usbboot = 0;
617 ft1000dev->dspalive = 0xffff;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200618
Marek Belisko6f953fb2011-02-03 11:07:51 +0100619 //
620 // Get version id of file, at first 4 bytes of file, for newer files.
621 //
Marek Beliskof7c1be02010-09-22 07:56:27 +0200622
Marek Belisko6f953fb2011-02-03 11:07:51 +0100623 state = STATE_START_DWNLD;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200624
Marek Belisko6f953fb2011-02-03 11:07:51 +0100625 file_hdr = (struct dsp_file_hdr *)pFileStart;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200626
Marek Belisko6f953fb2011-02-03 11:07:51 +0100627 ft1000_write_register(ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200628
Marek Belisko6f953fb2011-02-03 11:07:51 +0100629 s_file = (u16 *) (pFileStart + file_hdr->loader_offset);
630 c_file = (u8 *) (pFileStart + file_hdr->loader_offset);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200631
Marek Belisko6f953fb2011-02-03 11:07:51 +0100632 boot_end = (u8 *) (pFileStart + file_hdr->loader_code_end);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200633
Marek Belisko6f953fb2011-02-03 11:07:51 +0100634 loader_code_address = file_hdr->loader_code_address;
635 loader_code_size = file_hdr->loader_code_size;
Rashika Kheria36f955bf062013-10-27 19:50:45 +0530636 correct_version = false;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200637
Marek Belisko6f953fb2011-02-03 11:07:51 +0100638 while ((status == STATUS_SUCCESS) && (state != STATE_DONE_FILE)) {
639 switch (state) {
640 case STATE_START_DWNLD:
Kelley Nielseneb3836c2013-10-27 16:40:39 -0700641 status = scram_start_dwnld(ft1000dev, &handshake,
642 &state);
Marek Belisko6f953fb2011-02-03 11:07:51 +0100643 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200644
Marek Belisko6f953fb2011-02-03 11:07:51 +0100645 case STATE_BOOT_DWNLD:
646 DEBUG("FT1000:STATE_BOOT_DWNLD\n");
Ondrej Zary3aa23032012-12-02 12:30:19 +0100647 ft1000dev->bootmode = 1;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100648 handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST);
649 if (handshake == HANDSHAKE_REQUEST) {
650 /*
651 * Get type associated with the request.
652 */
653 request = get_request_type(ft1000dev);
654 switch (request) {
655 case REQUEST_RUN_ADDRESS:
656 DEBUG("FT1000:REQUEST_RUN_ADDRESS\n");
657 put_request_value(ft1000dev,
658 loader_code_address);
659 break;
660 case REQUEST_CODE_LENGTH:
661 DEBUG("FT1000:REQUEST_CODE_LENGTH\n");
662 put_request_value(ft1000dev,
663 loader_code_size);
664 break;
665 case REQUEST_DONE_BL:
666 DEBUG("FT1000:REQUEST_DONE_BL\n");
667 /* Reposition ptrs to beginning of code section */
668 s_file = (u16 *) (boot_end);
669 c_file = (u8 *) (boot_end);
670 //DEBUG("FT1000:download:s_file = 0x%8x\n", (int)s_file);
671 //DEBUG("FT1000:download:c_file = 0x%8x\n", (int)c_file);
672 state = STATE_CODE_DWNLD;
Ondrej Zary3aa23032012-12-02 12:30:19 +0100673 ft1000dev->fcodeldr = 1;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100674 break;
675 case REQUEST_CODE_SEGMENT:
676 //DEBUG("FT1000:REQUEST_CODE_SEGMENT\n");
677 word_length =
678 get_request_value(ft1000dev);
679 //DEBUG("FT1000:word_length = 0x%x\n", (int)word_length);
680 //NdisMSleep (100);
681 if (word_length > MAX_LENGTH) {
682 DEBUG
683 ("FT1000:download:Download error: Max length exceeded\n");
684 status = STATUS_FAILURE;
685 break;
686 }
687 if ((word_length * 2 + c_file) >
688 boot_end) {
689 /*
690 * Error, beyond boot code range.
691 */
692 DEBUG
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300693 ("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundary.\n",
Marek Belisko6f953fb2011-02-03 11:07:51 +0100694 (int)word_length);
695 status = STATUS_FAILURE;
696 break;
697 }
698 /*
699 * Position ASIC DPRAM auto-increment pointer.
700 */
701 dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200702 if (word_length & 0x1)
703 word_length++;
704 word_length = word_length / 2;
705
Marek Belisko6f953fb2011-02-03 11:07:51 +0100706 status =
707 write_blk(ft1000dev, &s_file,
708 &c_file, word_length);
709 //DEBUG("write_blk returned %d\n", status);
710 break;
711 default:
712 DEBUG
713 ("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n",
714 request);
715 status = STATUS_FAILURE;
716 break;
717 }
Ondrej Zary3aa23032012-12-02 12:30:19 +0100718 if (ft1000dev->usbboot)
Marek Belisko6f953fb2011-02-03 11:07:51 +0100719 put_handshake_usb(ft1000dev,
720 HANDSHAKE_RESPONSE);
721 else
722 put_handshake(ft1000dev,
723 HANDSHAKE_RESPONSE);
724 } else {
725 DEBUG
726 ("FT1000:download:Download error: Handshake failed\n");
727 status = STATUS_FAILURE;
728 }
Marek Beliskof7c1be02010-09-22 07:56:27 +0200729
Marek Belisko6f953fb2011-02-03 11:07:51 +0100730 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200731
Marek Belisko6f953fb2011-02-03 11:07:51 +0100732 case STATE_CODE_DWNLD:
733 //DEBUG("FT1000:STATE_CODE_DWNLD\n");
Ondrej Zary3aa23032012-12-02 12:30:19 +0100734 ft1000dev->bootmode = 0;
735 if (ft1000dev->usbboot)
Marek Belisko6f953fb2011-02-03 11:07:51 +0100736 handshake =
737 get_handshake_usb(ft1000dev,
738 HANDSHAKE_REQUEST);
739 else
740 handshake =
741 get_handshake(ft1000dev, HANDSHAKE_REQUEST);
742 if (handshake == HANDSHAKE_REQUEST) {
743 /*
744 * Get type associated with the request.
745 */
Ondrej Zary3aa23032012-12-02 12:30:19 +0100746 if (ft1000dev->usbboot)
Marek Belisko6f953fb2011-02-03 11:07:51 +0100747 request =
748 get_request_type_usb(ft1000dev);
749 else
750 request = get_request_type(ft1000dev);
751 switch (request) {
752 case REQUEST_FILE_CHECKSUM:
753 DEBUG
754 ("FT1000:download:image_chksum = 0x%8x\n",
755 image_chksum);
756 put_request_value(ft1000dev,
757 image_chksum);
758 break;
759 case REQUEST_RUN_ADDRESS:
760 DEBUG
761 ("FT1000:download: REQUEST_RUN_ADDRESS\n");
762 if (correct_version) {
763 DEBUG
764 ("FT1000:download:run_address = 0x%8x\n",
765 (int)run_address);
766 put_request_value(ft1000dev,
767 run_address);
768 } else {
769 DEBUG
770 ("FT1000:download:Download error: Got Run address request before image offset request.\n");
771 status = STATUS_FAILURE;
772 break;
773 }
774 break;
775 case REQUEST_CODE_LENGTH:
776 DEBUG
777 ("FT1000:download:REQUEST_CODE_LENGTH\n");
778 if (correct_version) {
779 DEBUG
780 ("FT1000:download:run_size = 0x%8x\n",
781 (int)run_size);
782 put_request_value(ft1000dev,
783 run_size);
784 } else {
785 DEBUG
786 ("FT1000:download:Download error: Got Size request before image offset request.\n");
787 status = STATUS_FAILURE;
788 break;
789 }
790 break;
791 case REQUEST_DONE_CL:
Ondrej Zary3aa23032012-12-02 12:30:19 +0100792 ft1000dev->usbboot = 3;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100793 /* Reposition ptrs to beginning of provisioning section */
794 s_file =
795 (u16 *) (pFileStart +
796 file_hdr->commands_offset);
797 c_file =
798 (u8 *) (pFileStart +
799 file_hdr->commands_offset);
800 state = STATE_DONE_DWNLD;
801 break;
802 case REQUEST_CODE_SEGMENT:
803 //DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n");
804 if (!correct_version) {
805 DEBUG
806 ("FT1000:download:Download error: Got Code Segment request before image offset request.\n");
807 status = STATUS_FAILURE;
808 break;
809 }
Marek Belisko165d2902011-02-03 11:07:39 +0100810
Marek Belisko6f953fb2011-02-03 11:07:51 +0100811 word_length =
812 get_request_value(ft1000dev);
813 //DEBUG("FT1000:download:word_length = %d\n", (int)word_length);
814 if (word_length > MAX_LENGTH) {
815 DEBUG
816 ("FT1000:download:Download error: Max length exceeded\n");
817 status = STATUS_FAILURE;
818 break;
819 }
820 if ((word_length * 2 + c_file) >
821 code_end) {
822 /*
823 * Error, beyond boot code range.
824 */
825 DEBUG
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300826 ("FT1000:download:Download error: Requested len=%d exceeds DSP code boundary.\n",
Marek Belisko6f953fb2011-02-03 11:07:51 +0100827 (int)word_length);
828 status = STATUS_FAILURE;
829 break;
830 }
831 /*
832 * Position ASIC DPRAM auto-increment pointer.
833 */
834 dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
835 if (word_length & 0x1)
836 word_length++;
837 word_length = word_length / 2;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200838
Marek Belisko6f953fb2011-02-03 11:07:51 +0100839 write_blk_fifo(ft1000dev, &s_file,
840 &c_file, word_length);
Ondrej Zary3aa23032012-12-02 12:30:19 +0100841 if (ft1000dev->usbboot == 0)
842 ft1000dev->usbboot++;
843 if (ft1000dev->usbboot == 1) {
Marek Belisko6f953fb2011-02-03 11:07:51 +0100844 tempword = 0;
845 ft1000_write_dpram16(ft1000dev,
846 DWNLD_MAG1_PS_HDR_LOC,
847 tempword,
848 0);
849 }
Marek Belisko6e2c2dc2010-10-14 11:41:00 +0200850
Marek Belisko6f953fb2011-02-03 11:07:51 +0100851 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200852
Marek Belisko6f953fb2011-02-03 11:07:51 +0100853 case REQUEST_MAILBOX_DATA:
854 DEBUG
855 ("FT1000:download: REQUEST_MAILBOX_DATA\n");
856 // Convert length from byte count to word count. Make sure we round up.
857 word_length =
858 (long)(pft1000info->DSPInfoBlklen +
859 1) / 2;
860 put_request_value(ft1000dev,
861 word_length);
862 mailbox_data =
863 (struct drv_msg *)&(pft1000info->
864 DSPInfoBlk[0]);
865 /*
866 * Position ASIC DPRAM auto-increment pointer.
867 */
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700868
Marek Belisko6f953fb2011-02-03 11:07:51 +0100869 data = (u16 *) & mailbox_data->data[0];
870 dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
871 if (word_length & 0x1)
872 word_length++;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200873
Marek Belisko6f953fb2011-02-03 11:07:51 +0100874 word_length = (word_length / 2);
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700875
Marek Belisko6f953fb2011-02-03 11:07:51 +0100876 for (; word_length > 0; word_length--) { /* In words */
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700877
Marek Belisko6f953fb2011-02-03 11:07:51 +0100878 templong = *data++;
879 templong |= (*data++ << 16);
880 status =
881 fix_ft1000_write_dpram32
882 (ft1000dev, dpram++,
883 (u8 *) & templong);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200884
Marek Belisko6f953fb2011-02-03 11:07:51 +0100885 }
886 break;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700887
Marek Belisko6f953fb2011-02-03 11:07:51 +0100888 case REQUEST_VERSION_INFO:
889 DEBUG
890 ("FT1000:download:REQUEST_VERSION_INFO\n");
891 word_length =
892 file_hdr->version_data_size;
893 put_request_value(ft1000dev,
894 word_length);
895 /*
896 * Position ASIC DPRAM auto-increment pointer.
897 */
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700898
Marek Belisko6f953fb2011-02-03 11:07:51 +0100899 s_file =
900 (u16 *) (pFileStart +
901 file_hdr->
902 version_data_offset);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200903
Marek Belisko6f953fb2011-02-03 11:07:51 +0100904 dpram = (u16) DWNLD_MAG1_PS_HDR_LOC;
905 if (word_length & 0x1)
906 word_length++;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700907
Marek Belisko6f953fb2011-02-03 11:07:51 +0100908 word_length = (word_length / 2);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200909
Marek Belisko6f953fb2011-02-03 11:07:51 +0100910 for (; word_length > 0; word_length--) { /* In words */
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700911
Marek Belisko6f953fb2011-02-03 11:07:51 +0100912 templong = ntohs(*s_file++);
913 temp = ntohs(*s_file++);
914 templong |= (temp << 16);
915 status =
916 fix_ft1000_write_dpram32
917 (ft1000dev, dpram++,
Kelley Nielsen610554d2013-10-12 10:26:48 -0700918 (u8 *) &templong);
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700919
Marek Belisko6f953fb2011-02-03 11:07:51 +0100920 }
921 break;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700922
Marek Belisko6f953fb2011-02-03 11:07:51 +0100923 case REQUEST_CODE_BY_VERSION:
924 DEBUG
925 ("FT1000:download:REQUEST_CODE_BY_VERSION\n");
Rashika Kheria36f955bf062013-10-27 19:50:45 +0530926 correct_version = false;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100927 requested_version =
928 get_request_value(ft1000dev);
Marek Beliskof7c1be02010-09-22 07:56:27 +0200929
Marek Belisko6f953fb2011-02-03 11:07:51 +0100930 dsp_img_info =
931 (struct dsp_image_info *)(pFileStart
932 +
933 sizeof
934 (struct
935 dsp_file_hdr));
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700936
Marek Belisko6f953fb2011-02-03 11:07:51 +0100937 for (image = 0;
938 image < file_hdr->nDspImages;
939 image++) {
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700940
Marek Beliskodfc95392011-02-03 11:07:54 +0100941 if (dsp_img_info->version ==
942 requested_version) {
Rashika Kheria36f955bf062013-10-27 19:50:45 +0530943 correct_version = true;
Marek Belisko6f953fb2011-02-03 11:07:51 +0100944 DEBUG
945 ("FT1000:download: correct_version is TRUE\n");
946 s_file =
947 (u16 *) (pFileStart
948 +
949 dsp_img_info->
950 begin_offset);
951 c_file =
952 (u8 *) (pFileStart +
953 dsp_img_info->
954 begin_offset);
955 code_end =
956 (u8 *) (pFileStart +
957 dsp_img_info->
958 end_offset);
959 run_address =
960 dsp_img_info->
961 run_address;
962 run_size =
963 dsp_img_info->
964 image_size;
965 image_chksum =
966 (u32) dsp_img_info->
967 checksum;
968 break;
969 }
970 dsp_img_info++;
Marek Beliskof7c1be02010-09-22 07:56:27 +0200971
Marek Belisko6f953fb2011-02-03 11:07:51 +0100972 } //end of for
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700973
Marek Belisko6f953fb2011-02-03 11:07:51 +0100974 if (!correct_version) {
975 /*
976 * Error, beyond boot code range.
977 */
978 DEBUG
979 ("FT1000:download:Download error: Bad Version Request = 0x%x.\n",
980 (int)requested_version);
981 status = STATUS_FAILURE;
982 break;
983 }
984 break;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -0700985
Marek Belisko6f953fb2011-02-03 11:07:51 +0100986 default:
987 DEBUG
988 ("FT1000:download:Download error: Bad request type=%d in CODE download state.\n",
989 request);
990 status = STATUS_FAILURE;
991 break;
992 }
Ondrej Zary3aa23032012-12-02 12:30:19 +0100993 if (ft1000dev->usbboot)
Marek Belisko6f953fb2011-02-03 11:07:51 +0100994 put_handshake_usb(ft1000dev,
995 HANDSHAKE_RESPONSE);
996 else
997 put_handshake(ft1000dev,
998 HANDSHAKE_RESPONSE);
999 } else {
1000 DEBUG
1001 ("FT1000:download:Download error: Handshake failed\n");
1002 status = STATUS_FAILURE;
1003 }
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -07001004
Marek Belisko6f953fb2011-02-03 11:07:51 +01001005 break;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -07001006
Marek Belisko6f953fb2011-02-03 11:07:51 +01001007 case STATE_DONE_DWNLD:
1008 DEBUG("FT1000:download:Code loader is done...\n");
1009 state = STATE_SECTION_PROV;
1010 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +02001011
Marek Belisko6f953fb2011-02-03 11:07:51 +01001012 case STATE_SECTION_PROV:
1013 DEBUG("FT1000:download:STATE_SECTION_PROV\n");
1014 pseudo_header = (struct pseudo_hdr *)c_file;
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -07001015
Marek Belisko6f953fb2011-02-03 11:07:51 +01001016 if (pseudo_header->checksum ==
1017 hdr_checksum(pseudo_header)) {
1018 if (pseudo_header->portdest !=
Kelley Nielsen6f5519f2013-10-12 10:28:50 -07001019 0x80 /* Dsp OAM */) {
Marek Belisko6f953fb2011-02-03 11:07:51 +01001020 state = STATE_DONE_PROV;
1021 break;
1022 }
1023 pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */
Marek Beliskof7c1be02010-09-22 07:56:27 +02001024
Kelley Nielsen0c5e8022013-10-12 08:32:46 -07001025 /* Get buffer for provisioning data */
Marek Belisko6f953fb2011-02-03 11:07:51 +01001026 pbuffer =
1027 kmalloc((pseudo_header_len +
1028 sizeof(struct pseudo_hdr)),
1029 GFP_ATOMIC);
1030 if (pbuffer) {
1031 memcpy(pbuffer, (void *)c_file,
1032 (u32) (pseudo_header_len +
1033 sizeof(struct
1034 pseudo_hdr)));
1035 // link provisioning data
1036 pprov_record =
1037 kmalloc(sizeof(struct prov_record),
1038 GFP_ATOMIC);
1039 if (pprov_record) {
1040 pprov_record->pprov_data =
1041 pbuffer;
1042 list_add_tail(&pprov_record->
1043 list,
1044 &pft1000info->
1045 prov_list);
1046 // Move to next entry if available
1047 c_file =
1048 (u8 *) ((unsigned long)
1049 c_file +
1050 (u32) ((pseudo_header_len + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
1051 if ((unsigned long)(c_file) -
1052 (unsigned long)(pFileStart)
1053 >=
1054 (unsigned long)FileLength) {
1055 state = STATE_DONE_FILE;
1056 }
1057 } else {
1058 kfree(pbuffer);
1059 status = STATUS_FAILURE;
1060 }
1061 } else {
1062 status = STATUS_FAILURE;
1063 }
1064 } else {
1065 /* Checksum did not compute */
1066 status = STATUS_FAILURE;
1067 }
1068 DEBUG
1069 ("ft1000:download: after STATE_SECTION_PROV, state = %d, status= %d\n",
1070 state, status);
1071 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +02001072
Marek Belisko6f953fb2011-02-03 11:07:51 +01001073 case STATE_DONE_PROV:
1074 DEBUG("FT1000:download:STATE_DONE_PROV\n");
1075 state = STATE_DONE_FILE;
1076 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +02001077
Marek Belisko6f953fb2011-02-03 11:07:51 +01001078 default:
1079 status = STATUS_FAILURE;
1080 break;
1081 } /* End Switch */
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -07001082
Kelley Nielsencfd9d1f2013-10-12 08:37:53 -07001083 if (status != STATUS_SUCCESS)
Marek Belisko6f953fb2011-02-03 11:07:51 +01001084 break;
Marek Beliskof7c1be02010-09-22 07:56:27 +02001085
1086/****
1087 // Check if Card is present
Marek Belisko0ce72ea2010-12-14 14:02:54 +01001088 status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK);
1089 if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) {
Marek Beliskof7c1be02010-09-22 07:56:27 +02001090 break;
1091 }
1092
Marek Belisko0ce72ea2010-12-14 14:02:54 +01001093 status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID);
1094 if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) {
Marek Beliskof7c1be02010-09-22 07:56:27 +02001095 break;
1096 }
1097****/
1098
Marek Belisko6f953fb2011-02-03 11:07:51 +01001099 } /* End while */
Greg Kroah-Hartmanbf3146c2010-09-22 08:34:49 -07001100
Marek Belisko6f953fb2011-02-03 11:07:51 +01001101 DEBUG("Download exiting with status = 0x%8x\n", status);
1102 ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX,
1103 FT1000_REG_DOORBELL);
Marek Beliskof7c1be02010-09-22 07:56:27 +02001104
Marek Belisko6f953fb2011-02-03 11:07:51 +01001105 return status;
Marek Beliskof7c1be02010-09-22 07:56:27 +02001106}
1107