1 /************************************************************************/
3 /* AMD CFI Enabled Flash Memory Drivers */
4 /* File name: CFIFLASH.C */
5 /* Revision: 1.0 5/07/98 */
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., */
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. */
31 /************************************************************************/ #ifdef _CFE_
32 #include "lib_printf.h"
34 #include <linux/param.h>
35 #include <linux/sched.h>
36 #include <linux/timer.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 */
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. */
78 /* The meminfo struct occupies 653 bytes of heap space, depending */
79 /* on the value of the define MAXSECTORS. Adjust to suit */
81 /*********************************************************************/
85 int i
=0, j
=0, count
=0;
87 struct cfi_query query
;
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.
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
;
122 // need to determine if it top or bottom boot here
124 #if defined(DEBUG_FLASH)
125 printf("device_id = %0x\n", device_id
);
144 printf("Flash memory not supported! Device id = %x\n", device_id
);
149 #if defined(DEBUG_FLASH)
150 printf("meminfo: topBoot=%d\n", 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
);
169 #if defined(DEBUG_FLASH)
170 printf("BottomBoot\n");
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
);
189 #if defined(DEBUG_FLASH)
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!!!
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);
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
))
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);
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 */
254 /*********************************************************************/
256 byte
flash_sector_protect_verify(byte sector
)
258 volatile WORD
*fwp
; /* flash window */
261 fwp
= (WORD
*)get_flash_memptr(sector
);
263 flash_command(FLASH_AUTOSEL
,sector
,0,0);
265 fwp
+= ((meminfo
.sec
[sector
].base
)/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 */
278 /*********************************************************************/
280 byte
flash_chip_erase(byte sector
)
282 flash_command(FLASH_CERASE
,sector
,0,0);
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
);
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
)
331 flash_command(FLASH_SELECT
, sector
, 0, 0);
332 fwp
= (byte
*)get_flash_memptr(sector
);
335 *buffer
++ = *(fwp
+ offset
);
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);
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);
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);
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
);
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 */
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);
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;
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
493 if( query
->query_string
[0] != 'Q' &&
494 query
->query_string
[1] != 'R' &&
495 query
->query_string
[2] != 'Y') {
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 */
528 query
->timeout_single_write
= (1 << temp
);
532 query
->timeout_buffer_write
= (1 << temp
);
534 query
->timeout_buffer_write
= 0x00;
538 query
->timeout_block_erase
= (1 << temp
);
542 query
->timeout_chip_erase
= (1 << temp
);
544 query
->timeout_chip_erase
= 0x00;
547 query
->max_timeout_single_write
= (1 << temp
) *
548 query
->timeout_single_write
;
552 query
->max_timeout_buffer_write
= (1 << temp
) *
553 query
->timeout_buffer_write
;
555 query
->max_timeout_buffer_write
= 0x00;
558 query
->max_timeout_block_erase
= (1 << temp
) *
559 query
->timeout_block_erase
;
563 query
->max_timeout_chip_erase
= (1 << temp
) *
564 query
->timeout_chip_erase
;
566 query
->max_timeout_chip_erase
= 0x00;
569 query
->device_size
= (int) (((int)1) << temp
);
571 query
->interface_description
= fwp
[0x28];
575 query
->max_multi_byte_write
= (1 << temp
);
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') {
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);
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 */
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 */
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)*/
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
);
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
,
666 volatile WORD
*flashptr
; /* flash window (64K bytes) */
669 /**************************************************************/
670 /* IMPORTANT: Note that flashptr is defined as a WORD pointer */
671 /* If BYTE pointers are used, the command tables will have to */
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*/
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
);
691 if (command
== FLASH_SELECT
) {
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
) {
701 flashptr
[offset
/2] = data
;
702 } else if (command
== FLASH_UBRESET
) {
705 } else if (command
== FLASH_CFIQUERY
) {
706 flashptr
[0x55] = 0x98;
709 flashptr
[0x555] = 0xAA; /* unlock 1 */
710 flashptr
[0x2AA] = 0x55; /* unlock 2 */
713 flashptr
[0x555] = 0x90;
716 flashptr
[0x555] = 0xA0;
717 flashptr
[offset
/2] = data
;
720 flashptr
[0x555] = 0x80;
721 flashptr
[0x555] = 0xAA;
722 flashptr
[0x2AA] = 0x55;
723 flashptr
[0x555] = 0x10;
726 flashptr
[0x555] = 0x80;
727 flashptr
[0x555] = 0xAA;
728 flashptr
[0x2AA] = 0x55;
732 flashptr
[0x555] = 0x20;
737 if (retry
-- > 0 && flash_status(flashptr
) == STATUS_READY
) {
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
,
752 volatile WORD
*flashptr
; /* flash window */
756 int retry
= 0, retried
= 0;
758 flashptr
= (WORD
*)get_flash_memptr(sector
);
760 dst
= &flashptr
[offset
/2]; /* (byte offset) */
763 if ((nbytes
| offset
) & 1) {
769 /* Check to see if we're in unlock bypass mode */
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
;
780 flashptr
[0x555] = 0xAA; /* unlock 1 */
781 flashptr
[0x2AA] = 0x55; /* unlock 2 */
783 flashptr
[0x555] = 0xA0;
786 while ((stat
= flash_status(flashptr
)) == STATUS_BUSY
) {}
787 if (stat
!= STATUS_READY
) break;
791 if (stat
!= STATUS_READY
|| nbytes
!= 0) {
794 --dst
, --src
; /* back up */
795 goto again
; /* and retry the last word */
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
)
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 */
824 else if (t
== 0x04) { /* erase-suspend */
825 if (retry
--) goto again
; /* may have been write completion */
826 return STATUS_ERSUSP
;
829 if (d
& 0x20) { /* timeout */
830 if (retry
--) goto again
; /* may have been write completion */
831 return STATUS_TIMEOUT
;
838 if (retry
--) goto again
; /* may have been write completion */
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 */
854 fwp
= (WORD
*)get_flash_memptr(sector
);
856 flash_command(FLASH_AUTOSEL
,sector
,0,0);
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 */
874 fwp
= (WORD
*)get_flash_memptr(sector
);
876 flash_command(FLASH_AUTOSEL
,sector
,0,0);
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
)
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");
905 blk_start
--; // last blk, dec by 1
908 if( blk_start
== last_blk
)
910 printf("Address is too big.\n");
918 /************************************************************************/
919 /* The purpose of flash_get_total_size() is to return the total size of */
921 /************************************************************************/
922 int flash_get_total_size()