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 /************************************************************************/
33 #include "lib_types.h"
34 #include "lib_printf.h"
35 #include "lib_string.h"
36 #include "cfe_timer.h"
39 #include <linux/param.h>
40 #include <linux/sched.h>
41 #include <linux/timer.h>
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);
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;
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
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 */
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. */
101 /* The meminfo struct occupies 653 bytes of heap space, depending */
102 /* on the value of the define MAXSECTORS. Adjust to suit */
104 /*********************************************************************/
105 byte flash_init(void)
107 int i=0, j=0, count=0;
110 int flipCFIGeometry = FALSE;
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.
122 meminfo.bank1start = 0;
123 meminfo.bank2start = 0;
125 meminfo.sec[0].size = 8192;
126 meminfo.sec[0].base = 0x00000;
127 meminfo.sec[0].bank = 1;
129 flash_command(FLASH_RESET, 0, 0, 0);
131 device_id = flash_get_device_id();
138 flashFamily = FLASH_INTEL;
153 // add ST flash device id here
155 // add ST flash device id here
157 flashFamily = FLASH_AMD;
161 // add SST flash device id here
163 // add SST flash device id here
164 flashFamily = FLASH_SST;
167 printk("Flash memory not supported! Device id = %x\n", device_id);
171 if (flash_get_cfi(&query, 0, flashFamily) == -1) {
175 flash_get_cfi(&query, cfi_data_struct_29W160, flashFamily);
178 printk("CFI data structure not found. Device id = %x\n", device_id);
183 // need to determine if it top or bottom boot here
199 flipCFIGeometry = FALSE;
207 // add SST and ST flash device id here
210 // add SST and ST flash device id here
212 flipCFIGeometry = TRUE;
215 printk("Flash memory not supported! Device id = %x\n", device_id);
219 count=0;basecount=0L;
221 if (!flipCFIGeometry)
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;
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;
244 meminfo.nsect = count;
245 totalSize = meminfo.sec[count-1].base + meminfo.sec[count-1].size;
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)
260 for( i = 0; i < 3; i++ ) {
261 flash_command(FLASH_SERASE, sector, 0, 0);
262 if (flash_wait(sector, 0, 0xffff) == STATUS_READY)
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)
278 fwp = (byte *)flash_get_memptr(sector);
281 *buffer++ = *(fwp + offset);
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 */
295 /*********************************************************************/
296 int flash_write_buf(WORD sector, int offset, byte *buffer, int numbytes)
300 unsigned char *p = flash_get_memptr(sector) + offset;
302 /* After writing the flash block, compare the contents to the source
303 * buffer. Try to write the sector successfully up to three times.
305 for( i = 0; i < 3; i++ ) {
306 ret = flash_write(sector, offset, buffer, numbytes);
307 if( !memcmp( p, buffer, numbytes ) )
309 /* Erase and try again */
310 flash_sector_erase_int(sector);
311 printk("CFIFLASH: Rewriting sector %d\n", sector);
316 printk( "Flash write error. Verify failed\n" );
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)
328 return meminfo.nsect;
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)
339 return meminfo.sec[sector].size;
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 */
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 */
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)*/
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)
369 unsigned char *memptr = (unsigned char*)(FLASH_BASE_ADDR_REG + meminfo.sec[sector].base);
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)
381 int last_blk = flash_get_numsectors();
382 int relative_addr = addr - (int) FLASH_BASE_ADDR_REG;
384 for(blk_start=0, i=0; i < relative_addr && blk_start < last_blk; blk_start++)
385 i += flash_get_sector_size(blk_start);
387 if( i > relative_addr )
389 blk_start--; // last blk, dec by 1
392 if( blk_start == last_blk )
394 printk("Address is too big.\n");
401 /************************************************************************/
402 /* The purpose of flash_get_total_size() is to return the total size of */
404 /************************************************************************/
405 int flash_get_total_size()
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)
418 volatile UINT16 *flashptr;
419 volatile UINT16 *flashbase;
421 flashptr = (UINT16 *) flash_get_memptr(sector);
422 flashbase = (UINT16 *) flash_get_memptr(0);
424 switch (flashFamily) {
425 case FLASH_UNDEFINED:
426 /* These commands should work for AMD, Intel and SST flashes */
433 flashptr[0x5555] = 0xAA; /* unlock 1 */
434 flashptr[0x2AAA] = 0x55; /* unlock 2 */
435 flashptr[0x5555] = 0x90;
447 flashptr[0x555] = 0xAA; /* unlock 1 */
448 flashptr[0x2AA] = 0x55; /* unlock 2 */
449 flashptr[0x555] = 0x90;
452 flashptr[0x55] = 0x98;
455 flashptr[0x555] = 0xAA; /* unlock 1 */
456 flashptr[0x2AA] = 0x55; /* unlock 2 */
457 flashptr[0x555] = 0x20;
461 flashptr[offset/2] = data;
468 flashptr[0x555] = 0xAA; /* unlock 1 */
469 flashptr[0x2AA] = 0x55; /* unlock 2 */
470 flashptr[0x555] = 0x80;
471 flashptr[0x555] = 0xAA;
472 flashptr[0x2AA] = 0x55;
492 flashptr[offset/2] = data;
507 flashbase[0x5555] = 0xAA; /* unlock 1 */
508 flashbase[0x2AAA] = 0x55; /* unlock 2 */
509 flashbase[0x5555] = 0xf0;
512 flashbase[0x5555] = 0xAA; /* unlock 1 */
513 flashbase[0x2AAA] = 0x55; /* unlock 2 */
514 flashbase[0x5555] = 0x90;
517 flashbase[0x5555] = 0xAA; /* unlock 1 */
518 flashbase[0x2AAA] = 0x55; /* unlock 2 */
519 flashbase[0x5555] = 0x98;
524 flashbase[0x5555] = 0xAA; /* unlock 1 */
525 flashbase[0x2AAA] = 0x55; /* unlock 2 */
526 flashbase[0x5555] = 0xa0;
527 flashptr[offset/2] = data;
532 flashbase[0x5555] = 0xAA; /* unlock 1 */
533 flashbase[0x2AAA] = 0x55; /* unlock 2 */
534 flashbase[0x5555] = 0x80;
535 flashbase[0x5555] = 0xAA;
536 flashbase[0x2AAA] = 0x55;
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)
560 if ((nbytes | offset) & 1) {
564 flash_command(FLASH_UB, 0, 0, 0);
566 flash_command(FLASH_PROG, sector, offset, *src);
567 if (flash_wait(sector, offset, *src) != STATUS_READY)
573 flash_command(FLASH_UBRESET, 0, 0, 0);
575 return (byte*)src - buf;
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)
586 volatile UINT16 *flashptr; /* flash window */
589 flashptr = (UINT16 *) flash_get_memptr(sector);
591 if (flashFamily == FLASH_AMD || flashFamily == FLASH_SST) {
592 #if defined(_BCM96338_) || defined(CONFIG_BCM96338)
594 d1 = flashptr[offset/2];
597 } while (!(d1 & 0x20));
599 d1 = flashptr[offset/2];
602 flash_command(FLASH_RESET, 0, 0, 0);
603 return STATUS_TIMEOUT;
607 dlast = *flashptr; // read the first data word outside the loop
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.
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
617 d1 = *flashptr; /* read data */
618 d1 ^= *flashptr; /* read it again and see what toggled */
619 if (d1 == 0) /* no toggles, nothing's happening */
621 } while (!(d1 & 0x20));
624 d1 = *flashptr; /* read data */
625 d1 ^= *flashptr; /* read it again and see what toggled */
631 flash_command(FLASH_RESET, 0, 0, 0);
632 return STATUS_TIMEOUT;
635 } else if (flashFamily == FLASH_INTEL) {
637 /* Wait for completion */
638 while(!(*flashptr & 0x80));
639 if (*flashptr & 0x30) {
641 flash_command(FLASH_RESET, 0, 0, 0);
642 return STATUS_TIMEOUT;
645 flash_command(FLASH_RESET, 0, 0, 0);
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()
658 volatile UINT16 *fwp; /* flash window */
661 fwp = (UINT16 *)flash_get_memptr(0);
663 flash_command(FLASH_READ_ID, 0, 0, 0);
665 if (answer == ID_AM29LV320M) {
666 answer = *(fwp + 0xe);
667 answer = *(fwp + 0xf);
670 flash_command(FLASH_RESET, 0, 0, 0);
671 return( (UINT16) answer );
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)
685 volatile UINT16 *fwp; /* flash window */
688 flash_command(FLASH_CFIQUERY, 0, 0, 0);
691 fwp = (UINT16 *)flash_get_memptr(0);
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;
701 /* If not 'QRY', then we dont have a CFI enabled device in the socket */
702 if( fwp[0x10] != 'Q' &&
705 flash_command(FLASH_RESET, 0, 0, 0);
709 query->num_erase_blocks = fwp[0x2C];
710 if(flashFamily == FLASH_SST)
711 query->num_erase_blocks = 1;
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))]);
719 flash_command(FLASH_RESET, 0, 0, 0);