3 Copyright 2002 Broadcom Corp. All Rights Reserved.
5 This program is free software; you can distribute it and/or modify it
6 under the terms of the GNU General Public License (Version 2) as
7 published by the Free Software Foundation.
9 This program is distributed in the hope it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
20 ***************************************************************************
21 * File Name : bcm63xx_flash.c
23 * Description: This file contains the flash device driver APIs for bcm63xx board.
25 * Created on : 8/10/2002 seanl: use cfiflash.c, cfliflash.h (AMD specific)
27 ***************************************************************************/
32 #include <linux/capability.h>
33 #include <linux/slab.h>
34 #include <linux/errno.h>
35 #include <linux/module.h>
36 #include <asm/uaccess.h>
38 #include <bcm_map_part.h>
40 #define BCMTAG_EXE_USE
42 #include "flash_api.h"
43 #include "boardparms.h"
47 extern PFILE_TAG kerSysImageTagGet(void);
49 static FLASH_ADDR_INFO fInfo;
50 static int flashInitialized = 0;
52 void *retriedKmalloc(size_t size)
57 // try 1000 times before quit
58 while (((pBuf = kmalloc(size, GFP_KERNEL)) == NULL) && (tryCount++ < 1000))
60 current->state = TASK_INTERRUPTIBLE;
61 schedule_timeout(HZ/10);
66 memset(pBuf, 0, size);
71 void retriedKfree(void *pBuf)
76 /***************************************************************************
77 // Function Name: getCrc32
78 // Description : caculate the CRC 32 of the given data.
79 // Parameters : pdata - array of data.
80 // size - number of input data bytes.
81 // crc - either CRC32_INIT_VALUE or previous return value.
83 ****************************************************************************/
84 UINT32 getCrc32(byte *pdata, UINT32 size, UINT32 crc)
87 crc = (crc >> 8) ^ Crc32_table[(crc ^ *pdata++) & 0xff];
92 // get the nvram start addr
94 unsigned long get_nvram_start_addr(void)
96 return ((unsigned long)
97 (flash_get_memptr(fInfo.flash_nvram_start_blk) + fInfo.flash_nvram_blk_offset));
100 // get the scratch_pad start addr
102 unsigned long get_scratch_pad_start_addr(void)
104 return ((unsigned long)
105 (flash_get_memptr(fInfo.flash_scratch_pad_start_blk) + fInfo.flash_scratch_pad_blk_offset));
108 // Initialize the flash and fill out the fInfo structure
109 void kerSysFlashInit( void )
116 NVRAM_DATA nvramData;
117 UINT32 crc = CRC32_INIT_VALUE, savedCrc;
118 PFILE_TAG pTag = NULL;
119 unsigned long kernelEndAddr = 0;
120 unsigned long spAddr = 0;
122 if (flashInitialized)
125 flashInitialized = 1;
128 totalBlks = flash_get_numsectors();
129 totalSize = flash_get_total_size();
131 printk("Total Flash size: %dK with %d sectors\n", totalSize/1024, totalBlks);
133 /* nvram is always at the end of flash */
134 fInfo.flash_nvram_length = NVRAM_LENGTH;
135 fInfo.flash_nvram_start_blk = 0; /* always the first block */
136 fInfo.flash_nvram_number_blk = 1; /*always fits in the first block */
137 fInfo.flash_nvram_blk_offset = NVRAM_DATA_OFFSET;
140 memcpy((char *)&nvramData, (char *)get_nvram_start_addr(), sizeof(NVRAM_DATA));
141 savedCrc = nvramData.ulCheckSum;
142 nvramData.ulCheckSum = 0;
143 crc = getCrc32((char *)&nvramData, (UINT32) sizeof(NVRAM_DATA), crc);
145 BpSetBoardId( nvramData.szBoardId );
147 fInfo.flash_persistent_length = NVRAM_PSI_DEFAULT;
150 printk("***Board is not initialized****: Using the default PSI size: %d\n",
151 fInfo.flash_persistent_length);
155 unsigned long ulPsiSize;
156 if( BpGetPsiSize( &ulPsiSize ) == BP_SUCCESS )
157 fInfo.flash_persistent_length = ulPsiSize;
160 printk("***Board id is not set****: Using the default PSI size: %d\n",
161 fInfo.flash_persistent_length);
165 fInfo.flash_persistent_length *= ONEK;
166 startAddr = totalSize - fInfo.flash_persistent_length;
167 fInfo.flash_persistent_start_blk = flash_get_blk(startAddr+FLASH_BASE);
168 fInfo.flash_persistent_number_blk = totalBlks - fInfo.flash_persistent_start_blk;
169 // save abs SP address (Scratch Pad). it is before PSI
170 spAddr = startAddr - SP_MAX_LEN ;
171 // find out the offset in the start_blk
173 for (i = fInfo.flash_persistent_start_blk;
174 i < (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk); i++)
176 usedBlkSize += flash_get_sector_size((unsigned short) i);
178 fInfo.flash_persistent_blk_offset = usedBlkSize - fInfo.flash_persistent_length;
180 // get the info for sp
181 if (!(pTag = kerSysImageTagGet()))
183 printk("Failed to read image tag from flash\n");
186 kernelEndAddr = (unsigned long)simple_strtoul(pTag->kernelAddress,NULL,10)+ \
187 (unsigned long) simple_strtoul(pTag->kernelLen, NULL, 10) + BOOT_OFFSET;
189 // make suer sp does not share kernel block
190 fInfo.flash_scratch_pad_start_blk = flash_get_blk(spAddr+FLASH_BASE);
191 if (fInfo.flash_scratch_pad_start_blk != flash_get_blk(kernelEndAddr))
193 fInfo.flash_scratch_pad_length = SP_MAX_LEN;
194 if (fInfo.flash_persistent_start_blk == fInfo.flash_scratch_pad_start_blk) // share blk
196 #if 0 /* do not used scratch pad unless it's in its own sector */
197 printk("Scratch pad is not used for this flash part.\n");
198 fInfo.flash_scratch_pad_length = 0; // no sp
199 #else /* allow scratch pad to share a sector with another section such as PSI */
200 fInfo.flash_scratch_pad_number_blk = 1;
201 fInfo.flash_scratch_pad_blk_offset = fInfo.flash_persistent_blk_offset - fInfo.flash_scratch_pad_length;
204 else // on different blk
206 fInfo.flash_scratch_pad_number_blk = fInfo.flash_persistent_start_blk\
207 - fInfo.flash_scratch_pad_start_blk;
208 // find out the offset in the start_blk
210 for (i = fInfo.flash_scratch_pad_start_blk;
211 i < (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk); i++)
212 usedBlkSize += flash_get_sector_size((unsigned short) i);
213 fInfo.flash_scratch_pad_blk_offset = usedBlkSize - fInfo.flash_scratch_pad_length;
218 printk("No flash for scratch pad!\n");
219 fInfo.flash_scratch_pad_length = 0; // no sp
222 #if defined(DEBUG_FLASH)
223 printk("fInfo.flash_scratch_pad_start_blk = %d\n", fInfo.flash_scratch_pad_start_blk);
224 printk("fInfo.flash_scratch_pad_number_blk = %d\n", fInfo.flash_scratch_pad_number_blk);
225 printk("fInfo.flash_scratch_pad_length = 0x%x\n", fInfo.flash_scratch_pad_length);
226 printk("fInfo.flash_scratch_pad_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_scratch_pad_blk_offset);
228 printk("fInfo.flash_nvram_start_blk = %d\n", fInfo.flash_nvram_start_blk);
229 printk("fInfo.flash_nvram_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_nvram_blk_offset);
230 printk("fInfo.flash_nvram_number_blk = %d\n", fInfo.flash_nvram_number_blk);
232 printk("psi startAddr = %x\n", startAddr+FLASH_BASE);
233 printk("fInfo.flash_persistent_start_blk = %d\n", fInfo.flash_persistent_start_blk);
234 printk("fInfo.flash_persistent_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_persistent_blk_offset);
235 printk("fInfo.flash_persistent_number_blk = %d\n", fInfo.flash_persistent_number_blk);
242 /***********************************************************************
243 * Function Name: kerSysFlashAddrInfoGet
244 * Description : Fills in a structure with information about the NVRAM
245 * and persistent storage sections of flash memory.
246 * Fro physmap.c to mount the fs vol.
248 ***********************************************************************/
249 void kerSysFlashAddrInfoGet(PFLASH_ADDR_INFO pflash_addr_info)
251 pflash_addr_info->flash_nvram_blk_offset = fInfo.flash_nvram_blk_offset;
252 pflash_addr_info->flash_nvram_length = fInfo.flash_nvram_length;
253 pflash_addr_info->flash_nvram_number_blk = fInfo.flash_nvram_number_blk;
254 pflash_addr_info->flash_nvram_start_blk = fInfo.flash_nvram_start_blk;
255 pflash_addr_info->flash_persistent_blk_offset = fInfo.flash_persistent_blk_offset;
256 pflash_addr_info->flash_persistent_length = fInfo.flash_persistent_length;
257 pflash_addr_info->flash_persistent_number_blk = fInfo.flash_persistent_number_blk;
258 pflash_addr_info->flash_persistent_start_blk = fInfo.flash_persistent_start_blk;
262 // get shared blks into *** pTempBuf *** which has to be released bye the caller!
263 // return: if pTempBuf != NULL, poits to the data with the dataSize of the buffer
266 static char *getSharedBlks(int start_blk, int end_blk)
271 char *pTempBuf = NULL;
274 for (i = start_blk; i < end_blk; i++)
275 usedBlkSize += flash_get_sector_size((unsigned short) i);
277 #if defined(DEBUG_FLASH)
278 printk("usedBlkSize = %d\n", usedBlkSize);
281 if ((pTempBuf = (char *) retriedKmalloc(usedBlkSize)) == NULL)
283 printk("failed to allocate memory with size: %d\n", usedBlkSize);
288 for (i = start_blk; i < end_blk; i++)
290 sect_size = flash_get_sector_size((unsigned short) i);
292 #if defined(DEBUG_FLASH)
293 printk("i = %d, sect_size = %d, end_blk = %d\n", i, sect_size, end_blk);
295 flash_read_buf((unsigned short)i, 0, pBuf, sect_size);
304 // Set the pTempBuf to flash from start_blk to end_blk
308 static int setSharedBlks(int start_blk, int end_blk, char *pTempBuf)
313 char *pBuf = pTempBuf;
315 for (i = start_blk; i < end_blk; i++)
317 sect_size = flash_get_sector_size((unsigned short) i);
318 flash_sector_erase_int(i);
319 if (flash_write_buf(i, 0, pBuf, sect_size) != sect_size)
321 printk("Error writing flash sector %d.", i);
333 /*******************************************************************************
335 *******************************************************************************/
341 int kerSysNvRamGet(char *string, int strLen, int offset)
345 if (!flashInitialized)
348 if (strLen > NVRAM_LENGTH)
351 if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
352 (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
355 // get string off the memory buffer
356 memcpy(string, (pBuf + fInfo.flash_nvram_blk_offset + offset), strLen);
368 int kerSysNvRamSet(char *string, int strLen, int offset)
373 if (strLen > NVRAM_LENGTH)
376 if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
377 (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
380 // set string to the memory buffer
381 memcpy((pBuf + fInfo.flash_nvram_blk_offset + offset), string, strLen);
383 if (setSharedBlks(fInfo.flash_nvram_start_blk,
384 (fInfo.flash_nvram_number_blk + fInfo.flash_nvram_start_blk), pBuf) != 0)
393 /***********************************************************************
394 * Function Name: kerSysEraseNvRam
395 * Description : Erase the NVRAM storage section of flash memory.
396 * Returns : 1 -- ok, 0 -- fail
397 ***********************************************************************/
398 int kerSysEraseNvRam(void)
401 char *tempStorage = retriedKmalloc(NVRAM_LENGTH);
403 // just write the whole buf with '0xff' to the flash
408 memset(tempStorage, 0xff, NVRAM_LENGTH);
409 if (kerSysNvRamSet(tempStorage, NVRAM_LENGTH, 0) != 0)
411 retriedKfree(tempStorage);
418 /*******************************************************************************
420 *******************************************************************************/
425 int kerSysPersistentGet(char *string, int strLen, int offset)
429 if (strLen > fInfo.flash_persistent_length)
432 if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
433 (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
436 // get string off the memory buffer
437 memcpy(string, (pBuf + fInfo.flash_persistent_blk_offset + offset), strLen);
449 int kerSysPersistentSet(char *string, int strLen, int offset)
454 if (strLen > fInfo.flash_persistent_length)
457 if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
458 (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
461 // set string to the memory buffer
462 memcpy((pBuf + fInfo.flash_persistent_blk_offset + offset), string, strLen);
463 // USR9108 add two terminating zeros to the end of the string
464 if ( strLen <= fInfo.flash_persistent_length - 2 )
465 memcpy((pBuf + fInfo.flash_persistent_blk_offset + offset + strLen), "\0\0", 2);
467 if (setSharedBlks(fInfo.flash_persistent_start_blk,
468 (fInfo.flash_persistent_number_blk + fInfo.flash_persistent_start_blk), pBuf) != 0)
480 // !0 - the sector number fail to be flashed (should not be 0)
481 int kerSysBcmImageSet( int flash_start_addr, char *string, int size)
487 char *pTempBuf = NULL;
490 blk_start = flash_get_blk(flash_start_addr);
494 if (flash_start_addr == FLASH_BASE && size > FLASH_LENGTH_BOOT_ROM)
497 /* write image to flash memory */
500 sect_size = flash_get_sector_size(blk_start);
501 // NOTE: for memory problem in multiple PVC configuration, temporary get rid of kmalloc this 64K for now.
502 // if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
504 // printk("Failed to allocate memory with size: %d. Reset the router...\n", sect_size);
505 // kerSysMipsSoftReset(); // reset the board right away.
507 // for whole image, no check on psi
508 if (!whole_image && blk_start == fInfo.flash_persistent_start_blk) // share the blk with psi
510 if (size > (sect_size - fInfo.flash_persistent_length))
512 printk("Image is too big\n");
513 break; // image is too big. Can not overwrite to nvram
515 if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
517 printk("Failed to allocate memory with size: %d. Reset the router...\n", sect_size);
518 kerSysMipsSoftReset(); // reset the board right away.
520 flash_read_buf((unsigned short)blk_start, 0, pTempBuf, sect_size);
521 if (copy_from_user((void *)pTempBuf,(void *)string, size) != 0)
523 flash_sector_erase_int(blk_start); // erase blk before flash
524 if (flash_write_buf(blk_start, 0, pTempBuf, sect_size) == sect_size)
525 size = 0; // break out and say all is ok
526 retriedKfree(pTempBuf);
530 flash_sector_erase_int(blk_start); // erase blk before flash
532 if (sect_size > size)
539 if ((i = flash_write_buf(blk_start, 0, string, sect_size)) != sect_size) {
549 // If flashing a whole image, erase to end of flash.
550 int total_blks = flash_get_numsectors();
551 while( blk_start < total_blks )
553 flash_sector_erase_int(blk_start);
558 retriedKfree(pTempBuf);
563 sts = blk_start; // failed to flash this sector
568 /*******************************************************************************
570 *******************************************************************************/
571 // get sp data. NOTE: memcpy work here -- not using copy_from/to_user
573 // >0 - number of bytes copied to tokBuf
575 int kerSysScratchPadGet(char *tokenId, char *tokBuf, int bufLen)
577 PSP_TOKEN pToken = NULL;
579 char *pShareBuf = NULL;
580 char *startPtr = NULL;
584 if (fInfo.flash_scratch_pad_length == 0)
587 if( bufLen >= (fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
590 printk("Exceed scratch pad space by %d\n", bufLen -
591 fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
596 if( (pShareBuf = getSharedBlks(fInfo.flash_scratch_pad_start_blk,
597 (fInfo.flash_scratch_pad_start_blk +
598 fInfo.flash_scratch_pad_number_blk))) == NULL )
603 // pBuf points to SP buf
604 pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;
606 if(memcmp(((PSP_HEADER)pBuf)->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0)
608 printk("Scratch pad is not initialized.\n");
612 // search for the token
613 usedLen = sizeof(SP_HEADER);
614 startPtr = pBuf + sizeof(SP_HEADER);
615 pToken = (PSP_TOKEN) startPtr;
616 while( pToken->tokenName[0] != '\0' && pToken->tokenLen > 0 &&
617 pToken->tokenLen < fInfo.flash_scratch_pad_length &&
618 usedLen < fInfo.flash_scratch_pad_length )
621 if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
623 sts = pToken->tokenLen;
624 memcpy(tokBuf, startPtr + sizeof(SP_TOKEN), sts);
628 usedLen += ((pToken->tokenLen + 0x03) & ~0x03);
629 startPtr += sizeof(SP_TOKEN) + ((pToken->tokenLen + 0x03) & ~0x03);
630 pToken = (PSP_TOKEN) startPtr;
633 retriedKfree(pShareBuf);
639 // set sp. NOTE: memcpy work here -- not using copy_from/to_user
643 int kerSysScratchPadSet(char *tokenId, char *tokBuf, int bufLen)
645 PSP_TOKEN pToken = NULL;
646 char *pShareBuf = NULL;
653 if (fInfo.flash_scratch_pad_length == 0)
656 if( bufLen >= fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
659 printk("Scratch pad overflow by %d bytes. Information not saved.\n",
660 bufLen - fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) -
665 if( (pShareBuf = getSharedBlks( fInfo.flash_scratch_pad_start_blk,
666 (fInfo.flash_scratch_pad_start_blk +
667 fInfo.flash_scratch_pad_number_blk) )) == NULL )
672 // pBuf points to SP buf
673 pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;
676 memset((char *)&SPHead, 0, sizeof(SP_HEADER));
677 memcpy(SPHead.SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN);
678 SPHead.SPVersion = SP_VERSION;
681 memset((char*)&SPToken, 0, sizeof(SP_TOKEN));
682 strncpy(SPToken.tokenName, tokenId, TOKEN_NAME_LEN - 1);
683 SPToken.tokenLen = bufLen;
685 if(memcmp(((PSP_HEADER)pBuf)->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0)
687 // new sp, so just flash the token
688 printk("No scratch pad found. Initialize scratch pad...\n");
689 memcpy(pBuf, (char *)&SPHead, sizeof(SP_HEADER));
690 curPtr = pBuf + sizeof(SP_HEADER);
691 memcpy(curPtr, (char *)&SPToken, sizeof(SP_TOKEN));
692 curPtr += sizeof(SP_TOKEN);
694 memcpy(curPtr, tokBuf, bufLen);
703 /* Calculate the used length. */
704 usedLen = sizeof(SP_HEADER);
705 curPtr = pBuf + sizeof(SP_HEADER);
706 pToken = (PSP_TOKEN) curPtr;
707 skipLen = (pToken->tokenLen + 0x03) & ~0x03;
708 while( pToken->tokenName[0] >= 'A' && pToken->tokenName[0] <= 'z' &&
709 strlen(pToken->tokenName) < TOKEN_NAME_LEN &&
710 pToken->tokenLen > 0 &&
711 pToken->tokenLen < fInfo.flash_scratch_pad_length &&
712 usedLen < fInfo.flash_scratch_pad_length )
714 usedLen += sizeof(SP_TOKEN) + skipLen;
715 curPtr += sizeof(SP_TOKEN) + skipLen;
716 pToken = (PSP_TOKEN) curPtr;
717 skipLen = (pToken->tokenLen + 0x03) & ~0x03;
720 if( usedLen + SPToken.tokenLen + sizeof(SP_TOKEN) >
721 fInfo.flash_scratch_pad_length )
723 printk("Scratch pad overflow by %d bytes. Information not saved.\n",
724 (usedLen + SPToken.tokenLen + sizeof(SP_TOKEN)) -
725 fInfo.flash_scratch_pad_length);
729 curPtr = pBuf + sizeof(SP_HEADER);
730 curLen = sizeof(SP_HEADER);
731 while( curLen < usedLen )
733 pToken = (PSP_TOKEN) curPtr;
734 skipLen = (pToken->tokenLen + 0x03) & ~0x03;
735 if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
737 // The token id already exists.
738 if( tokBuf && pToken->tokenLen == bufLen )
740 // The length of the new data and the existing data is the
741 // same. Overwrite the existing data.
742 memcpy((curPtr+sizeof(SP_TOKEN)), tokBuf, bufLen);
747 // The length of the new data and the existing data is
748 // different. Shift the rest of the scratch pad to this
749 // token's location and put this token's data at the end.
750 char *nextPtr = curPtr + sizeof(SP_TOKEN) + skipLen;
751 int copyLen = usedLen - (curLen+sizeof(SP_TOKEN) + skipLen);
752 memcpy( curPtr, nextPtr, copyLen );
753 memset( curPtr + copyLen, 0x00,
754 fInfo.flash_scratch_pad_length - (curLen + copyLen) );
755 usedLen -= sizeof(SP_TOKEN) + skipLen;
761 curPtr += sizeof(SP_TOKEN) + skipLen;
762 curLen += sizeof(SP_TOKEN) + skipLen;
769 memcpy( pBuf + usedLen, &SPToken, sizeof(SP_TOKEN) );
770 memcpy( pBuf + usedLen + sizeof(SP_TOKEN), tokBuf, bufLen );
772 memcpy( pBuf, &SPHead, sizeof(SP_HEADER) );
775 } // else if not new sp
777 sts = setSharedBlks(fInfo.flash_scratch_pad_start_blk,
778 (fInfo.flash_scratch_pad_number_blk + fInfo.flash_scratch_pad_start_blk),
781 retriedKfree(pShareBuf);
788 int kerSysFlashSizeGet(void)
790 return flash_get_total_size();
793 int kerSysMemoryMappedFlashSizeGet(void)
795 return( flash_get_total_memory_mapped_size() );
798 unsigned long kerSysReadFromFlash( void *toaddr, unsigned long fromaddr,
801 int sect = flash_get_blk((int) fromaddr);
802 unsigned char *start = flash_get_memptr(sect);
803 flash_read_buf( sect, (int) fromaddr - (int) start, toaddr, len );