]>
Commit | Line | Data |
---|---|---|
f7c1be0c MB |
1 | //===================================================== |
2 | // CopyRight (C) 2007 Qualcomm Inc. All Rights Reserved. | |
3 | // | |
4 | // | |
5 | // This file is part of Express Card USB Driver | |
6 | // | |
7 | // $Id: | |
8 | //==================================================== | |
9 | // 20090926; aelias; removed compiler warnings; ubuntu 9.04; 2.6.28-15-generic | |
10 | ||
11 | #include <linux/init.h> | |
12 | #include <linux/kernel.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/netdevice.h> | |
15 | #include <linux/etherdevice.h> | |
16 | #include <linux/usb.h> | |
17 | #include <linux/vmalloc.h> | |
18 | #include "ft1000_usb.h" | |
19 | ||
f7c1be0c MB |
20 | |
21 | #define DWNLD_HANDSHAKE_LOC 0x02 | |
22 | #define DWNLD_TYPE_LOC 0x04 | |
23 | #define DWNLD_SIZE_MSW_LOC 0x06 | |
24 | #define DWNLD_SIZE_LSW_LOC 0x08 | |
25 | #define DWNLD_PS_HDR_LOC 0x0A | |
26 | ||
27 | #define MAX_DSP_WAIT_LOOPS 40 | |
28 | #define DSP_WAIT_SLEEP_TIME 1000 /* 1 millisecond */ | |
29 | #define DSP_WAIT_DISPATCH_LVL 50 /* 50 usec */ | |
30 | ||
31 | #define HANDSHAKE_TIMEOUT_VALUE 0xF1F1 | |
32 | #define HANDSHAKE_RESET_VALUE 0xFEFE /* When DSP requests startover */ | |
33 | #define HANDSHAKE_RESET_VALUE_USB 0xFE7E /* When DSP requests startover */ | |
34 | #define HANDSHAKE_DSP_BL_READY 0xFEFE /* At start DSP writes this when bootloader ready */ | |
35 | #define HANDSHAKE_DSP_BL_READY_USB 0xFE7E /* At start DSP writes this when bootloader ready */ | |
36 | #define HANDSHAKE_DRIVER_READY 0xFFFF /* Driver writes after receiving 0xFEFE */ | |
37 | #define HANDSHAKE_SEND_DATA 0x0000 /* DSP writes this when ready for more data */ | |
38 | ||
39 | #define HANDSHAKE_REQUEST 0x0001 /* Request from DSP */ | |
40 | #define HANDSHAKE_RESPONSE 0x0000 /* Satisfied DSP request */ | |
41 | ||
42 | #define REQUEST_CODE_LENGTH 0x0000 | |
43 | #define REQUEST_RUN_ADDRESS 0x0001 | |
44 | #define REQUEST_CODE_SEGMENT 0x0002 /* In WORD count */ | |
45 | #define REQUEST_DONE_BL 0x0003 | |
46 | #define REQUEST_DONE_CL 0x0004 | |
47 | #define REQUEST_VERSION_INFO 0x0005 | |
48 | #define REQUEST_CODE_BY_VERSION 0x0006 | |
bf3146c8 | 49 | #define REQUEST_MAILBOX_DATA 0x0007 |
f7c1be0c MB |
50 | #define REQUEST_FILE_CHECKSUM 0x0008 |
51 | ||
52 | #define STATE_START_DWNLD 0x01 | |
53 | #define STATE_BOOT_DWNLD 0x02 | |
54 | #define STATE_CODE_DWNLD 0x03 | |
55 | #define STATE_DONE_DWNLD 0x04 | |
56 | #define STATE_SECTION_PROV 0x05 | |
57 | #define STATE_DONE_PROV 0x06 | |
58 | #define STATE_DONE_FILE 0x07 | |
59 | ||
60 | #define MAX_LENGTH 0x7f0 | |
61 | ||
62 | // Temporary download mechanism for Magnemite | |
63 | #define DWNLD_MAG_TYPE_LOC 0x00 | |
64 | #define DWNLD_MAG_LEN_LOC 0x01 | |
65 | #define DWNLD_MAG_ADDR_LOC 0x02 | |
66 | #define DWNLD_MAG_CHKSUM_LOC 0x03 | |
67 | #define DWNLD_MAG_VAL_LOC 0x04 | |
68 | ||
69 | #define HANDSHAKE_MAG_DSP_BL_READY 0xFEFE0000 /* At start DSP writes this when bootloader ready */ | |
70 | #define HANDSHAKE_MAG_DSP_ENTRY 0x01000000 /* Dsp writes this to request for entry address */ | |
71 | #define HANDSHAKE_MAG_DSP_DATA 0x02000000 /* Dsp writes this to request for data block */ | |
72 | #define HANDSHAKE_MAG_DSP_DONE 0x03000000 /* Dsp writes this to indicate download done */ | |
73 | ||
bf3146c8 | 74 | #define HANDSHAKE_MAG_DRV_READY 0xFFFF0000 /* Driver writes this to indicate ready to download */ |
f7c1be0c MB |
75 | #define HANDSHAKE_MAG_DRV_DATA 0x02FECDAB /* Driver writes this to indicate data available to DSP */ |
76 | #define HANDSHAKE_MAG_DRV_ENTRY 0x01FECDAB /* Driver writes this to indicate entry point to DSP */ | |
77 | ||
78 | #define HANDSHAKE_MAG_TIMEOUT_VALUE 0xF1F1 | |
79 | ||
80 | ||
81 | // New Magnemite downloader | |
82 | #define DWNLD_MAG1_HANDSHAKE_LOC 0x00 | |
83 | #define DWNLD_MAG1_TYPE_LOC 0x01 | |
84 | #define DWNLD_MAG1_SIZE_LOC 0x02 | |
85 | #define DWNLD_MAG1_PS_HDR_LOC 0x03 | |
86 | ||
13da8f0d | 87 | struct dsp_file_hdr { |
f7c1be0c MB |
88 | long version_id; // Version ID of this image format. |
89 | long package_id; // Package ID of code release. | |
90 | long build_date; // Date/time stamp when file was built. | |
91 | long commands_offset; // Offset to attached commands in Pseudo Hdr format. | |
92 | long loader_offset; // Offset to bootloader code. | |
93 | long loader_code_address; // Start address of bootloader. | |
94 | long loader_code_end; // Where bootloader code ends. | |
95 | long loader_code_size; | |
96 | long version_data_offset; // Offset were scrambled version data begins. | |
97 | long version_data_size; // Size, in words, of scrambled version data. | |
98 | long nDspImages; // Number of DSP images in file. | |
13da8f0d | 99 | }; |
f7c1be0c | 100 | |
13da8f0d MB |
101 | #pragma pack(1) |
102 | struct dsp_image_info { | |
f7c1be0c MB |
103 | long coff_date; // Date/time when DSP Coff image was built. |
104 | long begin_offset; // Offset in file where image begins. | |
105 | long end_offset; // Offset in file where image begins. | |
106 | long run_address; // On chip Start address of DSP code. | |
107 | long image_size; // Size of image. | |
108 | long version; // Embedded version # of DSP code. | |
109 | unsigned short checksum; // DSP File checksum | |
110 | unsigned short pad1; | |
13da8f0d MB |
111 | }; |
112 | ||
f7c1be0c | 113 | |
f7c1be0c MB |
114 | //--------------------------------------------------------------------------- |
115 | // Function: check_usb_db | |
116 | // | |
117 | // Parameters: struct ft1000_device - device structure | |
bf3146c8 | 118 | // |
f7c1be0c MB |
119 | // Returns: 0 - success |
120 | // | |
121 | // Description: This function checks if the doorbell register is cleared | |
122 | // | |
123 | // Notes: | |
124 | // | |
125 | //--------------------------------------------------------------------------- | |
84b7801d | 126 | static u32 check_usb_db (struct ft1000_device *ft1000dev) |
f7c1be0c | 127 | { |
c5d680c0 MB |
128 | int loopcnt; |
129 | u16 temp; | |
130 | u32 status; | |
131 | ||
132 | loopcnt = 0; | |
133 | ||
134 | while (loopcnt < 10) { | |
135 | status = ft1000_read_register(ft1000dev, &temp, | |
136 | FT1000_REG_DOORBELL); | |
137 | DEBUG("check_usb_db: read FT1000_REG_DOORBELL value is %x\n", | |
138 | temp); | |
139 | if (temp & 0x0080) { | |
140 | DEBUG("FT1000:Got checkusb doorbell\n"); | |
141 | status = ft1000_write_register(ft1000dev, 0x0080, | |
142 | FT1000_REG_DOORBELL); | |
143 | status = ft1000_write_register(ft1000dev, 0x0100, | |
144 | FT1000_REG_DOORBELL); | |
145 | status = ft1000_write_register(ft1000dev, 0x8000, | |
146 | FT1000_REG_DOORBELL); | |
147 | break; | |
148 | } else { | |
149 | loopcnt++; | |
150 | msleep(10); | |
151 | } | |
152 | ||
153 | } | |
154 | ||
155 | loopcnt = 0; | |
156 | while (loopcnt < 20) { | |
157 | status = ft1000_read_register(ft1000dev, &temp, | |
158 | FT1000_REG_DOORBELL); | |
159 | DEBUG("FT1000:check_usb_db:Doorbell = 0x%x\n", temp); | |
160 | if (temp & 0x8000) { | |
161 | loopcnt++; | |
162 | msleep(10); | |
163 | } else { | |
164 | DEBUG("check_usb_db: door bell is cleared, return 0\n"); | |
165 | return 0; | |
166 | } | |
167 | } | |
168 | ||
169 | return HANDSHAKE_MAG_TIMEOUT_VALUE; | |
f7c1be0c MB |
170 | } |
171 | ||
172 | //--------------------------------------------------------------------------- | |
173 | // Function: get_handshake | |
174 | // | |
175 | // Parameters: struct ft1000_device - device structure | |
fc549a05 | 176 | // u16 expected_value - the handshake value expected |
bf3146c8 | 177 | // |
f7c1be0c MB |
178 | // Returns: handshakevalue - success |
179 | // HANDSHAKE_TIMEOUT_VALUE - failure | |
180 | // | |
181 | // Description: This function gets the handshake and compare with the expected value | |
182 | // | |
183 | // Notes: | |
184 | // | |
185 | //--------------------------------------------------------------------------- | |
fc549a05 | 186 | static u16 get_handshake(struct ft1000_device *ft1000dev, u16 expected_value) |
f7c1be0c | 187 | { |
d7a7318b MB |
188 | u16 handshake; |
189 | int loopcnt; | |
190 | u32 status = 0; | |
1a88a068 | 191 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
f7c1be0c | 192 | |
d7a7318b MB |
193 | loopcnt = 0; |
194 | ||
195 | while (loopcnt < 100) { | |
196 | /* Need to clear downloader doorbell if Hartley ASIC */ | |
197 | status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_RX, | |
198 | FT1000_REG_DOORBELL); | |
199 | if (pft1000info->fcodeldr) { | |
200 | DEBUG(" get_handshake: fcodeldr is %d\n", | |
201 | pft1000info->fcodeldr); | |
202 | pft1000info->fcodeldr = 0; | |
203 | status = check_usb_db(ft1000dev); | |
204 | if (status != STATUS_SUCCESS) { | |
205 | DEBUG("get_handshake: check_usb_db failed\n"); | |
206 | status = STATUS_FAILURE; | |
207 | break; | |
208 | } | |
209 | status = ft1000_write_register(ft1000dev, | |
210 | FT1000_DB_DNLD_RX, | |
211 | FT1000_REG_DOORBELL); | |
212 | } | |
213 | ||
214 | status = ft1000_read_dpram16(ft1000dev, | |
215 | DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1); | |
216 | handshake = ntohs(handshake); | |
217 | ||
218 | if (status) | |
219 | return HANDSHAKE_TIMEOUT_VALUE; | |
220 | ||
221 | if ((handshake == expected_value) || | |
222 | (handshake == HANDSHAKE_RESET_VALUE_USB)) { | |
223 | return handshake; | |
224 | } else { | |
225 | loopcnt++; | |
226 | msleep(10); | |
227 | } | |
228 | } | |
229 | ||
230 | return HANDSHAKE_TIMEOUT_VALUE; | |
f7c1be0c MB |
231 | } |
232 | ||
233 | //--------------------------------------------------------------------------- | |
234 | // Function: put_handshake | |
235 | // | |
236 | // Parameters: struct ft1000_device - device structure | |
fc549a05 | 237 | // u16 handshake_value - handshake to be written |
bf3146c8 | 238 | // |
f7c1be0c MB |
239 | // Returns: none |
240 | // | |
241 | // Description: This function write the handshake value to the handshake location | |
242 | // in DPRAM | |
243 | // | |
244 | // Notes: | |
245 | // | |
246 | //--------------------------------------------------------------------------- | |
fc549a05 | 247 | static void put_handshake(struct ft1000_device *ft1000dev,u16 handshake_value) |
f7c1be0c | 248 | { |
a8d4d198 MB |
249 | u32 tempx; |
250 | u16 tempword; | |
251 | u32 status; | |
f7c1be0c | 252 | |
a8d4d198 MB |
253 | tempx = (u32)handshake_value; |
254 | tempx = ntohl(tempx); | |
255 | ||
256 | tempword = (u16)(tempx & 0xffff); | |
257 | status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, | |
258 | tempword, 0); | |
259 | tempword = (u16)(tempx >> 16); | |
260 | status = ft1000_write_dpram16(ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, | |
261 | tempword, 1); | |
262 | status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, | |
263 | FT1000_REG_DOORBELL); | |
f7c1be0c MB |
264 | } |
265 | ||
fc549a05 | 266 | static u16 get_handshake_usb(struct ft1000_device *ft1000dev, u16 expected_value) |
f7c1be0c | 267 | { |
5865a18e MB |
268 | u16 handshake; |
269 | int loopcnt; | |
270 | u16 temp; | |
271 | u32 status = 0; | |
f7c1be0c | 272 | |
1a88a068 | 273 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
5865a18e MB |
274 | loopcnt = 0; |
275 | handshake = 0; | |
276 | ||
277 | while (loopcnt < 100) { | |
278 | if (pft1000info->usbboot == 2) { | |
279 | status = ft1000_read_dpram32(ft1000dev, 0, | |
280 | (u8 *)&(pft1000info->tempbuf[0]), 64); | |
281 | for (temp = 0; temp < 16; temp++) { | |
282 | DEBUG("tempbuf %d = 0x%x\n", temp, | |
283 | pft1000info->tempbuf[temp]); | |
284 | } | |
285 | status = ft1000_read_dpram16(ft1000dev, | |
286 | DWNLD_MAG1_HANDSHAKE_LOC, | |
287 | (u8 *)&handshake, 1); | |
288 | DEBUG("handshake from read_dpram16 = 0x%x\n", | |
289 | handshake); | |
290 | if (pft1000info->dspalive == pft1000info->tempbuf[6]) { | |
291 | handshake = 0; | |
292 | } else { | |
293 | handshake = pft1000info->tempbuf[1]; | |
294 | pft1000info->dspalive = | |
295 | pft1000info->tempbuf[6]; | |
296 | } | |
297 | } else { | |
298 | status = ft1000_read_dpram16(ft1000dev, | |
299 | DWNLD_MAG1_HANDSHAKE_LOC, | |
300 | (u8 *)&handshake, 1); | |
301 | } | |
f7c1be0c | 302 | |
5865a18e MB |
303 | loopcnt++; |
304 | msleep(10); | |
305 | handshake = ntohs(handshake); | |
306 | if ((handshake == expected_value) || | |
307 | (handshake == HANDSHAKE_RESET_VALUE_USB)) | |
308 | return handshake; | |
309 | } | |
310 | ||
311 | return HANDSHAKE_TIMEOUT_VALUE; | |
f7c1be0c MB |
312 | } |
313 | ||
fc549a05 | 314 | static void put_handshake_usb(struct ft1000_device *ft1000dev,u16 handshake_value) |
f7c1be0c | 315 | { |
5acc5396 | 316 | int i; |
f7c1be0c MB |
317 | |
318 | for (i=0; i<1000; i++); | |
319 | } | |
320 | ||
321 | //--------------------------------------------------------------------------- | |
322 | // Function: get_request_type | |
323 | // | |
324 | // Parameters: struct ft1000_device - device structure | |
bf3146c8 | 325 | // |
f7c1be0c MB |
326 | // Returns: request type - success |
327 | // | |
328 | // Description: This function returns the request type | |
329 | // | |
330 | // Notes: | |
331 | // | |
332 | //--------------------------------------------------------------------------- | |
fc549a05 | 333 | static u16 get_request_type(struct ft1000_device *ft1000dev) |
f7c1be0c | 334 | { |
9b43f374 MB |
335 | u16 request_type; |
336 | u32 status; | |
337 | u16 tempword; | |
338 | u32 tempx; | |
1a88a068 | 339 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
f7c1be0c | 340 | |
9b43f374 MB |
341 | if (pft1000info->bootmode == 1) { |
342 | status = fix_ft1000_read_dpram32(ft1000dev, | |
343 | DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); | |
344 | tempx = ntohl(tempx); | |
345 | } else { | |
346 | tempx = 0; | |
347 | status = ft1000_read_dpram16(ft1000dev, | |
348 | DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1); | |
349 | tempx |= (tempword << 16); | |
350 | tempx = ntohl(tempx); | |
351 | } | |
352 | request_type = (u16)tempx; | |
f7c1be0c | 353 | |
9b43f374 | 354 | return request_type; |
f7c1be0c MB |
355 | } |
356 | ||
fc549a05 | 357 | static u16 get_request_type_usb(struct ft1000_device *ft1000dev) |
f7c1be0c | 358 | { |
c3ed5d2f MB |
359 | u16 request_type; |
360 | u32 status; | |
361 | u16 tempword; | |
362 | u32 tempx; | |
1a88a068 | 363 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
f7c1be0c | 364 | |
c3ed5d2f MB |
365 | if (pft1000info->bootmode == 1) { |
366 | status = fix_ft1000_read_dpram32(ft1000dev, | |
367 | DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx); | |
368 | tempx = ntohl(tempx); | |
369 | } else { | |
370 | if (pft1000info->usbboot == 2) { | |
371 | tempx = pft1000info->tempbuf[2]; | |
372 | tempword = pft1000info->tempbuf[3]; | |
373 | } else { | |
374 | tempx = 0; | |
375 | status = ft1000_read_dpram16(ft1000dev, | |
376 | DWNLD_MAG1_TYPE_LOC, | |
377 | (u8 *)&tempword, 1); | |
378 | } | |
379 | tempx |= (tempword << 16); | |
380 | tempx = ntohl(tempx); | |
381 | } | |
382 | request_type = (u16)tempx; | |
f7c1be0c | 383 | |
c3ed5d2f | 384 | return request_type; |
f7c1be0c MB |
385 | } |
386 | ||
387 | //--------------------------------------------------------------------------- | |
388 | // Function: get_request_value | |
389 | // | |
390 | // Parameters: struct ft1000_device - device structure | |
bf3146c8 | 391 | // |
f7c1be0c MB |
392 | // Returns: request value - success |
393 | // | |
394 | // Description: This function returns the request value | |
395 | // | |
396 | // Notes: | |
397 | // | |
398 | //--------------------------------------------------------------------------- | |
2a953cfd | 399 | static long get_request_value(struct ft1000_device *ft1000dev) |
f7c1be0c | 400 | { |
114a06ae MB |
401 | u32 value; |
402 | u16 tempword; | |
403 | u32 status; | |
1a88a068 | 404 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
f7c1be0c | 405 | |
114a06ae MB |
406 | if (pft1000info->bootmode == 1) { |
407 | status = fix_ft1000_read_dpram32(ft1000dev, | |
408 | DWNLD_MAG1_SIZE_LOC, (u8 *)&value); | |
409 | value = ntohl(value); | |
410 | } else { | |
411 | status = ft1000_read_dpram16(ft1000dev, | |
412 | DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0); | |
413 | value = tempword; | |
414 | status = ft1000_read_dpram16(ft1000dev, | |
415 | DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1); | |
416 | value |= (tempword << 16); | |
417 | value = ntohl(value); | |
418 | } | |
f7c1be0c | 419 | |
114a06ae | 420 | return value; |
f7c1be0c MB |
421 | } |
422 | ||
f7c1be0c MB |
423 | |
424 | //--------------------------------------------------------------------------- | |
425 | // Function: put_request_value | |
426 | // | |
427 | // Parameters: struct ft1000_device - device structure | |
428 | // long lvalue - value to be put into DPRAM location DWNLD_MAG1_SIZE_LOC | |
bf3146c8 | 429 | // |
f7c1be0c MB |
430 | // Returns: none |
431 | // | |
432 | // Description: This function writes a value to DWNLD_MAG1_SIZE_LOC | |
433 | // | |
434 | // Notes: | |
435 | // | |
436 | //--------------------------------------------------------------------------- | |
2a953cfd | 437 | static void put_request_value(struct ft1000_device *ft1000dev, long lvalue) |
f7c1be0c | 438 | { |
cc4f65bf MB |
439 | u32 tempx; |
440 | u32 status; | |
f7c1be0c | 441 | |
cc4f65bf MB |
442 | tempx = ntohl(lvalue); |
443 | status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, | |
444 | (u8 *)&tempx); | |
f7c1be0c MB |
445 | } |
446 | ||
447 | ||
448 | ||
449 | //--------------------------------------------------------------------------- | |
450 | // Function: hdr_checksum | |
451 | // | |
b13e39b2 | 452 | // Parameters: struct pseudo_hdr *pHdr - Pseudo header pointer |
bf3146c8 | 453 | // |
f7c1be0c MB |
454 | // Returns: checksum - success |
455 | // | |
456 | // Description: This function returns the checksum of the pseudo header | |
457 | // | |
458 | // Notes: | |
459 | // | |
460 | //--------------------------------------------------------------------------- | |
fc549a05 | 461 | static u16 hdr_checksum(struct pseudo_hdr *pHdr) |
f7c1be0c | 462 | { |
78395f67 MB |
463 | u16 *usPtr = (u16 *)pHdr; |
464 | u16 chksum; | |
f7c1be0c | 465 | |
bf3146c8 | 466 | |
78395f67 MB |
467 | chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^ |
468 | usPtr[4]) ^ usPtr[5]) ^ usPtr[6]); | |
f7c1be0c | 469 | |
78395f67 | 470 | return chksum; |
f7c1be0c MB |
471 | } |
472 | ||
473 | ||
474 | //--------------------------------------------------------------------------- | |
475 | // Function: write_blk | |
476 | // | |
477 | // Parameters: struct ft1000_device - device structure | |
fc549a05 | 478 | // u16 **pUsFile - DSP image file pointer in u16 |
c8f775c8 | 479 | // u8 **pUcFile - DSP image file pointer in u8 |
f7c1be0c MB |
480 | // long word_length - lenght of the buffer to be written |
481 | // to DPRAM | |
bf3146c8 | 482 | // |
f7c1be0c MB |
483 | // Returns: STATUS_SUCCESS - success |
484 | // STATUS_FAILURE - failure | |
485 | // | |
486 | // Description: This function writes a block of DSP image to DPRAM | |
487 | // | |
488 | // Notes: | |
489 | // | |
490 | //--------------------------------------------------------------------------- | |
84b7801d | 491 | static u32 write_blk (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length) |
f7c1be0c | 492 | { |
84b7801d | 493 | u32 Status = STATUS_SUCCESS; |
fc549a05 | 494 | u16 dpram; |
f7c1be0c | 495 | int loopcnt, i, j; |
fc549a05 MB |
496 | u16 tempword; |
497 | u16 tempbuffer[64]; | |
498 | u16 resultbuffer[64]; | |
1a88a068 | 499 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
f7c1be0c MB |
500 | |
501 | //DEBUG("FT1000:download:start word_length = %d\n",(int)word_length); | |
fc549a05 | 502 | dpram = (u16)DWNLD_MAG1_PS_HDR_LOC; |
f7c1be0c MB |
503 | tempword = *(*pUsFile); |
504 | (*pUsFile)++; | |
505 | Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0); | |
506 | tempword = *(*pUsFile); | |
507 | (*pUsFile)++; | |
508 | Status = ft1000_write_dpram16(ft1000dev, dpram++, tempword, 1); | |
509 | ||
510 | *pUcFile = *pUcFile + 4; | |
511 | word_length--; | |
fc549a05 | 512 | tempword = (u16)word_length; |
f7c1be0c | 513 | word_length = (word_length / 16) + 1; |
f7c1be0c MB |
514 | for (; word_length > 0; word_length--) /* In words */ |
515 | { | |
516 | loopcnt = 0; | |
517 | ||
bf3146c8 | 518 | for (i=0; i<32; i++) |
f7c1be0c | 519 | { |
bf3146c8 | 520 | if (tempword != 0) |
f7c1be0c MB |
521 | { |
522 | tempbuffer[i++] = *(*pUsFile); | |
523 | (*pUsFile)++; | |
524 | tempbuffer[i] = *(*pUsFile); | |
525 | (*pUsFile)++; | |
526 | *pUcFile = *pUcFile + 4; | |
527 | loopcnt++; | |
528 | tempword--; | |
529 | } | |
bf3146c8 | 530 | else |
f7c1be0c MB |
531 | { |
532 | tempbuffer[i++] = 0; | |
533 | tempbuffer[i] = 0; | |
534 | } | |
535 | } | |
bf3146c8 | 536 | |
f7c1be0c MB |
537 | //DEBUG("write_blk: loopcnt is %d\n", loopcnt); |
538 | //DEBUG("write_blk: bootmode = %d\n", bootmode); | |
539 | //DEBUG("write_blk: dpram = %x\n", dpram); | |
bf3146c8 GKH |
540 | if (pft1000info->bootmode == 0) |
541 | { | |
542 | if (dpram >= 0x3F4) | |
e2cb7da1 | 543 | Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 8); |
bf3146c8 | 544 | else |
e2cb7da1 | 545 | Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64); |
f7c1be0c | 546 | } |
bf3146c8 | 547 | else |
f7c1be0c | 548 | { |
bf3146c8 | 549 | for (j=0; j<10; j++) |
f7c1be0c | 550 | { |
e2cb7da1 | 551 | Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64); |
bf3146c8 | 552 | if (Status == STATUS_SUCCESS) |
f7c1be0c MB |
553 | { |
554 | // Work around for ASIC bit stuffing problem. | |
bf3146c8 | 555 | if ( (tempbuffer[31] & 0xfe00) == 0xfe00) |
f7c1be0c | 556 | { |
e2cb7da1 | 557 | Status = ft1000_write_dpram32(ft1000dev, dpram+12, (u8 *)&tempbuffer[24], 64); |
f7c1be0c MB |
558 | } |
559 | // Let's check the data written | |
e2cb7da1 | 560 | Status = ft1000_read_dpram32 (ft1000dev, dpram, (u8 *)&resultbuffer[0], 64); |
bf3146c8 | 561 | if ( (tempbuffer[31] & 0xfe00) == 0xfe00) |
f7c1be0c | 562 | { |
bf3146c8 | 563 | for (i=0; i<28; i++) |
f7c1be0c | 564 | { |
bf3146c8 | 565 | if (resultbuffer[i] != tempbuffer[i]) |
f7c1be0c MB |
566 | { |
567 | //NdisMSleep (100); | |
568 | DEBUG("FT1000:download:DPRAM write failed 1 during bootloading\n"); | |
569 | msleep(10); | |
570 | Status = STATUS_FAILURE; | |
571 | break; | |
572 | } | |
573 | } | |
e2cb7da1 | 574 | Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (u8 *)&resultbuffer[0], 64); |
bf3146c8 | 575 | for (i=0; i<16; i++) |
f7c1be0c MB |
576 | { |
577 | if (resultbuffer[i] != tempbuffer[i+24]) | |
578 | { | |
579 | //NdisMSleep (100); | |
580 | DEBUG("FT1000:download:DPRAM write failed 2 during bootloading\n"); | |
581 | msleep(10); | |
582 | Status = STATUS_FAILURE; | |
583 | break; | |
584 | } | |
585 | } | |
586 | } | |
bf3146c8 | 587 | else |
f7c1be0c | 588 | { |
bf3146c8 | 589 | for (i=0; i<32; i++) |
f7c1be0c | 590 | { |
bf3146c8 | 591 | if (resultbuffer[i] != tempbuffer[i]) |
f7c1be0c MB |
592 | { |
593 | //NdisMSleep (100); | |
594 | DEBUG("FT1000:download:DPRAM write failed 3 during bootloading\n"); | |
595 | msleep(10); | |
596 | Status = STATUS_FAILURE; | |
597 | break; | |
598 | } | |
599 | } | |
600 | } | |
601 | ||
bf3146c8 | 602 | if (Status == STATUS_SUCCESS) |
f7c1be0c | 603 | break; |
bf3146c8 | 604 | |
f7c1be0c MB |
605 | } |
606 | } | |
bf3146c8 GKH |
607 | |
608 | if (Status != STATUS_SUCCESS) | |
f7c1be0c MB |
609 | { |
610 | DEBUG("FT1000:download:Write failed tempbuffer[31] = 0x%x\n", tempbuffer[31]); | |
611 | break; | |
612 | } | |
613 | ||
614 | } | |
615 | dpram = dpram + loopcnt; | |
616 | } | |
bf3146c8 | 617 | |
f7c1be0c MB |
618 | return Status; |
619 | } | |
620 | ||
621 | static void usb_dnld_complete (struct urb *urb) | |
622 | { | |
623 | //DEBUG("****** usb_dnld_complete\n"); | |
624 | } | |
625 | ||
626 | //--------------------------------------------------------------------------- | |
627 | // Function: write_blk_fifo | |
628 | // | |
629 | // Parameters: struct ft1000_device - device structure | |
fc549a05 | 630 | // u16 **pUsFile - DSP image file pointer in u16 |
c8f775c8 | 631 | // u8 **pUcFile - DSP image file pointer in u8 |
f7c1be0c MB |
632 | // long word_length - lenght of the buffer to be written |
633 | // to DPRAM | |
bf3146c8 | 634 | // |
f7c1be0c MB |
635 | // Returns: STATUS_SUCCESS - success |
636 | // STATUS_FAILURE - failure | |
637 | // | |
638 | // Description: This function writes a block of DSP image to DPRAM | |
639 | // | |
640 | // Notes: | |
641 | // | |
642 | //--------------------------------------------------------------------------- | |
857af455 MB |
643 | static u32 write_blk_fifo(struct ft1000_device *ft1000dev, u16 **pUsFile, |
644 | u8 **pUcFile, long word_length) | |
f7c1be0c | 645 | { |
857af455 MB |
646 | u32 Status = STATUS_SUCCESS; |
647 | int byte_length; | |
648 | long aligncnt; | |
f7c1be0c | 649 | |
857af455 | 650 | byte_length = word_length * 4; |
f7c1be0c | 651 | |
857af455 MB |
652 | if (byte_length % 4) |
653 | aligncnt = 4 - (byte_length % 4); | |
654 | else | |
655 | aligncnt = 0; | |
656 | byte_length += aligncnt; | |
f7c1be0c | 657 | |
857af455 MB |
658 | if (byte_length && ((byte_length % 64) == 0)) |
659 | byte_length += 4; | |
f7c1be0c | 660 | |
857af455 MB |
661 | if (byte_length < 64) |
662 | byte_length = 68; | |
f7c1be0c | 663 | |
857af455 MB |
664 | usb_init_urb(ft1000dev->tx_urb); |
665 | memcpy(ft1000dev->tx_buf, *pUcFile, byte_length); | |
666 | usb_fill_bulk_urb(ft1000dev->tx_urb, | |
667 | ft1000dev->dev, | |
668 | usb_sndbulkpipe(ft1000dev->dev, | |
669 | ft1000dev->bulk_out_endpointAddr), | |
670 | ft1000dev->tx_buf, byte_length, usb_dnld_complete, | |
671 | (void *)ft1000dev); | |
bf3146c8 | 672 | |
857af455 | 673 | usb_submit_urb(ft1000dev->tx_urb, GFP_ATOMIC); |
f7c1be0c | 674 | |
857af455 MB |
675 | *pUsFile = *pUsFile + (word_length << 1); |
676 | *pUcFile = *pUcFile + (word_length << 2); | |
f7c1be0c | 677 | |
857af455 | 678 | return Status; |
f7c1be0c MB |
679 | } |
680 | ||
681 | //--------------------------------------------------------------------------- | |
682 | // | |
683 | // Function: scram_dnldr | |
684 | // | |
685 | // Synopsis: Scramble downloader for Harley based ASIC via USB interface | |
686 | // | |
687 | // Arguments: pFileStart - pointer to start of file | |
688 | // FileLength - file length | |
689 | // | |
690 | // Returns: status - return code | |
691 | //--------------------------------------------------------------------------- | |
692 | ||
6f953fbb MB |
693 | u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, |
694 | u32 FileLength) | |
f7c1be0c | 695 | { |
6f953fbb MB |
696 | u16 status = STATUS_SUCCESS; |
697 | u32 state; | |
698 | u16 handshake; | |
0ce72ea3 | 699 | struct pseudo_hdr *pseudo_header; |
6f953fbb MB |
700 | u16 pseudo_header_len; |
701 | long word_length; | |
702 | u16 request; | |
703 | u16 temp; | |
704 | u16 tempword; | |
f7c1be0c | 705 | |
0ce72ea3 MB |
706 | struct dsp_file_hdr *file_hdr; |
707 | struct dsp_image_info *dsp_img_info = NULL; | |
6f953fbb MB |
708 | long requested_version; |
709 | bool correct_version; | |
0ce72ea3 | 710 | struct drv_msg *mailbox_data; |
6f953fbb MB |
711 | u16 *data = NULL; |
712 | u16 *s_file = NULL; | |
713 | u8 *c_file = NULL; | |
714 | u8 *boot_end = NULL, *code_end = NULL; | |
715 | int image; | |
716 | long loader_code_address, loader_code_size = 0; | |
717 | long run_address = 0, run_size = 0; | |
718 | ||
719 | u32 templong; | |
720 | u32 image_chksum = 0; | |
721 | ||
722 | u16 dpram = 0; | |
723 | u8 *pbuffer; | |
e27d96dd | 724 | struct prov_record *pprov_record; |
1a88a068 | 725 | struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net); |
bf3146c8 | 726 | |
6f953fbb MB |
727 | DEBUG("Entered scram_dnldr...\n"); |
728 | ||
729 | pft1000info->fcodeldr = 0; | |
730 | pft1000info->usbboot = 0; | |
731 | pft1000info->dspalive = 0xffff; | |
f7c1be0c | 732 | |
6f953fbb MB |
733 | // |
734 | // Get version id of file, at first 4 bytes of file, for newer files. | |
735 | // | |
f7c1be0c | 736 | |
6f953fbb | 737 | state = STATE_START_DWNLD; |
f7c1be0c | 738 | |
6f953fbb | 739 | file_hdr = (struct dsp_file_hdr *)pFileStart; |
f7c1be0c | 740 | |
6f953fbb | 741 | ft1000_write_register(ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK); |
f7c1be0c | 742 | |
6f953fbb MB |
743 | s_file = (u16 *) (pFileStart + file_hdr->loader_offset); |
744 | c_file = (u8 *) (pFileStart + file_hdr->loader_offset); | |
f7c1be0c | 745 | |
6f953fbb | 746 | boot_end = (u8 *) (pFileStart + file_hdr->loader_code_end); |
f7c1be0c | 747 | |
6f953fbb MB |
748 | loader_code_address = file_hdr->loader_code_address; |
749 | loader_code_size = file_hdr->loader_code_size; | |
750 | correct_version = FALSE; | |
751 | ||
752 | while ((status == STATUS_SUCCESS) && (state != STATE_DONE_FILE)) { | |
753 | switch (state) { | |
754 | case STATE_START_DWNLD: | |
755 | DEBUG("FT1000:STATE_START_DWNLD\n"); | |
756 | if (pft1000info->usbboot) | |
757 | handshake = | |
758 | get_handshake_usb(ft1000dev, | |
759 | HANDSHAKE_DSP_BL_READY); | |
760 | else | |
761 | handshake = | |
762 | get_handshake(ft1000dev, | |
763 | HANDSHAKE_DSP_BL_READY); | |
764 | ||
765 | if (handshake == HANDSHAKE_DSP_BL_READY) { | |
766 | DEBUG | |
767 | ("scram_dnldr: handshake is HANDSHAKE_DSP_BL_READY, call put_handshake(HANDSHAKE_DRIVER_READY)\n"); | |
768 | put_handshake(ft1000dev, | |
769 | HANDSHAKE_DRIVER_READY); | |
770 | } else { | |
771 | DEBUG | |
772 | ("FT1000:download:Download error: Handshake failed\n"); | |
773 | status = STATUS_FAILURE; | |
774 | } | |
f7c1be0c | 775 | |
6f953fbb | 776 | state = STATE_BOOT_DWNLD; |
f7c1be0c | 777 | |
6f953fbb | 778 | break; |
f7c1be0c | 779 | |
6f953fbb MB |
780 | case STATE_BOOT_DWNLD: |
781 | DEBUG("FT1000:STATE_BOOT_DWNLD\n"); | |
782 | pft1000info->bootmode = 1; | |
783 | handshake = get_handshake(ft1000dev, HANDSHAKE_REQUEST); | |
784 | if (handshake == HANDSHAKE_REQUEST) { | |
785 | /* | |
786 | * Get type associated with the request. | |
787 | */ | |
788 | request = get_request_type(ft1000dev); | |
789 | switch (request) { | |
790 | case REQUEST_RUN_ADDRESS: | |
791 | DEBUG("FT1000:REQUEST_RUN_ADDRESS\n"); | |
792 | put_request_value(ft1000dev, | |
793 | loader_code_address); | |
794 | break; | |
795 | case REQUEST_CODE_LENGTH: | |
796 | DEBUG("FT1000:REQUEST_CODE_LENGTH\n"); | |
797 | put_request_value(ft1000dev, | |
798 | loader_code_size); | |
799 | break; | |
800 | case REQUEST_DONE_BL: | |
801 | DEBUG("FT1000:REQUEST_DONE_BL\n"); | |
802 | /* Reposition ptrs to beginning of code section */ | |
803 | s_file = (u16 *) (boot_end); | |
804 | c_file = (u8 *) (boot_end); | |
805 | //DEBUG("FT1000:download:s_file = 0x%8x\n", (int)s_file); | |
806 | //DEBUG("FT1000:download:c_file = 0x%8x\n", (int)c_file); | |
807 | state = STATE_CODE_DWNLD; | |
808 | pft1000info->fcodeldr = 1; | |
809 | break; | |
810 | case REQUEST_CODE_SEGMENT: | |
811 | //DEBUG("FT1000:REQUEST_CODE_SEGMENT\n"); | |
812 | word_length = | |
813 | get_request_value(ft1000dev); | |
814 | //DEBUG("FT1000:word_length = 0x%x\n", (int)word_length); | |
815 | //NdisMSleep (100); | |
816 | if (word_length > MAX_LENGTH) { | |
817 | DEBUG | |
818 | ("FT1000:download:Download error: Max length exceeded\n"); | |
819 | status = STATUS_FAILURE; | |
820 | break; | |
821 | } | |
822 | if ((word_length * 2 + c_file) > | |
823 | boot_end) { | |
824 | /* | |
825 | * Error, beyond boot code range. | |
826 | */ | |
827 | DEBUG | |
828 | ("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundry.\n", | |
829 | (int)word_length); | |
830 | status = STATUS_FAILURE; | |
831 | break; | |
832 | } | |
833 | /* | |
834 | * Position ASIC DPRAM auto-increment pointer. | |
835 | */ | |
836 | dpram = (u16) DWNLD_MAG1_PS_HDR_LOC; | |
f7c1be0c MB |
837 | if (word_length & 0x1) |
838 | word_length++; | |
839 | word_length = word_length / 2; | |
840 | ||
6f953fbb MB |
841 | status = |
842 | write_blk(ft1000dev, &s_file, | |
843 | &c_file, word_length); | |
844 | //DEBUG("write_blk returned %d\n", status); | |
845 | break; | |
846 | default: | |
847 | DEBUG | |
848 | ("FT1000:download:Download error: Bad request type=%d in BOOT download state.\n", | |
849 | request); | |
850 | status = STATUS_FAILURE; | |
851 | break; | |
852 | } | |
853 | if (pft1000info->usbboot) | |
854 | put_handshake_usb(ft1000dev, | |
855 | HANDSHAKE_RESPONSE); | |
856 | else | |
857 | put_handshake(ft1000dev, | |
858 | HANDSHAKE_RESPONSE); | |
859 | } else { | |
860 | DEBUG | |
861 | ("FT1000:download:Download error: Handshake failed\n"); | |
862 | status = STATUS_FAILURE; | |
863 | } | |
864 | ||
865 | break; | |
866 | ||
867 | case STATE_CODE_DWNLD: | |
868 | //DEBUG("FT1000:STATE_CODE_DWNLD\n"); | |
869 | pft1000info->bootmode = 0; | |
870 | if (pft1000info->usbboot) | |
871 | handshake = | |
872 | get_handshake_usb(ft1000dev, | |
873 | HANDSHAKE_REQUEST); | |
874 | else | |
875 | handshake = | |
876 | get_handshake(ft1000dev, HANDSHAKE_REQUEST); | |
877 | if (handshake == HANDSHAKE_REQUEST) { | |
878 | /* | |
879 | * Get type associated with the request. | |
880 | */ | |
881 | if (pft1000info->usbboot) | |
882 | request = | |
883 | get_request_type_usb(ft1000dev); | |
884 | else | |
885 | request = get_request_type(ft1000dev); | |
886 | switch (request) { | |
887 | case REQUEST_FILE_CHECKSUM: | |
888 | DEBUG | |
889 | ("FT1000:download:image_chksum = 0x%8x\n", | |
890 | image_chksum); | |
891 | put_request_value(ft1000dev, | |
892 | image_chksum); | |
893 | break; | |
894 | case REQUEST_RUN_ADDRESS: | |
895 | DEBUG | |
896 | ("FT1000:download: REQUEST_RUN_ADDRESS\n"); | |
897 | if (correct_version) { | |
898 | DEBUG | |
899 | ("FT1000:download:run_address = 0x%8x\n", | |
900 | (int)run_address); | |
901 | put_request_value(ft1000dev, | |
902 | run_address); | |
903 | } else { | |
904 | DEBUG | |
905 | ("FT1000:download:Download error: Got Run address request before image offset request.\n"); | |
906 | status = STATUS_FAILURE; | |
907 | break; | |
908 | } | |
909 | break; | |
910 | case REQUEST_CODE_LENGTH: | |
911 | DEBUG | |
912 | ("FT1000:download:REQUEST_CODE_LENGTH\n"); | |
913 | if (correct_version) { | |
914 | DEBUG | |
915 | ("FT1000:download:run_size = 0x%8x\n", | |
916 | (int)run_size); | |
917 | put_request_value(ft1000dev, | |
918 | run_size); | |
919 | } else { | |
920 | DEBUG | |
921 | ("FT1000:download:Download error: Got Size request before image offset request.\n"); | |
922 | status = STATUS_FAILURE; | |
923 | break; | |
924 | } | |
925 | break; | |
926 | case REQUEST_DONE_CL: | |
927 | pft1000info->usbboot = 3; | |
928 | /* Reposition ptrs to beginning of provisioning section */ | |
929 | s_file = | |
930 | (u16 *) (pFileStart + | |
931 | file_hdr->commands_offset); | |
932 | c_file = | |
933 | (u8 *) (pFileStart + | |
934 | file_hdr->commands_offset); | |
935 | state = STATE_DONE_DWNLD; | |
936 | break; | |
937 | case REQUEST_CODE_SEGMENT: | |
938 | //DEBUG("FT1000:download: REQUEST_CODE_SEGMENT - CODELOADER\n"); | |
939 | if (!correct_version) { | |
940 | DEBUG | |
941 | ("FT1000:download:Download error: Got Code Segment request before image offset request.\n"); | |
942 | status = STATUS_FAILURE; | |
943 | break; | |
944 | } | |
945 | ||
946 | word_length = | |
947 | get_request_value(ft1000dev); | |
948 | //DEBUG("FT1000:download:word_length = %d\n", (int)word_length); | |
949 | if (word_length > MAX_LENGTH) { | |
950 | DEBUG | |
951 | ("FT1000:download:Download error: Max length exceeded\n"); | |
952 | status = STATUS_FAILURE; | |
953 | break; | |
954 | } | |
955 | if ((word_length * 2 + c_file) > | |
956 | code_end) { | |
957 | /* | |
958 | * Error, beyond boot code range. | |
959 | */ | |
960 | DEBUG | |
961 | ("FT1000:download:Download error: Requested len=%d exceeds DSP code boundry.\n", | |
962 | (int)word_length); | |
963 | status = STATUS_FAILURE; | |
964 | break; | |
965 | } | |
966 | /* | |
967 | * Position ASIC DPRAM auto-increment pointer. | |
968 | */ | |
969 | dpram = (u16) DWNLD_MAG1_PS_HDR_LOC; | |
970 | if (word_length & 0x1) | |
971 | word_length++; | |
972 | word_length = word_length / 2; | |
973 | ||
974 | write_blk_fifo(ft1000dev, &s_file, | |
975 | &c_file, word_length); | |
976 | if (pft1000info->usbboot == 0) | |
977 | pft1000info->usbboot++; | |
978 | if (pft1000info->usbboot == 1) { | |
979 | tempword = 0; | |
980 | ft1000_write_dpram16(ft1000dev, | |
981 | DWNLD_MAG1_PS_HDR_LOC, | |
982 | tempword, | |
983 | 0); | |
984 | } | |
985 | ||
986 | break; | |
987 | ||
988 | case REQUEST_MAILBOX_DATA: | |
989 | DEBUG | |
990 | ("FT1000:download: REQUEST_MAILBOX_DATA\n"); | |
991 | // Convert length from byte count to word count. Make sure we round up. | |
992 | word_length = | |
993 | (long)(pft1000info->DSPInfoBlklen + | |
994 | 1) / 2; | |
995 | put_request_value(ft1000dev, | |
996 | word_length); | |
997 | mailbox_data = | |
998 | (struct drv_msg *)&(pft1000info-> | |
999 | DSPInfoBlk[0]); | |
1000 | /* | |
1001 | * Position ASIC DPRAM auto-increment pointer. | |
1002 | */ | |
1003 | ||
1004 | data = (u16 *) & mailbox_data->data[0]; | |
1005 | dpram = (u16) DWNLD_MAG1_PS_HDR_LOC; | |
1006 | if (word_length & 0x1) | |
1007 | word_length++; | |
1008 | ||
1009 | word_length = (word_length / 2); | |
1010 | ||
1011 | for (; word_length > 0; word_length--) { /* In words */ | |
1012 | ||
1013 | templong = *data++; | |
1014 | templong |= (*data++ << 16); | |
1015 | status = | |
1016 | fix_ft1000_write_dpram32 | |
1017 | (ft1000dev, dpram++, | |
1018 | (u8 *) & templong); | |
1019 | ||
1020 | } | |
1021 | break; | |
1022 | ||
1023 | case REQUEST_VERSION_INFO: | |
1024 | DEBUG | |
1025 | ("FT1000:download:REQUEST_VERSION_INFO\n"); | |
1026 | word_length = | |
1027 | file_hdr->version_data_size; | |
1028 | put_request_value(ft1000dev, | |
1029 | word_length); | |
1030 | /* | |
1031 | * Position ASIC DPRAM auto-increment pointer. | |
1032 | */ | |
1033 | ||
1034 | s_file = | |
1035 | (u16 *) (pFileStart + | |
1036 | file_hdr-> | |
1037 | version_data_offset); | |
1038 | ||
1039 | dpram = (u16) DWNLD_MAG1_PS_HDR_LOC; | |
1040 | if (word_length & 0x1) | |
1041 | word_length++; | |
1042 | ||
1043 | word_length = (word_length / 2); | |
1044 | ||
1045 | for (; word_length > 0; word_length--) { /* In words */ | |
1046 | ||
1047 | templong = ntohs(*s_file++); | |
1048 | temp = ntohs(*s_file++); | |
1049 | templong |= (temp << 16); | |
1050 | status = | |
1051 | fix_ft1000_write_dpram32 | |
1052 | (ft1000dev, dpram++, | |
1053 | (u8 *) & templong); | |
1054 | ||
1055 | } | |
1056 | break; | |
1057 | ||
1058 | case REQUEST_CODE_BY_VERSION: | |
1059 | DEBUG | |
1060 | ("FT1000:download:REQUEST_CODE_BY_VERSION\n"); | |
1061 | correct_version = FALSE; | |
1062 | requested_version = | |
1063 | get_request_value(ft1000dev); | |
1064 | ||
1065 | dsp_img_info = | |
1066 | (struct dsp_image_info *)(pFileStart | |
1067 | + | |
1068 | sizeof | |
1069 | (struct | |
1070 | dsp_file_hdr)); | |
1071 | ||
1072 | for (image = 0; | |
1073 | image < file_hdr->nDspImages; | |
1074 | image++) { | |
1075 | ||
1076 | temp = | |
1077 | (u16) (dsp_img_info-> | |
1078 | version); | |
1079 | templong = temp; | |
1080 | temp = | |
1081 | (u16) (dsp_img_info-> | |
1082 | version >> 16); | |
1083 | templong |= (temp << 16); | |
1084 | if (templong == | |
1085 | (u32) requested_version) { | |
1086 | correct_version = TRUE; | |
1087 | DEBUG | |
1088 | ("FT1000:download: correct_version is TRUE\n"); | |
1089 | s_file = | |
1090 | (u16 *) (pFileStart | |
1091 | + | |
1092 | dsp_img_info-> | |
1093 | begin_offset); | |
1094 | c_file = | |
1095 | (u8 *) (pFileStart + | |
1096 | dsp_img_info-> | |
1097 | begin_offset); | |
1098 | code_end = | |
1099 | (u8 *) (pFileStart + | |
1100 | dsp_img_info-> | |
1101 | end_offset); | |
1102 | run_address = | |
1103 | dsp_img_info-> | |
1104 | run_address; | |
1105 | run_size = | |
1106 | dsp_img_info-> | |
1107 | image_size; | |
1108 | image_chksum = | |
1109 | (u32) dsp_img_info-> | |
1110 | checksum; | |
1111 | break; | |
1112 | } | |
1113 | dsp_img_info++; | |
1114 | ||
1115 | } //end of for | |
1116 | ||
1117 | if (!correct_version) { | |
1118 | /* | |
1119 | * Error, beyond boot code range. | |
1120 | */ | |
1121 | DEBUG | |
1122 | ("FT1000:download:Download error: Bad Version Request = 0x%x.\n", | |
1123 | (int)requested_version); | |
1124 | status = STATUS_FAILURE; | |
1125 | break; | |
1126 | } | |
1127 | break; | |
1128 | ||
1129 | default: | |
1130 | DEBUG | |
1131 | ("FT1000:download:Download error: Bad request type=%d in CODE download state.\n", | |
1132 | request); | |
1133 | status = STATUS_FAILURE; | |
1134 | break; | |
1135 | } | |
1136 | if (pft1000info->usbboot) | |
1137 | put_handshake_usb(ft1000dev, | |
1138 | HANDSHAKE_RESPONSE); | |
1139 | else | |
1140 | put_handshake(ft1000dev, | |
1141 | HANDSHAKE_RESPONSE); | |
1142 | } else { | |
1143 | DEBUG | |
1144 | ("FT1000:download:Download error: Handshake failed\n"); | |
1145 | status = STATUS_FAILURE; | |
1146 | } | |
1147 | ||
1148 | break; | |
1149 | ||
1150 | case STATE_DONE_DWNLD: | |
1151 | DEBUG("FT1000:download:Code loader is done...\n"); | |
1152 | state = STATE_SECTION_PROV; | |
1153 | break; | |
1154 | ||
1155 | case STATE_SECTION_PROV: | |
1156 | DEBUG("FT1000:download:STATE_SECTION_PROV\n"); | |
1157 | pseudo_header = (struct pseudo_hdr *)c_file; | |
1158 | ||
1159 | if (pseudo_header->checksum == | |
1160 | hdr_checksum(pseudo_header)) { | |
1161 | if (pseudo_header->portdest != | |
1162 | 0x80 /* Dsp OAM */ ) { | |
1163 | state = STATE_DONE_PROV; | |
1164 | break; | |
1165 | } | |
1166 | pseudo_header_len = ntohs(pseudo_header->length); /* Byte length for PROV records */ | |
1167 | ||
1168 | // Get buffer for provisioning data | |
1169 | pbuffer = | |
1170 | kmalloc((pseudo_header_len + | |
1171 | sizeof(struct pseudo_hdr)), | |
1172 | GFP_ATOMIC); | |
1173 | if (pbuffer) { | |
1174 | memcpy(pbuffer, (void *)c_file, | |
1175 | (u32) (pseudo_header_len + | |
1176 | sizeof(struct | |
1177 | pseudo_hdr))); | |
1178 | // link provisioning data | |
1179 | pprov_record = | |
1180 | kmalloc(sizeof(struct prov_record), | |
1181 | GFP_ATOMIC); | |
1182 | if (pprov_record) { | |
1183 | pprov_record->pprov_data = | |
1184 | pbuffer; | |
1185 | list_add_tail(&pprov_record-> | |
1186 | list, | |
1187 | &pft1000info-> | |
1188 | prov_list); | |
1189 | // Move to next entry if available | |
1190 | c_file = | |
1191 | (u8 *) ((unsigned long) | |
1192 | c_file + | |
1193 | (u32) ((pseudo_header_len + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr)); | |
1194 | if ((unsigned long)(c_file) - | |
1195 | (unsigned long)(pFileStart) | |
1196 | >= | |
1197 | (unsigned long)FileLength) { | |
1198 | state = STATE_DONE_FILE; | |
1199 | } | |
1200 | } else { | |
1201 | kfree(pbuffer); | |
1202 | status = STATUS_FAILURE; | |
1203 | } | |
1204 | } else { | |
1205 | status = STATUS_FAILURE; | |
1206 | } | |
1207 | } else { | |
1208 | /* Checksum did not compute */ | |
1209 | status = STATUS_FAILURE; | |
1210 | } | |
1211 | DEBUG | |
1212 | ("ft1000:download: after STATE_SECTION_PROV, state = %d, status= %d\n", | |
1213 | state, status); | |
1214 | break; | |
1215 | ||
1216 | case STATE_DONE_PROV: | |
1217 | DEBUG("FT1000:download:STATE_DONE_PROV\n"); | |
1218 | state = STATE_DONE_FILE; | |
1219 | break; | |
1220 | ||
1221 | default: | |
1222 | status = STATUS_FAILURE; | |
1223 | break; | |
1224 | } /* End Switch */ | |
1225 | ||
1226 | if (status != STATUS_SUCCESS) { | |
1227 | break; | |
1228 | } | |
f7c1be0c MB |
1229 | |
1230 | /**** | |
1231 | // Check if Card is present | |
0ce72ea3 MB |
1232 | status = Harley_Read_Register(&temp, FT1000_REG_SUP_IMASK); |
1233 | if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0x0000) ) { | |
f7c1be0c MB |
1234 | break; |
1235 | } | |
1236 | ||
0ce72ea3 MB |
1237 | status = Harley_Read_Register(&temp, FT1000_REG_ASIC_ID); |
1238 | if ( (status != NDIS_STATUS_SUCCESS) || (temp == 0xffff) ) { | |
f7c1be0c MB |
1239 | break; |
1240 | } | |
1241 | ****/ | |
1242 | ||
6f953fbb | 1243 | } /* End while */ |
bf3146c8 | 1244 | |
6f953fbb MB |
1245 | DEBUG("Download exiting with status = 0x%8x\n", status); |
1246 | ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, | |
1247 | FT1000_REG_DOORBELL); | |
f7c1be0c | 1248 | |
6f953fbb | 1249 | return status; |
f7c1be0c MB |
1250 | } |
1251 |