www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / bcmdrivers / opensource / char / board / bcm963xx / impl1 / cfiflash.c
1 /************************************************************************/
2 /*                                                                      */
3 /*  AMD CFI Enabled Flash Memory Drivers                                */
4 /*  File name: CFIFLASH.C                                               */
5 /*  Revision:  1.0  5/07/98                                             */
6 /*                                                                      */
7 /* Copyright (c) 1998 ADVANCED MICRO DEVICES, INC. All Rights Reserved. */
8 /* This software is unpublished and contains the trade secrets and      */
9 /* confidential proprietary information of AMD. Unless otherwise        */
10 /* provided in the Software Agreement associated herewith, it is        */
11 /* licensed in confidence "AS IS" and is not to be reproduced in whole  */
12 /* or part by any means except for backup. Use, duplication, or         */
13 /* disclosure by the Government is subject to the restrictions in       */
14 /* paragraph (b) (3) (B) of the Rights in Technical Data and Computer   */
15 /* Software clause in DFAR 52.227-7013 (a) (Oct 1988).                  */
16 /* Software owned by                                                    */
17 /* Advanced Micro Devices, Inc.,                                        */
18 /* One AMD Place,                                                       */
19 /* P.O. Box 3453                                                        */
20 /* Sunnyvale, CA 94088-3453.                                            */
21 /************************************************************************/
22 /*  This software constitutes a basic shell of source code for          */
23 /*  programming all AMD Flash components. AMD                           */
24 /*  will not be responsible for misuse or illegal use of this           */
25 /*  software for devices not supported herein. AMD is providing         */
26 /*  this source code "AS IS" and will not be responsible for            */
27 /*  issues arising from incorrect user implementation of the            */
28 /*  source code herein. It is the user's responsibility to              */
29 /*  properly design-in this source code.                                */
30 /*                                                                      */ 
31 /************************************************************************/                        
32 #ifdef _CFE_                                                
33 #include "lib_types.h"
34 #include "lib_printf.h"
35 #include "lib_string.h"
36 #include "cfe_timer.h"
37 #define printk  printf
38 #else       // linux
39 #include <linux/param.h>
40 #include <linux/sched.h>
41 #include <linux/timer.h>
42 #endif
43
44 #include "cfiflash.h"
45
46 #define USR9108
47
48 static int flash_wait(WORD sector, int offset, UINT16 data);
49 static UINT16 flash_get_device_id(void);
50 static int flash_get_cfi(struct cfi_query *query, UINT16 *cfi_struct, int flashFamily);
51 static int flash_write(WORD sector, int offset, byte *buf, int nbytes);
52 static void flash_command(int command, WORD sector, int offset, UINT16 data);
53
54 /*********************************************************************/
55 /* 'meminfo' should be a pointer, but most C compilers will not      */
56 /* allocate static storage for a pointer without calling             */
57 /* non-portable functions such as 'new'.  We also want to avoid      */
58 /* the overhead of passing this pointer for every driver call.       */
59 /* Systems with limited heap space will need to do this.             */
60 /*********************************************************************/
61 struct flashinfo meminfo; /* Flash information structure */
62 static int flashFamily = FLASH_UNDEFINED;
63 static int totalSize = 0;
64 static struct cfi_query query;
65
66 static UINT16 cfi_data_struct_29W160[] = {
67     0x0020, 0x0049, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
68     0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
69     0x0051, 0x0052, 0x0059, 0x0002, 0x0000, 0x0040, 0x0000, 0x0000,
70     0x0000, 0x0000, 0x0000, 0x0027, 0x0036, 0x0000, 0x0000, 0x0004,
71     0x0000, 0x000a, 0x0000, 0x0004, 0x0000, 0x0003, 0x0000, 0x0015,
72     0x0002, 0x0000, 0x0000, 0x0000, 0x0004, 0x0000, 0x0000, 0x0040,
73     0x0000, 0x0001, 0x0000, 0x0020, 0x0000, 0x0000, 0x0000, 0x0080,
74     0x0000, 0x001e, 0x0000, 0x0000, 0x0001, 0xffff, 0xffff, 0xffff,
75     0x0050, 0x0052, 0x0049, 0x0031, 0x0030, 0x0000, 0x0002, 0x0001,
76     0x0001, 0x0004, 0x0000, 0x0000, 0x0000, 0xffff, 0xffff, 0x0002,
77     0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
78     0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
79     0xffff, 0x0888, 0x252b, 0x8c84, 0x7dbc, 0xffff, 0xffff, 0xffff,
80     0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
81     0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
82     0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
83 };
84
85
86 /*********************************************************************/
87 /* Init_flash is used to build a sector table from the information   */
88 /* provided through the CFI query.  This information is translated   */
89 /* from erase_block information to base:offset information for each  */
90 /* individual sector. This information is then stored in the meminfo */
91 /* structure, and used throughout the driver to access sector        */
92 /* information.                                                      */
93 /*                                                                   */
94 /* This is more efficient than deriving the sector base:offset       */
95 /* information every time the memory map switches (since on the      */
96 /* development platform can only map 64k at a time).  If the entire  */
97 /* flash memory array can be mapped in, then the addition static     */
98 /* allocation for the meminfo structure can be eliminated, but the   */
99 /* drivers will have to be re-written.                               */
100 /*                                                                   */
101 /* The meminfo struct occupies 653 bytes of heap space, depending    */
102 /* on the value of the define MAXSECTORS.  Adjust to suit            */
103 /* application                                                       */ 
104 /*********************************************************************/
105 byte flash_init(void)
106 {
107     int i=0, j=0, count=0;
108     int basecount=0L;
109     UINT16 device_id;
110     int flipCFIGeometry = FALSE;
111
112     /* First, assume
113     * a single 8k sector for sector 0.  This is to allow
114     * the system to perform memory mapping to the device,
115     * even though the actual physical layout is unknown.
116     * Once mapped in, the CFI query will produce all
117     * relevant information.
118     */
119     meminfo.addr = 0L;
120     meminfo.areg = 0;
121     meminfo.nsect = 1;
122     meminfo.bank1start = 0;
123     meminfo.bank2start = 0;
124     
125     meminfo.sec[0].size = 8192;
126     meminfo.sec[0].base = 0x00000;
127     meminfo.sec[0].bank = 1;
128         
129     flash_command(FLASH_RESET, 0, 0, 0);
130
131     device_id = flash_get_device_id();
132
133     switch (device_id) {
134         case ID_I28F160C3B:
135         case ID_I28F320C3B:
136         case ID_I28F160C3T:
137         case ID_I28F320C3T:
138             flashFamily = FLASH_INTEL;
139             break;
140         case ID_AM29DL800B:
141         case ID_AM29LV800B:
142         case ID_AM29LV400B:   
143         case ID_AM29LV160B:
144         case ID_AM29LV320B:
145         case ID_MX29LV320AB:
146         case ID_AM29LV320MB:
147         case ID_AM29DL800T:
148         case ID_AM29LV800T:
149         case ID_AM29LV160T:
150         case ID_AM29LV320T:
151         case ID_MX29LV320AT:
152         case ID_AM29LV320MT:
153     // add ST flash device id  here           
154         case ID_M29W320ET:
155     // add ST flash device id  here        
156         
157             flashFamily = FLASH_AMD;
158             break;
159         case ID_SST39VF1601:
160                 case ID_SST39VF3201:
161     // add SST flash device id  here        
162                 case ID_SST39VF3202:
163     // add SST flash device id  here        
164             flashFamily = FLASH_SST;
165             break;
166         default:
167             printk("Flash memory not supported!  Device id = %x\n", device_id);
168             return -1;           
169     }
170
171     if (flash_get_cfi(&query, 0, flashFamily) == -1) {
172         switch(device_id) {
173         case ID_AM29LV160T:
174         case ID_AM29LV160B:
175             flash_get_cfi(&query, cfi_data_struct_29W160, flashFamily);
176             break;
177         default:
178             printk("CFI data structure not found. Device id = %x\n", device_id);
179             return -1;           
180         }
181     }
182
183     // need to determine if it top or bottom boot here
184     switch (device_id)
185     {
186         case ID_AM29DL800B:
187         case ID_AM29LV800B:
188         case ID_AM29LV400B:   
189         case ID_AM29LV160B:
190         case ID_AM29LV320B:
191         case ID_MX29LV320AB:
192         case ID_AM29LV320MB:
193         case ID_I28F160C3B:
194         case ID_I28F320C3B:
195         case ID_I28F160C3T:
196         case ID_I28F320C3T:
197                 case ID_SST39VF1601:
198                 case ID_SST39VF3201:
199             flipCFIGeometry = FALSE;
200             break;
201         case ID_AM29DL800T:
202         case ID_AM29LV800T:
203         case ID_AM29LV160T:
204         case ID_AM29LV320T:
205         case ID_MX29LV320AT:
206         case ID_AM29LV320MT:
207     // add SST and ST flash device id  here           
208         case ID_SST39VF3202:
209         case ID_M29W320ET:
210     // add SST and ST flash device id  here                         
211         
212             flipCFIGeometry = TRUE;
213             break;
214         default:
215             printk("Flash memory not supported!  Device id = %x\n", device_id);
216             return -1;           
217     }
218
219     count=0;basecount=0L;
220
221     if (!flipCFIGeometry)
222     {
223        for (i=0; i<query.num_erase_blocks; i++) {
224             for(j=0; j<query.erase_block[i].num_sectors; j++) {
225                 meminfo.sec[count].size = (int) query.erase_block[i].sector_size;
226                 meminfo.sec[count].base = (int) basecount;
227                 basecount += (int) query.erase_block[i].sector_size;
228                 count++;
229             }
230         }
231     }
232     else
233     {
234         for (i = (query.num_erase_blocks - 1); i >= 0; i--) {
235             for(j=0; j<query.erase_block[i].num_sectors; j++) {
236                 meminfo.sec[count].size = (int) query.erase_block[i].sector_size;
237                 meminfo.sec[count].base = (int) basecount;
238                 basecount += (int) query.erase_block[i].sector_size;
239                                 count++;
240             }
241         }
242     }
243
244     meminfo.nsect = count;
245     totalSize = meminfo.sec[count-1].base + meminfo.sec[count-1].size;
246     return (0);
247 }
248
249 /*********************************************************************/
250 /* Flash_sector_erase_int() is identical to flash_sector_erase(),    */
251 /* except it will wait until the erase is completed before returning */
252 /* control to the calling function.  This can be used in cases which */
253 /* require the program to hold until a sector is erased, without     */
254 /* adding the wait check external to this function.                  */
255 /*********************************************************************/
256 byte flash_sector_erase_int(WORD sector)
257 {
258     int i;
259
260     for( i = 0; i < 3; i++ ) {
261         flash_command(FLASH_SERASE, sector, 0, 0);
262         if (flash_wait(sector, 0, 0xffff) == STATUS_READY)
263             break;
264     }
265
266     return(1);
267 }
268
269 /*********************************************************************/
270 /* flash_read_buf() reads buffer of data from the specified          */
271 /* offset from the sector parameter.                                 */
272 /*********************************************************************/
273 int flash_read_buf(WORD sector, int offset,
274                         byte *buffer, int numbytes)
275 {
276     byte *fwp;
277
278     fwp = (byte *)flash_get_memptr(sector);
279
280         while (numbytes) {
281                 *buffer++ = *(fwp + offset);
282                 numbytes--;
283                 fwp++;
284     }
285
286     return (1);
287 }
288
289 /*********************************************************************/
290 /* flash_write_buf() utilizes                                        */
291 /* the unlock bypass mode of the flash device.  This can remove      */
292 /* significant overhead from the bulk programming operation, and     */
293 /* when programming bulk data a sizeable performance increase can be */
294 /* observed.                                                         */
295 /*********************************************************************/
296 int flash_write_buf(WORD sector, int offset, byte *buffer, int numbytes)
297 {
298     int ret = -1;
299     int i;
300     unsigned char *p = flash_get_memptr(sector) + offset;
301
302     /* After writing the flash block, compare the contents to the source
303      * buffer.  Try to write the sector successfully up to three times.
304      */
305     for( i = 0; i < 3; i++ ) {
306         ret = flash_write(sector, offset, buffer, numbytes);
307         if( !memcmp( p, buffer, numbytes ) )
308             break;
309         /* Erase and try again */
310         flash_sector_erase_int(sector);
311         printk("CFIFLASH: Rewriting sector %d\n", sector);
312         ret = -1;
313     }
314
315     if( ret == -1 )
316         printk( "Flash write error.  Verify failed\n" );
317
318     return( ret );
319 }
320
321 /*********************************************************************/
322 /* Usefull funtion to return the number of sectors in the device.    */
323 /* Can be used for functions which need to loop among all the        */
324 /* sectors, or wish to know the number of the last sector.           */
325 /*********************************************************************/
326 int flash_get_numsectors(void)
327 {
328     return meminfo.nsect;
329 }
330
331 /*********************************************************************/
332 /* flash_get_sector_size() is provided for cases in which the size   */
333 /* of a sector is required by a host application.  The sector size   */
334 /* (in bytes) is returned in the data location pointed to by the     */
335 /* 'size' parameter.                                                 */
336 /*********************************************************************/
337 int flash_get_sector_size(WORD sector)
338 {
339     return meminfo.sec[sector].size;
340 }
341
342 /*********************************************************************/
343 /* The purpose of flash_get_memptr() is to return a memory pointer   */
344 /* which points to the beginning of memory space allocated for the   */
345 /* flash.  All function pointers are then referenced from this       */
346 /* pointer.                                                          */
347 /*                                                                   */
348 /* Different systems will implement this in different ways:          */
349 /* possibilities include:                                            */
350 /*  - A direct memory pointer                                        */
351 /*  - A pointer to a memory map                                      */
352 /*  - A pointer to a hardware port from which the linear             */
353 /*    address is translated                                          */
354 /*  - Output of an MMU function / service                            */
355 /*                                                                   */
356 /* Also note that this function expects the pointer to a specific    */
357 /* sector of the device.  This can be provided by dereferencing      */
358 /* the pointer from a translated offset of the sector from a         */
359 /* global base pointer (e.g. flashptr = base_pointer + sector_offset)*/
360 /*                                                                   */
361 /* Important: Many AMD flash devices need both bank and or sector    */
362 /* address bits to be correctly set (bank address bits are A18-A16,  */
363 /* and sector address bits are A18-A12, or A12-A15).  Flash parts    */
364 /* which do not need these bits will ignore them, so it is safe to   */
365 /* assume that every part will require these bits to be set.         */
366 /*********************************************************************/
367 unsigned char *flash_get_memptr(WORD sector)
368 {
369         unsigned char *memptr = (unsigned char*)(FLASH_BASE_ADDR_REG + meminfo.sec[sector].base);
370
371         return (memptr);
372 }
373
374 /*********************************************************************/
375 /* The purpose of flash_get_blk() is to return a the block number    */
376 /* for a given memory address.                                       */
377 /*********************************************************************/
378 int flash_get_blk(int addr)
379 {
380     int blk_start, i;
381     int last_blk = flash_get_numsectors();
382     int relative_addr = addr - (int) FLASH_BASE_ADDR_REG;
383
384     for(blk_start=0, i=0; i < relative_addr && blk_start < last_blk; blk_start++)
385         i += flash_get_sector_size(blk_start);
386
387     if( i > relative_addr )
388     {
389         blk_start--;        // last blk, dec by 1
390     }
391     else
392         if( blk_start == last_blk )
393         {
394             printk("Address is too big.\n");
395             blk_start = -1;
396         }
397
398     return( blk_start );
399 }
400
401 /************************************************************************/
402 /* The purpose of flash_get_total_size() is to return the total size of */
403 /* the flash                                                            */
404 /************************************************************************/
405 int flash_get_total_size()
406 {
407     return totalSize;
408 }
409
410 /*********************************************************************/
411 /* Flash_command() is the main driver function.  It performs         */
412 /* every possible command available to AMD B revision                */
413 /* flash parts. Note that this command is not used directly, but     */
414 /* rather called through the API wrapper functions provided below.   */
415 /*********************************************************************/
416 static void flash_command(int command, WORD sector, int offset, UINT16 data)
417 {
418     volatile UINT16 *flashptr;
419     volatile UINT16 *flashbase;
420
421     flashptr = (UINT16 *) flash_get_memptr(sector);
422     flashbase = (UINT16 *) flash_get_memptr(0);
423     
424     switch (flashFamily) {
425     case FLASH_UNDEFINED:
426         /* These commands should work for AMD, Intel and SST flashes */
427         switch (command) {
428         case FLASH_RESET:
429             flashptr[0] = 0xF0;
430             flashptr[0] = 0xFF;
431             break;
432         case FLASH_READ_ID:
433                         flashptr[0x5555] = 0xAA;       /* unlock 1 */
434             flashptr[0x2AAA] = 0x55;       /* unlock 2 */
435             flashptr[0x5555] = 0x90;
436             break;
437         default:
438             break;
439         }
440         break;
441     case FLASH_AMD:
442         switch (command) {
443         case FLASH_RESET:
444             flashptr[0] = 0xF0;
445             break;
446         case FLASH_READ_ID:
447             flashptr[0x555] = 0xAA;       /* unlock 1 */
448             flashptr[0x2AA] = 0x55;       /* unlock 2 */
449             flashptr[0x555] = 0x90;
450             break;
451         case FLASH_CFIQUERY:
452             flashptr[0x55] = 0x98;
453             break;
454         case FLASH_UB:
455             flashptr[0x555] = 0xAA;       /* unlock 1 */
456             flashptr[0x2AA] = 0x55;       /* unlock 2 */
457             flashptr[0x555] = 0x20;
458             break;
459         case FLASH_PROG:
460             flashptr[0] = 0xA0;
461             flashptr[offset/2] = data;
462             break;
463         case FLASH_UBRESET:
464             flashptr[0] = 0x90;
465             flashptr[0] = 0x00;
466             break;
467         case FLASH_SERASE:
468             flashptr[0x555] = 0xAA;       /* unlock 1 */
469             flashptr[0x2AA] = 0x55;       /* unlock 2 */
470             flashptr[0x555] = 0x80;
471             flashptr[0x555] = 0xAA;
472             flashptr[0x2AA] = 0x55;
473             flashptr[0] = 0x30;
474             break;
475         default:
476             break;
477         }
478         break;
479     case FLASH_INTEL:
480         switch (command) {
481         case FLASH_RESET:
482             flashptr[0] = 0xFF;
483             break;
484         case FLASH_READ_ID:
485             flashptr[0] = 0x90;
486             break;
487         case FLASH_CFIQUERY:
488             flashptr[0] = 0x98;
489             break;
490         case FLASH_PROG:
491             flashptr[0] = 0x40;
492             flashptr[offset/2] = data;
493             break;
494         case FLASH_SERASE:
495             flashptr[0] = 0x60;
496             flashptr[0] = 0xD0;
497             flashptr[0] = 0x20;
498             flashptr[0] = 0xD0;
499             break;
500         default:
501             break;
502         }
503         break;
504     case FLASH_SST:
505         switch (command) {
506         case FLASH_RESET:
507             flashbase[0x5555] = 0xAA;       /* unlock 1 */
508             flashbase[0x2AAA] = 0x55;       /* unlock 2 */
509             flashbase[0x5555] = 0xf0;
510             break;
511         case FLASH_READ_ID:
512             flashbase[0x5555] = 0xAA;       /* unlock 1 */
513             flashbase[0x2AAA] = 0x55;       /* unlock 2 */
514             flashbase[0x5555] = 0x90;
515             break;
516         case FLASH_CFIQUERY:
517             flashbase[0x5555] = 0xAA;       /* unlock 1 */
518             flashbase[0x2AAA] = 0x55;       /* unlock 2 */
519             flashbase[0x5555] = 0x98;
520             break;
521         case FLASH_UB:
522             break;
523         case FLASH_PROG:
524             flashbase[0x5555] = 0xAA;       /* unlock 1 */
525             flashbase[0x2AAA] = 0x55;       /* unlock 2 */
526             flashbase[0x5555] = 0xa0;
527             flashptr[offset/2] = data;
528             break;
529         case FLASH_UBRESET:
530             break;
531         case FLASH_SERASE:
532             flashbase[0x5555] = 0xAA;       /* unlock 1 */
533             flashbase[0x2AAA] = 0x55;       /* unlock 2 */
534             flashbase[0x5555] = 0x80;
535             flashbase[0x5555] = 0xAA;
536             flashbase[0x2AAA] = 0x55;
537             flashptr[0] = 0x30;
538             break;
539         default:
540             break;
541         }
542         break;
543     default:
544         break;
545     }
546 }
547
548 /*********************************************************************/
549 /* flash_write extends the functionality of flash_program() by       */
550 /* providing an faster way to program multiple data words, without   */
551 /* needing the function overhead of looping algorithms which         */
552 /* program word by word.  This function utilizes fast pointers       */
553 /* to quickly loop through bulk data.                                */
554 /*********************************************************************/
555 static int flash_write(WORD sector, int offset, byte *buf, int nbytes)
556 {
557     UINT16 *src;
558     src = (UINT16 *)buf;
559
560     if ((nbytes | offset) & 1) {
561         return -1;
562     }
563
564     flash_command(FLASH_UB, 0, 0, 0);
565     while (nbytes > 0) {
566         flash_command(FLASH_PROG, sector, offset, *src);
567         if (flash_wait(sector, offset, *src) != STATUS_READY)
568             break;
569         offset +=2;
570         nbytes -=2;
571         src++;
572     }
573     flash_command(FLASH_UBRESET, 0, 0, 0);
574     
575     return (byte*)src - buf;
576 }
577
578 /*********************************************************************/
579 /* flash_wait utilizes the DQ6, DQ5, and DQ2 polling algorithms      */
580 /* described in the flash data book.  It can quickly ascertain the   */
581 /* operational status of the flash device, and return an             */
582 /* appropriate status code (defined in flash.h)                      */
583 /*********************************************************************/
584 static int flash_wait(WORD sector, int offset, UINT16 data)
585 {
586     volatile UINT16 *flashptr; /* flash window */
587     UINT16 d1, dlast;
588
589     flashptr = (UINT16 *) flash_get_memptr(sector);
590
591     if (flashFamily == FLASH_AMD || flashFamily == FLASH_SST) {
592 #if defined(_BCM96338_) || defined(CONFIG_BCM96338)
593         do {
594             d1 = flashptr[offset/2];
595             if (d1 == data)
596                 return STATUS_READY;
597         } while (!(d1 & 0x20));
598
599         d1 = flashptr[offset/2];
600
601         if (d1 != data) {
602             flash_command(FLASH_RESET, 0, 0, 0);
603             return STATUS_TIMEOUT;
604         }
605 #else
606   #ifdef USR9108
607         dlast = *flashptr;      // read the first data word outside the loop 
608         do {
609             d1 = dlast;         // temp store the last read word.       
610             dlast = *flashptr;  // read data again to check for toggled bits
611             if (!((d1 ^ dlast) & 0x44))  // if bits 6 & 2 are not tuggled, return with success.
612                 return STATUS_READY;
613   // use actual last read word to check bit 5 according to the flash data sheets
614         } while (!(dlast & 0x20)); // continue if bit 5 is zero 
615   #else 
616         do {
617             d1 = *flashptr;    /* read data */
618             d1 ^= *flashptr;   /* read it again and see what toggled */
619             if (d1 == 0)       /* no toggles, nothing's happening */
620                 return STATUS_READY;
621         } while (!(d1 & 0x20));
622   #endif
623
624         d1 = *flashptr;        /* read data */
625         d1 ^= *flashptr;   /* read it again and see what toggled */
626   #ifdef USR9108  
627         if ((d1 & 0x44)) {
628   #else
629         if (d1 != 0) {
630   #endif
631             flash_command(FLASH_RESET, 0, 0, 0);
632             return STATUS_TIMEOUT;
633         }
634 #endif
635     } else if (flashFamily == FLASH_INTEL) {
636         flashptr[0] = 0x70;
637         /* Wait for completion */
638         while(!(*flashptr & 0x80));
639         if (*flashptr & 0x30) {
640             flashptr[0] = 0x50;
641             flash_command(FLASH_RESET, 0, 0, 0);
642             return STATUS_TIMEOUT;
643         }
644         flashptr[0] = 0x50;
645         flash_command(FLASH_RESET, 0, 0, 0);
646     }
647     
648     return STATUS_READY;
649 }
650
651 /*********************************************************************/
652 /* flash_get_device_id() will perform an autoselect sequence on the  */
653 /* flash device, and return the device id of the component.          */
654 /* This function automatically resets to read mode.                  */
655 /*********************************************************************/
656 static UINT16 flash_get_device_id()
657 {
658     volatile UINT16 *fwp; /* flash window */
659     UINT16 answer;
660     
661     fwp = (UINT16 *)flash_get_memptr(0);
662     
663     flash_command(FLASH_READ_ID, 0, 0, 0);
664     answer = *(fwp + 1);
665     if (answer == ID_AM29LV320M) {
666         answer = *(fwp + 0xe);
667         answer = *(fwp + 0xf);
668     }
669     
670     flash_command(FLASH_RESET, 0, 0, 0);
671     return( (UINT16) answer );
672 }
673
674 /*********************************************************************/
675 /* flash_get_cfi() is the main CFI workhorse function.  Due to it's  */
676 /* complexity and size it need only be called once upon              */
677 /* initializing the flash system.  Once it is called, all operations */
678 /* are performed by looking at the meminfo structure.                */
679 /* All possible care was made to make this algorithm as efficient as */
680 /* possible.  90% of all operations are memory reads, and all        */
681 /* calculations are done using bit-shifts when possible              */
682 /*********************************************************************/
683 static int flash_get_cfi(struct cfi_query *query, UINT16 *cfi_struct, int flashFamily)
684 {
685     volatile UINT16 *fwp; /* flash window */
686     int i=0;
687
688     flash_command(FLASH_CFIQUERY, 0, 0, 0);
689     
690     if (cfi_struct == 0)
691         fwp = (UINT16 *)flash_get_memptr(0);
692     else
693         fwp = cfi_struct;
694     
695     /* Initial house-cleaning */
696     for(i=0; i < 8; i++) {
697         query->erase_block[i].sector_size = 0;
698         query->erase_block[i].num_sectors = 0;
699     }
700     
701     /* If not 'QRY', then we dont have a CFI enabled device in the socket */
702     if( fwp[0x10] != 'Q' &&
703         fwp[0x11] != 'R' &&
704         fwp[0x12] != 'Y') {
705         flash_command(FLASH_RESET, 0, 0, 0);
706         return(-1);
707     }
708     
709         query->num_erase_blocks = fwp[0x2C];
710         if(flashFamily == FLASH_SST)
711                 query->num_erase_blocks = 1;
712         
713     for(i=0; i < query->num_erase_blocks; i++) {
714                         query->erase_block[i].num_sectors = fwp[(0x2D+(4*i))] + (fwp[0x2E + (4*i)] << 8);
715                         query->erase_block[i].num_sectors++;
716                         query->erase_block[i].sector_size = 256 * (256 * fwp[(0x30+(4*i))] + fwp[(0x2F+(4*i))]);
717     }
718     
719     flash_command(FLASH_RESET, 0, 0, 0);
720     return(1);
721 }