allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / cfe / cfe / arch / mips / board / bcm96345 / src / cfiflash.c
blobbdb6e4ec61391c4fffa520f851ded06272567f21
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 /************************************************************************/ #ifdef _CFE_
32 #include "lib_printf.h"
33 #else // linux
34 #include <linux/param.h>
35 #include <linux/sched.h>
36 #include <linux/timer.h>
37 #endif
39 #include "cfiflash.h"
41 static int flash_status(volatile WORD *fp);
42 static byte flash_get_manuf_code(byte sector);
43 static WORD flash_get_device_id(byte sector);
44 static byte flash_get_cfi(struct cfi_query *query);
45 static unsigned char *get_flash_memptr(byte sector);
46 static int flash_write(byte sector, int offset, byte *buf, int nbytes, int ub);
47 static void flash_command(int command, byte sector, int offset, unsigned int data);
48 byte flash_chip_erase(byte sector);
49 byte flash_write_word_ub(byte sector, int offset, WORD data);
52 /*********************************************************************/
53 /* 'meminfo' should be a pointer, but most C compilers will not */
54 /* allocate static storage for a pointer without calling */
55 /* non-portable functions such as 'new'. We also want to avoid */
56 /* the overhead of passing this pointer for every driver call. */
57 /* Systems with limited heap space will need to do this. */
58 /*********************************************************************/
59 struct flashinfo meminfo; /* Flash information structure */
60 static int topBoot = TRUE;
61 static int totalSize = 0;
63 /*********************************************************************/
64 /* Init_flash is used to build a sector table from the information */
65 /* provided through the CFI query. This information is translated */
66 /* from erase_block information to base:offset information for each */
67 /* individual sector. This information is then stored in the meminfo */
68 /* structure, and used throughout the driver to access sector */
69 /* information. */
70 /* */
71 /* This is more efficient than deriving the sector base:offset */
72 /* information every time the memory map switches (since on the */
73 /* development platform can only map 64k at a time). If the entire */
74 /* flash memory array can be mapped in, then the addition static */
75 /* allocation for the meminfo structure can be eliminated, but the */
76 /* drivers will have to be re-written. */
77 /* */
78 /* The meminfo struct occupies 653 bytes of heap space, depending */
79 /* on the value of the define MAXSECTORS. Adjust to suit */
80 /* application */
81 /*********************************************************************/
83 byte flash_init(void)
85 int i=0, j=0, count=0;
86 int basecount=0L;
87 struct cfi_query query;
88 byte manuf_id;
89 WORD device_id;
91 /* First, assume
92 * a single 8k sector for sector 0. This is to allow
93 * the system to perform memory mapping to the device,
94 * even though the actual physical layout is unknown.
95 * Once mapped in, the CFI query will produce all
96 * relevant information.
98 meminfo.addr = 0L;
99 meminfo.areg = 0;
100 meminfo.nsect = 1;
101 meminfo.bank1start = 0;
102 meminfo.bank2start = 0;
104 meminfo.sec[0].size = 8192;
105 meminfo.sec[0].base = 0x00000;
106 meminfo.sec[0].bank = 1;
108 manuf_id = flash_get_manuf_code(0);
109 device_id = flash_get_device_id(0);
111 flash_get_cfi(&query);
113 count=0;basecount=0L;
115 for (i=0; i<query.num_erase_blocks; i++) {
116 count += query.erase_block[i].num_sectors;
119 meminfo.nsect = count;
120 count=0;
122 // need to determine if it top or bottom boot here
124 #if defined(DEBUG_FLASH)
125 printf("device_id = %0x\n", device_id);
126 #endif
128 switch (device_id)
130 case ID_AM29DL800B:
131 case ID_AM29LV800B:
132 case ID_AM29LV400B:
133 case ID_AM29LV160B:
134 case ID_AM29LV320B:
135 topBoot = FALSE;
136 break;
137 case ID_AM29DL800T:
138 case ID_AM29LV800T:
139 case ID_AM29LV160T:
140 case ID_AM29LV320T:
141 topBoot = TRUE;
142 break;
143 default:
144 printf("Flash memory not supported! Device id = %x\n", device_id);
145 return -1;
149 #if defined(DEBUG_FLASH)
150 printf("meminfo: topBoot=%d\n", topBoot);
151 #endif
153 if (!topBoot)
155 for (i=0; i<query.num_erase_blocks; i++) {
156 for(j=0; j<query.erase_block[i].num_sectors; j++) {
157 meminfo.sec[count].size = (int) query.erase_block[i].sector_size;
158 meminfo.sec[count].base = (int) basecount;
159 basecount += (int) query.erase_block[i].sector_size;
161 #if defined(DEBUG_FLASH)
162 printf(" meminfo.sec[%d]: .size[0x%08X], base[0x%08X]\n", count, meminfo.sec[count].size, meminfo.sec[count].base+PHYS_FLASH_BASE);
163 #endif
165 count++;
169 #if defined(DEBUG_FLASH)
170 printf("BottomBoot\n");
171 #endif
174 else /* TOP BOOT */
176 for (i = (query.num_erase_blocks - 1); i >= 0; i--) {
177 for(j=0; j<query.erase_block[i].num_sectors; j++) {
178 meminfo.sec[count].size = (int) query.erase_block[i].sector_size;
179 meminfo.sec[count].base = (int) basecount;
180 basecount += (int) query.erase_block[i].sector_size;
182 #if defined(DEBUG_FLASH)
183 printf("meminfo.sec[%d]: .size[0x%08X], base[0x%08X]\n", count, meminfo.sec[count].size, meminfo.sec[count].base+PHYS_FLASH_BASE);
184 #endif
185 count++;
189 #if defined(DEBUG_FLASH)
190 printf("TopBoot\n");
191 #endif
195 totalSize = meminfo.sec[count-1].base + meminfo.sec[count-1].size;
197 // HAVE TO be a printf to reset flash ??? cfe_sleep -- delay will not help!!!
198 flash_reset();
201 return (0);
205 /*********************************************************************/
206 /* BEGIN API WRAPPER FUNCTIONS */
207 /*********************************************************************/
208 /* Flash_sector_erase() will erase a single sector dictated by the */
209 /* sector parameter. */
210 /* Note: this function will merely BEGIN the erase program. Code */
211 /* execution will immediately return to the calling function */
212 /*********************************************************************/
214 byte flash_sector_erase(byte sector)
216 flash_command(FLASH_SERASE,sector,0,0);
217 return(1);
220 /*********************************************************************/
221 /* Flash_sector_erase_int() is identical to flash_sector_erase(), */
222 /* except it will wait until the erase is completed before returning */
223 /* control to the calling function. This can be used in cases which */
224 /* require the program to hold until a sector is erased, without */
225 /* adding the wait check external to this function. */
226 /*********************************************************************/
228 byte flash_sector_erase_int(byte sector)
230 flash_command(FLASH_SERASE,sector,0,0);
231 while (flash_status((WORD*)get_flash_memptr(sector))
232 == STATUS_BUSY) { }
233 return(1);
236 /*********************************************************************/
237 /* flash_reset() will reset the flash device to reading array data. */
238 /* It is good practice to call this function after autoselect */
239 /* sequences had been performed. */
240 /*********************************************************************/
242 byte flash_reset(void)
244 flash_command(FLASH_RESET,1,0,0);
245 return(1);
248 /*********************************************************************/
249 /* flash_sector_protect_verify() performs an autoselect command */
250 /* sequence which checks the status of the sector protect CAM */
251 /* to check if the particular sector is protected. Function will */
252 /* return a '0' is the sector is unprotected, and a '1' if it is */
253 /* protected. */
254 /*********************************************************************/
256 byte flash_sector_protect_verify(byte sector)
258 volatile WORD *fwp; /* flash window */
259 byte answer;
261 fwp = (WORD *)get_flash_memptr(sector);
263 flash_command(FLASH_AUTOSEL,sector,0,0);
265 fwp += ((meminfo.sec[sector].base)/2);
266 fwp += 2;
268 answer = (byte) (*fwp & 0x0001); /* Only need DQ0 to check */
270 flash_command(FLASH_RESET,sector,0,0);
272 return( (byte) answer );
275 /*********************************************************************/
276 /* flash_chip_erase() will perform a complete erasure of the flash */
277 /* device. */
278 /*********************************************************************/
280 byte flash_chip_erase(byte sector)
282 flash_command(FLASH_CERASE,sector,0,0);
283 return(1);
286 /*********************************************************************/
287 /* flash_write_word() will program a single word of data at the */
288 /* specified offset from the beginning of the sector parameter. */
289 /* Note: this offset must be word aligned, or else errors are */
290 /* possible (this can happen when dealing with odd offsets due to */
291 /* only partial programming. */
292 /* Note: It is good practice to check the desired offset by first */
293 /* reading the data, and checking to see if it contains 0xFFFF */
294 /*********************************************************************/
296 byte flash_write_word(byte sector, int offset, WORD data)
298 flash_command(FLASH_PROG, sector, offset, data);
299 return (1);
302 /*********************************************************************/
303 /* flash_write_buf() functions like flash_write_word(), except */
304 /* that it accepts a pointer to a buffer to be programmed. This */
305 /* function will align the data to a word offset, then bulk program */
306 /* the flash device with the provided data. */
307 /* The maximum buffer size is currently only limited to the data */
308 /* size of the numbytes parameter (which in the test system is */
309 /* 16 bits = 65535 words */
310 /* Since the current maximum flash sector size is 64kbits, this */
311 /* should not present a problem. */
312 /*********************************************************************/
314 int flash_write_buf(byte sector, int offset,
315 byte *buffer, int numbytes)
318 return flash_write(sector, offset, buffer, numbytes, FALSE);
321 /*********************************************************************/
322 /* flash_read_buf() reads buffer of data from the specified */
323 /* offset from the sector parameter. */
324 /*********************************************************************/
326 int flash_read_buf(byte sector, int offset,
327 byte *buffer, int numbytes)
329 byte *fwp;
331 flash_command(FLASH_SELECT, sector, 0, 0);
332 fwp = (byte *)get_flash_memptr(sector);
334 while (numbytes) {
335 *buffer++ = *(fwp + offset);
336 numbytes--;
337 fwp++;
340 return (1);
343 /*********************************************************************/
344 /* flash_erase_suspend() will suspend an erase process in the */
345 /* specified sector. Array data can then be read from other sectors */
346 /* (or any other sectors in other banks), and the erase can be */
347 /* resumed using the flash_erase_resume function. */
348 /* Note: multiple sectors can be queued for erasure, so int as the */
349 /* 80 uS erase suspend window has not terminated (see AMD data sheet */
350 /* concerning erase_suspend restrictions). */
351 /*********************************************************************/
353 byte flash_erase_suspend(byte sector)
355 flash_command(FLASH_ESUSPEND, sector, 0, 0);
356 return (1);
359 /*********************************************************************/
360 /* flash_erase_resume() will resume all pending erases in the bank */
361 /* in which the sector parameter is located. */
362 /*********************************************************************/
364 byte flash_erase_resume(byte sector)
366 flash_command(FLASH_ERESUME, sector, 0, 0);
367 return (1);
370 /*********************************************************************/
371 /* UNLOCK BYPASS FUNCTIONS */
372 /*********************************************************************/
373 /* Unlock bypass mode is useful whenever the calling application */
374 /* wished to program large amounts of data in minimal time. Unlock */
375 /* bypass mode remove half of the bus overhead required to program */
376 /* a single word, from 4 cycles down to 2 cycles. Programming of */
377 /* individual bytes does not gain measurable benefit from unlock */
378 /* bypass mode, but programming large buffers can see a significant */
379 /* decrease in required programming time. */
380 /*********************************************************************/
382 /*********************************************************************/
383 /* flash_ub() places the flash into unlock bypass mode. This */
384 /* is REQUIRED to be called before any of the other unlock bypass */
385 /* commands will become valid (most will be ignored without first */
386 /* calling this function. */
387 /*********************************************************************/
389 byte flash_ub(byte sector)
391 flash_command(FLASH_UB, sector, 0, 0);
392 return(1);
395 /*********************************************************************/
396 /* flash_write_word_ub() programs a single word using unlock bypass */
397 /* mode. Note that the calling application will see little benefit */
398 /* from programming single words using this mode (outlined above) */
399 /*********************************************************************/
401 byte flash_write_word_ub(byte sector, int offset, WORD data)
403 flash_command(FLASH_UBPROG, sector, offset, data);
404 return (1);
407 /*********************************************************************/
408 /* flash_write_buf_ub() behaves in the exact same manner as */
409 /* flash_write_buf() (outlined above), expect that it utilizes */
410 /* the unlock bypass mode of the flash device. This can remove */
411 /* significant overhead from the bulk programming operation, and */
412 /* when programming bulk data a sizeable performance increase can be */
413 /* observed. */
414 /*********************************************************************/
416 int flash_write_buf_ub(byte sector, int offset,
417 byte *buffer, int numbytes)
419 return flash_write(sector, offset, buffer, numbytes, TRUE);
422 /*********************************************************************/
423 /* flash_reset_ub() is required to remove the flash from unlock */
424 /* bypass mode. This is important, as other flash commands will be */
425 /* ignored while the flash is in unlock bypass mode. */
426 /*********************************************************************/
428 byte flash_reset_ub(void)
430 flash_command(FLASH_UBRESET,1,0,0);
431 return(1);
434 /*********************************************************************/
435 /* Usefull funtion to return the number of sectors in the device. */
436 /* Can be used for functions which need to loop among all the */
437 /* sectors, or wish to know the number of the last sector. */
438 /*********************************************************************/
440 int flash_get_numsectors(void)
442 return meminfo.nsect;
445 /*********************************************************************/
446 /* flash_get_sector_size() is provided for cases in which the size */
447 /* of a sector is required by a host application. The sector size */
448 /* (in bytes) is returned in the data location pointed to by the */
449 /* 'size' parameter. */
450 /*********************************************************************/
452 int flash_get_sector_size(byte sector)
454 return meminfo.sec[sector].size;
457 /*********************************************************************/
458 /* flash_get_cfi() is the main CFI workhorse function. Due to it's */
459 /* complexity and size it need only be called once upon */
460 /* initializing the flash system. Once it is called, all operations */
461 /* are performed by looking at the meminfo structure. */
462 /* All possible care was made to make this algorithm as efficient as */
463 /* possible. 90% of all operations are memory reads, and all */
464 /* calculations are done using bit-shifts when possible */
465 /*********************************************************************/
467 byte flash_get_cfi(struct cfi_query *query)
469 volatile WORD *fwp; /* flash window */
470 int volts=0, milli=0, temp=0, i=0;
471 int offset=0;
473 flash_command(FLASH_RESET,0,0,0); /* Use sector 0 for all commands */
474 flash_command(FLASH_CFIQUERY,0,0,0);
476 fwp = (WORD *)get_flash_memptr(0);
478 /* Initial house-cleaning */
480 for(i=0; i < 8; i++) {
481 query->erase_block[i].sector_size = 0;
482 query->erase_block[i].num_sectors = 0;
485 query->query_string[0] = fwp[0x10];
486 query->query_string[1] = fwp[0x11];
487 query->query_string[2] = fwp[0x12];
488 query->query_string[3] = '\0';
490 /* If not 'QRY', then we dont have a CFI enabled device in the
491 socket */
493 if( query->query_string[0] != 'Q' &&
494 query->query_string[1] != 'R' &&
495 query->query_string[2] != 'Y') {
496 return(-1);
499 query->oem_command_set = fwp[0x13];
500 query->primary_table_address = fwp[0x15]; /* Important one! */
501 query->alt_command_set = fwp[0x17];
502 query->alt_table_address = fwp[0x19];
504 /* We will do some bit translation to give the following values
505 numerical meaning in terms of C 'float' numbers */
507 volts = ((fwp[0x1B] & 0xF0) >> 4);
508 milli = (fwp[0x1B] & 0x0F);
509 query->vcc_min = volts * 10 + milli;
511 volts = ((fwp[0x1C] & 0xF0) >> 4);
512 milli = (fwp[0x1C] & 0x0F);
513 query->vcc_max = volts * 10 + milli;
515 volts = ((fwp[0x1D] & 0xF0) >> 4);
516 milli = (fwp[0x1D] & 0x0F);
517 query->vpp_min = volts * 10 + milli;
519 volts = ((fwp[0x1E] & 0xF0) >> 4);
520 milli = (fwp[0x1E] & 0x0F);
521 query->vpp_max = volts * 10 + milli;
523 /* Let's not drag in the libm library to calculate powers
524 for something as simple as 2^(power)
525 Use a bit shift instead - it's faster */
527 temp = fwp[0x1F];
528 query->timeout_single_write = (1 << temp);
530 temp = fwp[0x20];
531 if (temp != 0x00)
532 query->timeout_buffer_write = (1 << temp);
533 else
534 query->timeout_buffer_write = 0x00;
536 temp = 0;
537 temp = fwp[0x21];
538 query->timeout_block_erase = (1 << temp);
540 temp = fwp[0x22];
541 if (temp != 0x00)
542 query->timeout_chip_erase = (1 << temp);
543 else
544 query->timeout_chip_erase = 0x00;
546 temp = fwp[0x23];
547 query->max_timeout_single_write = (1 << temp) *
548 query->timeout_single_write;
550 temp = fwp[0x24];
551 if (temp != 0x00)
552 query->max_timeout_buffer_write = (1 << temp) *
553 query->timeout_buffer_write;
554 else
555 query->max_timeout_buffer_write = 0x00;
557 temp = fwp[0x25];
558 query->max_timeout_block_erase = (1 << temp) *
559 query->timeout_block_erase;
561 temp = fwp[0x26];
562 if (temp != 0x00)
563 query->max_timeout_chip_erase = (1 << temp) *
564 query->timeout_chip_erase;
565 else
566 query->max_timeout_chip_erase = 0x00;
568 temp = fwp[0x27];
569 query->device_size = (int) (((int)1) << temp);
571 query->interface_description = fwp[0x28];
573 temp = fwp[0x2A];
574 if (temp != 0x00)
575 query->max_multi_byte_write = (1 << temp);
576 else
577 query->max_multi_byte_write = 0;
579 query->num_erase_blocks = fwp[0x2C];
581 for(i=0; i < query->num_erase_blocks; i++) {
582 query->erase_block[i].num_sectors = fwp[(0x2D+(4*i))];
583 query->erase_block[i].num_sectors++;
585 query->erase_block[i].sector_size = (int) 256 *
586 ( (int)256 * fwp[(0x30+(4*i))] + fwp[(0x2F+(4*i))] );
589 /* Store primary table offset in variable for clarity */
590 offset = query->primary_table_address;
592 query->primary_extended_query[0] = fwp[(offset)];
593 query->primary_extended_query[1] = fwp[(offset + 1)];
594 query->primary_extended_query[2] = fwp[(offset + 2)];
595 query->primary_extended_query[3] = '\0';
597 if( query->primary_extended_query[0] != 'P' &&
598 query->primary_extended_query[1] != 'R' &&
599 query->primary_extended_query[2] != 'I') {
600 return(2);
603 query->major_version = fwp[(offset + 3)];
604 query->minor_version = fwp[(offset + 4)];
606 query->sensitive_unlock = (byte) (fwp[(offset+5)] & 0x0F);
607 query->erase_suspend = (byte) (fwp[(offset+6)] & 0x0F);
608 query->sector_protect = (byte) (fwp[(offset+7)] & 0x0F);
609 query->sector_temp_unprotect = (byte) (fwp[(offset+8)] & 0x0F);
610 query->protect_scheme = (byte) (fwp[(offset+9)] & 0x0F);
611 query->is_simultaneous = (byte) (fwp[(offset+10)] & 0x0F);
612 query->is_burst = (byte) (fwp[(offset+11)] & 0x0F);
613 query->is_page = (byte) (fwp[(offset+12)] & 0x0F);
615 return(1);
618 /*********************************************************************/
619 /* The purpose of get_flash_memptr() is to return a memory pointer */
620 /* which points to the beginning of memory space allocated for the */
621 /* flash. All function pointers are then referenced from this */
622 /* pointer. */
623 /* */
624 /* Different systems will implement this in different ways: */
625 /* possibilities include: */
626 /* - A direct memory pointer */
627 /* - A pointer to a memory map */
628 /* - A pointer to a hardware port from which the linear */
629 /* address is translated */
630 /* - Output of an MMU function / service */
631 /* */
632 /* Also note that this function expects the pointer to a specific */
633 /* sector of the device. This can be provided by dereferencing */
634 /* the pointer from a translated offset of the sector from a */
635 /* global base pointer (e.g. flashptr = base_pointer + sector_offset)*/
636 /* */
637 /* Important: Many AMD flash devices need both bank and or sector */
638 /* address bits to be correctly set (bank address bits are A18-A16, */
639 /* and sector address bits are A18-A12, or A12-A15). Flash parts */
640 /* which do not need these bits will ignore them, so it is safe to */
641 /* assume that every part will require these bits to be set. */
642 /*********************************************************************/
644 static unsigned char *get_flash_memptr(byte sector)
646 unsigned char *memptr = (unsigned char*)(FLASH_BASE_ADDR_REG + meminfo.sec[sector].base);
648 return (memptr);
651 unsigned char *flash_get_memptr(byte sector)
653 return( get_flash_memptr(sector) );
656 /*********************************************************************/
657 /* Flash_command() is the main driver function. It performs */
658 /* every possible command available to AMD B revision */
659 /* flash parts. Note that this command is not used directly, but */
660 /* rather called through the API wrapper functions provided below. */
661 /*********************************************************************/
663 static void flash_command(int command, byte sector, int offset,
664 unsigned int data)
666 volatile WORD *flashptr; /* flash window (64K bytes) */
667 int retry;
669 /**************************************************************/
670 /* IMPORTANT: Note that flashptr is defined as a WORD pointer */
671 /* If BYTE pointers are used, the command tables will have to */
672 /* be remapped */
673 /* Note 1: flashptr is declared far - if system does not */
674 /* support far pointers, this will have to be changed */
675 /* Note 2: flashptr is declared static to avoid calling */
676 /* get_flash_memptr() on successive sector accesses */
677 /**************************************************************/
679 /* Some commands may not work the first time, but will work */
680 /* on successive attempts. Vary the number of retries to suit*/
681 /* requirements. */
683 static int retrycount[] = {0,0,0,0,15,15,0,15,0,0,0};
685 retry = retrycount[command];
687 flashptr = (WORD *) get_flash_memptr(sector);
689 again:
691 if (command == FLASH_SELECT) {
692 return;
693 } else if (command == FLASH_RESET || command > FLASH_LASTCMD) {
694 flashptr[0] = 0xF0; /* assume reset device to read mode */
695 } else if (command == FLASH_ESUSPEND) {
696 flashptr[0] = 0xB0; /* suspend sector erase */
697 } else if (command == FLASH_ERESUME) {
698 flashptr[0] = 0x30; /* resume suspended sector erase */
699 } else if (command == FLASH_UBPROG) {
700 flashptr[0] = 0xA0;
701 flashptr[offset/2] = data;
702 } else if (command == FLASH_UBRESET) {
703 flashptr[0] = 0x90;
704 flashptr[0] = 0x00;
705 } else if (command == FLASH_CFIQUERY) {
706 flashptr[0x55] = 0x98;
708 else {
709 flashptr[0x555] = 0xAA; /* unlock 1 */
710 flashptr[0x2AA] = 0x55; /* unlock 2 */
711 switch (command) {
712 case FLASH_AUTOSEL:
713 flashptr[0x555] = 0x90;
714 break;
715 case FLASH_PROG:
716 flashptr[0x555] = 0xA0;
717 flashptr[offset/2] = data;
718 break;
719 case FLASH_CERASE:
720 flashptr[0x555] = 0x80;
721 flashptr[0x555] = 0xAA;
722 flashptr[0x2AA] = 0x55;
723 flashptr[0x555] = 0x10;
724 break;
725 case FLASH_SERASE:
726 flashptr[0x555] = 0x80;
727 flashptr[0x555] = 0xAA;
728 flashptr[0x2AA] = 0x55;
729 flashptr[0] = 0x30;
730 break;
731 case FLASH_UB:
732 flashptr[0x555] = 0x20;
733 break;
737 if (retry-- > 0 && flash_status(flashptr) == STATUS_READY) {
738 goto again;
742 /*********************************************************************/
743 /* Flash_write extends the functionality of flash_program() by */
744 /* providing an faster way to program multiple data words, without */
745 /* needing the function overhead of looping algorithms which */
746 /* program word by word. This function utilizes fast pointers */
747 /* to quickly loop through bulk data. */
748 /*********************************************************************/
749 static int flash_write(byte sector, int offset, byte *buf,
750 int nbytes, int ub)
752 volatile WORD *flashptr; /* flash window */
753 volatile WORD *dst;
754 WORD *src;
755 int stat;
756 int retry = 0, retried = 0;
758 flashptr = (WORD *)get_flash_memptr(sector);
760 dst = &flashptr[offset/2]; /* (byte offset) */
761 src = (WORD *)buf;
763 if ((nbytes | offset) & 1) {
764 return -1;
767 again:
769 /* Check to see if we're in unlock bypass mode */
770 if (ub == FALSE)
771 flashptr[0] = 0xF0; /* reset device to read mode */
773 while ((stat = flash_status(flashptr)) == STATUS_BUSY) {}
774 if (stat != STATUS_READY) {
775 return (byte*)src - buf;
778 while (nbytes > 0) {
779 if (ub == FALSE){
780 flashptr[0x555] = 0xAA; /* unlock 1 */
781 flashptr[0x2AA] = 0x55; /* unlock 2 */
783 flashptr[0x555] = 0xA0;
784 *dst++ = *src++;
786 while ((stat = flash_status(flashptr)) == STATUS_BUSY) {}
787 if (stat != STATUS_READY) break;
788 nbytes -= 2;
791 if (stat != STATUS_READY || nbytes != 0) {
792 if (retry-- > 0) {
793 ++retried;
794 --dst, --src; /* back up */
795 goto again; /* and retry the last word */
797 if (ub == FALSE)
798 flash_command(FLASH_RESET,sector,0,0);
800 return (byte*)src - buf;
804 /*********************************************************************/
805 /* Flash_status utilizes the DQ6, DQ5, and DQ3 polling algorithms */
806 /* described in the flash data book. It can quickly ascertain the */
807 /* operational status of the flash device, and return an */
808 /* appropriate status code (defined in flash.h) */
809 /*********************************************************************/
811 static int flash_status(volatile WORD *fp)
813 WORD d, t;
814 int retry = 1;
816 again:
818 d = *fp; /* read data */
819 t = d ^ *fp; /* read it again and see what toggled */
821 if (t == 0) { /* no toggles, nothing's happening */
822 return STATUS_READY;
824 else if (t == 0x04) { /* erase-suspend */
825 if (retry--) goto again; /* may have been write completion */
826 return STATUS_ERSUSP;
828 else if (t & 0x40) {
829 if (d & 0x20) { /* timeout */
830 if (retry--) goto again; /* may have been write completion */
831 return STATUS_TIMEOUT;
833 else {
834 return STATUS_BUSY;
838 if (retry--) goto again; /* may have been write completion */
840 return STATUS_ERROR;
843 /*********************************************************************/
844 /* flash_get_device_id() will perform an autoselect sequence on the */
845 /* flash device, and return the device id of the component. */
846 /* This function automatically resets to read mode. */
847 /*********************************************************************/
849 static WORD flash_get_device_id(byte sector)
851 volatile WORD *fwp; /* flash window */
852 WORD answer;
854 fwp = (WORD *)get_flash_memptr(sector);
856 flash_command(FLASH_AUTOSEL,sector,0,0);
857 answer = *(++fwp);
859 flash_command(FLASH_RESET,sector,0,0); /* just to be safe */
860 return( (WORD) answer );
863 /*********************************************************************/
864 /* flash_get_manuf_code() will perform an autoselect sequence on the */
865 /* flash device, and return the manufacturer code of the component. */
866 /* This function automatically resets to read mode. */
867 /*********************************************************************/
869 static byte flash_get_manuf_code(byte sector)
871 volatile WORD *fwp; /* flash window */
872 WORD answer;
874 fwp = (WORD *)get_flash_memptr(sector);
876 flash_command(FLASH_AUTOSEL,sector,0,0);
877 answer = *fwp;
879 flash_command(FLASH_RESET,sector,0,0); /* just to be safe */
880 return( (byte) (answer & 0x00FF) );
884 /*********************************************************************/
885 /* The purpose of flash_get_blk() is to return a the block number */
886 /* for a given memory address. */
887 /*********************************************************************/
889 int flash_get_blk(int addr)
891 int blk_start, i;
892 int last_blk = flash_get_numsectors();
893 int relative_addr = addr - (int) FLASH_BASE_ADDR_REG;
895 for(blk_start=0, i=0; i < relative_addr && blk_start < last_blk; blk_start++)
896 i += flash_get_sector_size(blk_start);
898 if( i > relative_addr )
901 #if defined(DEBUG_FLASH)
902 printf("Address does not start on flash block boundary. Use the current blk_start\n");
903 #endif
905 blk_start--; // last blk, dec by 1
907 else
908 if( blk_start == last_blk )
910 printf("Address is too big.\n");
911 blk_start = -1;
914 return( blk_start );
918 /************************************************************************/
919 /* The purpose of flash_get_total_size() is to return the total size of */
920 /* the flash */
921 /************************************************************************/
922 int flash_get_total_size()
924 return totalSize;