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
43 #include "boardparms.h"
47 static FLASH_ADDR_INFO fInfo;
48 static int flashInitialized = 0;
50 void *retriedKmalloc(size_t size)
55 // try 1000 times before quit
56 while (((pBuf = kmalloc(size, GFP_KERNEL)) == NULL) && (tryCount++ < 1000))
58 current->state = TASK_INTERRUPTIBLE;
59 schedule_timeout(HZ/10);
64 memset(pBuf, 0, size);
69 void retriedKfree(void *pBuf)
74 /***************************************************************************
75 // Function Name: getCrc32
76 // Description : caculate the CRC 32 of the given data.
77 // Parameters : pdata - array of data.
78 // size - number of input data bytes.
79 // crc - either CRC32_INIT_VALUE or previous return value.
81 ****************************************************************************/
82 UINT32 getCrc32(byte *pdata, UINT32 size, UINT32 crc)
85 crc = (crc >> 8) ^ Crc32_table[(crc ^ *pdata++) & 0xff];
90 // get the nvram start addr
92 unsigned long get_nvram_start_addr(void)
94 return ((unsigned long)
95 (flash_get_memptr(fInfo.flash_nvram_start_blk) + fInfo.flash_nvram_blk_offset));
98 // get the scratch_pad start addr
100 unsigned long get_scratch_pad_start_addr(void)
102 return ((unsigned long)
103 (flash_get_memptr(fInfo.flash_scratch_pad_start_blk) + fInfo.flash_scratch_pad_blk_offset));
108 /* *********************************************************************
109 * kerSysImageTagGet()
114 * point to tag -- Found
116 ********************************************************************* */
117 PFILE_TAG kerSysImageTagGet(void)
120 int totalBlks = flash_get_numsectors();
122 unsigned char *sectAddr;
125 #if defined(DEBUG_FLASH)
126 printk("totalblks in tagGet=%d\n", totalBlks);
129 // start from 2nd blk, assume 1st one is always CFE
130 for (i = 1; i < totalBlks; i++)
132 sectAddr = flash_get_memptr((byte) i);
133 crc = CRC32_INIT_VALUE;
134 crc = getCrc32(sectAddr, (UINT32)TAG_LEN-TOKEN_LEN, crc);
135 pTag = (PFILE_TAG) sectAddr;
137 #if defined(DEBUG_FLASH)
138 printk("Check Tag crc on blk [%d]\n", i);
141 if (crc == (UINT32)(*(UINT32*)(pTag->tagValidationToken)))
145 return (PFILE_TAG) NULL;
148 // Initialize the flash and fill out the fInfo structure
149 void kerSysFlashInit( void )
156 NVRAM_DATA nvramData;
157 UINT32 crc = CRC32_INIT_VALUE, savedCrc;
158 PFILE_TAG pTag = NULL;
159 unsigned long kernelEndAddr = 0;
160 unsigned long spAddr = 0;
162 if (flashInitialized)
165 flashInitialized = 1;
168 totalBlks = flash_get_numsectors();
169 totalSize = flash_get_total_size();
171 printk("Total Flash size: %dK with %d sectors\n", totalSize/1024, totalBlks);
173 /* nvram is always at the end of flash */
174 fInfo.flash_nvram_length = FLASH45_LENGTH_NVRAM;
175 fInfo.flash_nvram_start_blk = 0; /* always the first block */
176 fInfo.flash_nvram_number_blk = 1; /*always fits in the first block */
177 fInfo.flash_nvram_blk_offset = NVRAM_DATA_OFFSET;
180 memcpy((char *)&nvramData, (char *)get_nvram_start_addr(), sizeof(NVRAM_DATA));
181 savedCrc = nvramData.ulCheckSum;
182 nvramData.ulCheckSum = 0;
183 crc = getCrc32((char *)&nvramData, (UINT32) sizeof(NVRAM_DATA), crc);
185 BpSetBoardId( nvramData.szBoardId );
187 fInfo.flash_persistent_length = NVRAM_PSI_DEFAULT;
190 printk("***Board is not initialized****: Using the default PSI size: %d\n",
191 fInfo.flash_persistent_length);
195 unsigned long ulPsiSize;
196 if( BpGetPsiSize( &ulPsiSize ) == BP_SUCCESS )
197 fInfo.flash_persistent_length = ulPsiSize;
200 printk("***Board id is not set****: Using the default PSI size: %d\n",
201 fInfo.flash_persistent_length);
205 fInfo.flash_persistent_length *= ONEK;
206 startAddr = totalSize - fInfo.flash_persistent_length;
207 fInfo.flash_persistent_start_blk = flash_get_blk(startAddr+FLASH_BASE_ADDR_REG);
208 fInfo.flash_persistent_number_blk = totalBlks - fInfo.flash_persistent_start_blk;
209 // save abs SP address (Scratch Pad). it is before PSI
210 spAddr = startAddr - SP_MAX_LEN ;
211 // find out the offset in the start_blk
213 for (i = fInfo.flash_persistent_start_blk;
214 i < (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk); i++)
216 usedBlkSize += flash_get_sector_size((byte) i);
218 fInfo.flash_persistent_blk_offset = usedBlkSize - fInfo.flash_persistent_length;
220 // get the info for sp
221 if (!(pTag = kerSysImageTagGet()))
223 printk("Failed to read image tag from flash\n");
226 kernelEndAddr = (unsigned long) simple_strtoul(pTag->kernelAddress, NULL, 10) + \
227 (unsigned long) simple_strtoul(pTag->kernelLen, NULL, 10);
229 // make suer sp does not share kernel block
230 fInfo.flash_scratch_pad_start_blk = flash_get_blk(spAddr+FLASH_BASE_ADDR_REG);
231 if (fInfo.flash_scratch_pad_start_blk != flash_get_blk(kernelEndAddr))
233 fInfo.flash_scratch_pad_length = SP_MAX_LEN;
234 if (fInfo.flash_persistent_start_blk == fInfo.flash_scratch_pad_start_blk) // share blk
236 #if 1 /* do not used scratch pad unless it's in its own sector */
237 printk("Scratch pad is not used for this flash part.\n");
238 fInfo.flash_scratch_pad_length = 0; // no sp
239 #else /* allow scratch pad to share a sector with another section such as PSI */
240 fInfo.flash_scratch_pad_number_blk = 1;
241 fInfo.flash_scratch_pad_blk_offset = fInfo.flash_persistent_blk_offset - fInfo.flash_scratch_pad_length;
244 else // on different blk
246 fInfo.flash_scratch_pad_number_blk = fInfo.flash_persistent_start_blk\
247 - fInfo.flash_scratch_pad_start_blk;
248 // find out the offset in the start_blk
250 for (i = fInfo.flash_scratch_pad_start_blk;
251 i < (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk); i++)
252 usedBlkSize += flash_get_sector_size((byte) i);
253 fInfo.flash_scratch_pad_blk_offset = usedBlkSize - fInfo.flash_scratch_pad_length;
258 printk("No flash for scratch pad!\n");
259 fInfo.flash_scratch_pad_length = 0; // no sp
262 #if defined(DEBUG_FLASH)
263 printk("fInfo.flash_scratch_pad_start_blk = %d\n", fInfo.flash_scratch_pad_start_blk);
264 printk("fInfo.flash_scratch_pad_number_blk = %d\n", fInfo.flash_scratch_pad_number_blk);
265 printk("fInfo.flash_scratch_pad_length = 0x%x\n", fInfo.flash_scratch_pad_length);
266 printk("fInfo.flash_scratch_pad_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_scratch_pad_blk_offset);
268 printk("fInfo.flash_nvram_start_blk = %d\n", fInfo.flash_nvram_start_blk);
269 printk("fInfo.flash_nvram_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_nvram_blk_offset);
270 printk("fInfo.flash_nvram_number_blk = %d\n", fInfo.flash_nvram_number_blk);
272 printk("psi startAddr = %x\n", startAddr+FLASH_BASE_ADDR_REG);
273 printk("fInfo.flash_persistent_start_blk = %d\n", fInfo.flash_persistent_start_blk);
274 printk("fInfo.flash_persistent_blk_offset = 0x%x\n", (unsigned int)fInfo.flash_persistent_blk_offset);
275 printk("fInfo.flash_persistent_number_blk = %d\n", fInfo.flash_persistent_number_blk);
282 /***********************************************************************
283 * Function Name: kerSysFlashAddrInfoGet
284 * Description : Fills in a structure with information about the NVRAM
285 * and persistent storage sections of flash memory.
286 * Fro physmap.c to mount the fs vol.
288 ***********************************************************************/
289 void kerSysFlashAddrInfoGet(PFLASH_ADDR_INFO pflash_addr_info)
291 pflash_addr_info->flash_nvram_blk_offset = fInfo.flash_nvram_blk_offset;
292 pflash_addr_info->flash_nvram_length = fInfo.flash_nvram_length;
293 pflash_addr_info->flash_nvram_number_blk = fInfo.flash_nvram_number_blk;
294 pflash_addr_info->flash_nvram_start_blk = fInfo.flash_nvram_start_blk;
295 pflash_addr_info->flash_persistent_blk_offset = fInfo.flash_persistent_blk_offset;
296 pflash_addr_info->flash_persistent_length = fInfo.flash_persistent_length;
297 pflash_addr_info->flash_persistent_number_blk = fInfo.flash_persistent_number_blk;
298 pflash_addr_info->flash_persistent_start_blk = fInfo.flash_persistent_start_blk;
302 // get shared blks into *** pTempBuf *** which has to be released bye the caller!
303 // return: if pTempBuf != NULL, poits to the data with the dataSize of the buffer
306 static char *getSharedBlks(int start_blk, int end_blk)
311 char *pTempBuf = NULL;
314 for (i = start_blk; i < end_blk; i++)
315 usedBlkSize += flash_get_sector_size((byte) i);
317 #if defined(DEBUG_FLASH)
318 printk("usedBlkSize = %d\n", usedBlkSize);
321 if ((pTempBuf = (char *) retriedKmalloc(usedBlkSize)) == NULL)
323 printk("failed to allocate memory with size: %d\n", usedBlkSize);
328 for (i = start_blk; i < end_blk; i++)
330 sect_size = flash_get_sector_size((byte) i);
332 #if defined(DEBUG_FLASH)
333 printk("i = %d, sect_size = %d, end_blk = %d\n", i, sect_size, end_blk);
335 flash_read_buf((byte)i, 0, pBuf, sect_size);
344 // Set the pTempBuf to flash from start_blk to end_blk
348 static int setSharedBlks(int start_blk, int end_blk, char *pTempBuf)
353 char *pBuf = pTempBuf;
355 for (i = start_blk; i < end_blk; i++)
357 sect_size = flash_get_sector_size((byte) i);
358 flash_sector_erase_int(i);
359 if (flash_write_buf(i, 0, pBuf, sect_size) != sect_size)
361 printk("Error writing flash sector %d.", i);
373 /*******************************************************************************
375 *******************************************************************************/
381 int kerSysNvRamGet(char *string, int strLen, int offset)
385 if (!flashInitialized)
388 if (strLen > FLASH45_LENGTH_NVRAM)
391 if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
392 (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
395 // get string off the memory buffer
396 memcpy(string, (pBuf + fInfo.flash_nvram_blk_offset + offset), strLen);
408 int kerSysNvRamSet(char *string, int strLen, int offset)
413 if (strLen > FLASH45_LENGTH_NVRAM)
416 if ((pBuf = getSharedBlks(fInfo.flash_nvram_start_blk,
417 (fInfo.flash_nvram_start_blk + fInfo.flash_nvram_number_blk))) == NULL)
420 // set string to the memory buffer
421 memcpy((pBuf + fInfo.flash_nvram_blk_offset + offset), string, strLen);
423 if (setSharedBlks(fInfo.flash_nvram_start_blk,
424 (fInfo.flash_nvram_number_blk + fInfo.flash_nvram_start_blk), pBuf) != 0)
433 /***********************************************************************
434 * Function Name: kerSysEraseNvRam
435 * Description : Erase the NVRAM storage section of flash memory.
436 * Returns : 1 -- ok, 0 -- fail
437 ***********************************************************************/
438 int kerSysEraseNvRam(void)
441 char *tempStorage = retriedKmalloc(FLASH45_LENGTH_NVRAM);
443 // just write the whole buf with '0xff' to the flash
448 memset(tempStorage, 0xff, FLASH45_LENGTH_NVRAM);
449 if (kerSysNvRamSet(tempStorage, FLASH45_LENGTH_NVRAM, 0) != 0)
451 retriedKfree(tempStorage);
458 /*******************************************************************************
460 *******************************************************************************/
465 int kerSysPersistentGet(char *string, int strLen, int offset)
469 if (strLen > fInfo.flash_persistent_length)
472 if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
473 (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
476 // get string off the memory buffer
477 memcpy(string, (pBuf + fInfo.flash_persistent_blk_offset + offset), strLen);
489 int kerSysPersistentSet(char *string, int strLen, int offset)
494 if (strLen > fInfo.flash_persistent_length)
497 if ((pBuf = getSharedBlks(fInfo.flash_persistent_start_blk,
498 (fInfo.flash_persistent_start_blk + fInfo.flash_persistent_number_blk))) == NULL)
501 // set string to the memory buffer
502 memcpy((pBuf + fInfo.flash_persistent_blk_offset + offset), string, strLen);
504 if (setSharedBlks(fInfo.flash_persistent_start_blk,
505 (fInfo.flash_persistent_number_blk + fInfo.flash_persistent_start_blk), pBuf) != 0)
517 // !0 - the sector number fail to be flashed (should not be 0)
518 int kerSysBcmImageSet( int flash_start_addr, char *string, int size)
524 char *pTempBuf = NULL;
527 blk_start = flash_get_blk(flash_start_addr);
531 if (flash_start_addr == FLASH_BASE && size > FLASH45_LENGTH_BOOT_ROM)
534 /* write image to flash memory */
537 sect_size = flash_get_sector_size(blk_start);
538 // NOTE: for memory problem in multiple PVC configuration, temporary get rid of kmalloc this 64K for now.
539 // if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
541 // printk("Failed to allocate memory with size: %d. Reset the router...\n", sect_size);
542 // kerSysMipsSoftReset(); // reset the board right away.
544 // for whole image, no check on psi
545 if (!whole_image && blk_start == fInfo.flash_persistent_start_blk) // share the blk with psi
547 if (size > (sect_size - fInfo.flash_persistent_length))
549 printk("Image is too big\n");
550 break; // image is too big. Can not overwrite to nvram
552 if ((pTempBuf = (char *)retriedKmalloc(sect_size)) == NULL)
554 printk("Failed to allocate memory with size: %d. Reset the router...\n", sect_size);
555 kerSysMipsSoftReset(); // reset the board right away.
557 flash_read_buf((byte)blk_start, 0, pTempBuf, sect_size);
558 if (copy_from_user((void *)pTempBuf,(void *)string, size) != 0)
560 flash_sector_erase_int(blk_start); // erase blk before flash
561 if (flash_write_buf(blk_start, 0, pTempBuf, sect_size) == sect_size)
562 size = 0; // break out and say all is ok
563 retriedKfree(pTempBuf);
567 flash_sector_erase_int(blk_start); // erase blk before flash
569 if (sect_size > size)
576 if ((i = flash_write_buf(blk_start, 0, string, sect_size)) != sect_size) {
577 printk("flash image error.\n");
587 // If flashing a whole image, erase to end of flash.
588 int total_blks = flash_get_numsectors();
589 while( blk_start < total_blks )
591 flash_sector_erase_int(blk_start);
596 retriedKfree(pTempBuf);
601 sts = blk_start; // failed to flash this sector
606 /*******************************************************************************
608 *******************************************************************************/
609 // get sp data. NOTE: memcpy work here -- not using copy_from/to_user
613 int kerSysScratchPadGet(char *tokenId, char *tokBuf, int bufLen)
615 PSP_HEADER pHead = NULL;
616 PSP_TOKEN pToken = NULL;
618 char *pShareBuf = NULL;
619 char *startPtr = NULL;
621 char *spEndPtr = NULL;
624 if (fInfo.flash_scratch_pad_length == 0)
627 if (bufLen >= (fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) - sizeof(SP_TOKEN)))
629 printk("Exceed scratch pad space by %d\n", bufLen - fInfo.flash_scratch_pad_length \
630 - sizeof(SP_HEADER) - sizeof(SP_TOKEN));
634 if ((pShareBuf = getSharedBlks(fInfo.flash_scratch_pad_start_blk,
635 (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk))) == NULL)
638 // pBuf points to SP buf
639 pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;
641 pHead = (PSP_HEADER) pBuf;
642 if (memcmp(pHead->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0)
644 printk("Scrap pad is not initialized.\n");
648 // search up to SPUsedLen for the token
649 startPtr = pBuf + sizeof(SP_HEADER);
650 endPtr = pBuf + pHead->SPUsedLen;
651 spEndPtr = pBuf + SP_MAX_LEN;
652 while (startPtr < endPtr && startPtr < spEndPtr)
654 pToken = (PSP_TOKEN) startPtr;
655 if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
657 memcpy(tokBuf, startPtr + sizeof(SP_TOKEN), bufLen);
662 startPtr += sizeof(SP_TOKEN) + pToken->tokenLen;
665 retriedKfree(pShareBuf);
671 // set sp. NOTE: memcpy work here -- not using copy_from/to_user
675 int kerSysScratchPadSet(char *tokenId, char *tokBuf, int bufLen)
677 PSP_TOKEN pToken = NULL;
678 PSP_HEADER pHead = NULL;
679 char *pShareBuf = NULL;
686 if (fInfo.flash_scratch_pad_length == 0)
689 if (bufLen >= (fInfo.flash_scratch_pad_length - sizeof(SP_HEADER) - sizeof(SP_TOKEN)))
691 printk("Exceed scratch pad space by %d\n", bufLen - fInfo.flash_scratch_pad_length \
692 - sizeof(SP_HEADER) - sizeof(SP_TOKEN));
696 if ((pShareBuf = getSharedBlks(fInfo.flash_scratch_pad_start_blk,
697 (fInfo.flash_scratch_pad_start_blk + fInfo.flash_scratch_pad_number_blk))) == NULL)
700 // pBuf points to SP buf
701 pBuf = pShareBuf + fInfo.flash_scratch_pad_blk_offset;
702 pHead = (PSP_HEADER) pBuf;
704 // form header info. SPUsedLen later on...
705 memset((char *)&SPHead, 0, sizeof(SP_HEADER));
706 memcpy(SPHead.SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN);
707 SPHead.SPVersion = SP_VERSION;
710 memset((char*)&SPToken, 0, sizeof(SP_TOKEN));
711 strncpy(SPToken.tokenName, tokenId, TOKEN_NAME_LEN - 1);
712 SPToken.tokenLen = bufLen;
713 if (memcmp(pHead->SPMagicNum, MAGIC_NUMBER, MAGIC_NUM_LEN) != 0)
715 // new sp, so just flash the token
716 printk("No Scrap pad found. Initialize scratch pad...\n");
717 SPHead.SPUsedLen = sizeof(SP_HEADER) + sizeof(SP_TOKEN) + bufLen;
718 memcpy(pBuf, (char *)&SPHead, sizeof(SP_HEADER));
719 curPtr = pBuf + sizeof(SP_HEADER);
720 memcpy(curPtr, (char *)&SPToken, sizeof(SP_TOKEN));
721 curPtr += sizeof(SP_TOKEN);
722 memcpy(curPtr, tokBuf, bufLen);
726 // need search for the token, if exist with same size overwrite it. if sizes differ,
727 // move over the later token data over and put the new one at the end
728 char *endPtr = pBuf + pHead->SPUsedLen;
729 char *spEndPtr = pBuf + SP_MAX_LEN;
730 curPtr = pBuf + sizeof(SP_HEADER);
731 while (curPtr < endPtr && curPtr < spEndPtr)
733 pToken = (PSP_TOKEN) curPtr;
734 if (strncmp(pToken->tokenName, tokenId, TOKEN_NAME_LEN) == 0)
736 if (pToken->tokenLen == bufLen) // overwirte it
738 memcpy((curPtr+sizeof(SP_TOKEN)), tokBuf, bufLen);
741 else // move later data over and put the new token at the end
743 memcpy((curPtr+sizeof(SP_TOKEN)), tokBuf, bufLen); // ~~~
747 else // not same token ~~~
751 curPtr += sizeof(SP_TOKEN) + pToken->tokenLen;
753 SPHead.SPUsedLen = sizeof(SP_HEADER) + sizeof(SP_TOKEN) + bufLen; // ~~~
754 if (SPHead.SPUsedLen > SP_MAX_LEN)
756 printk("No more Scratch pad space left! Over limit by %d bytes\n", SPHead.SPUsedLen - SP_MAX_LEN);
760 } // else if not new sp
762 sts = setSharedBlks(fInfo.flash_scratch_pad_start_blk,
763 (fInfo.flash_scratch_pad_number_blk + fInfo.flash_scratch_pad_start_blk), pShareBuf);
765 retriedKfree(pShareBuf);
772 int kerSysFlashSizeGet(void)
774 return flash_get_total_size();