📄 flash.c
字号:
/*------------------------------------------------------------------------- * Filename: flash.c * Version: $Id: flash.c,v 1.2 2001/08/06 22:44:52 erikm Exp $ * Copyright: Copyright (C) 1999, Jan-Derk Bakker * Author: Jan-Derk Bakker <J.D.Bakker@its.tudelft.nl> * Description: Flash I/O functions for blob * Created at: Mon Aug 23 20:00:00 1999 * Modified by: Erik Mouw <J.A.K.Mouw@its.tudelft.nl> * Modified at: Sat Jan 15 19:16:34 2000 *-----------------------------------------------------------------------*//* * flash.c: Flash I/O functions for blob * * Copyright (C) 1999 Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#ident "$Id: flash.c,v 1.2 2001/08/06 22:44:52 erikm Exp $"#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "led.h"#include "main.h"#include "util.h"#include "serial.h"#include "flash.h"/* define for advanced flash functionality (not that it works) -- Erik *//* #define ADVANCED_FLASH 1 *//* Static function defs */static u32 EraseOne(const char *whichOne);#ifdef ADVANCED_FLASHstatic void GetBlockOrder(tBlkInfo *blocksInfo, u8 which, u8 blockOrder[NUM_FLASH_BLOCKS]);#endif#ifdef ADVANCED_FLASHvoid ScanFlash(tBlkInfo *blocksInfo){/* Scans the flash for headers in the main blocks. Maybe in the future we will put the headers in one of the parameter blocks. */ int i,j; j = 0; for(i = 0; i < NUM_FLASH_BLOCKS; i++) { MyMemCpy((u32 *) &(blocksInfo->headers[i]), FLASH_BLOCK_BASE + i * FLASH_BLOCK_SIZE, sizeof(tBlkHdr) / 4); /* Is this a 'first' block ? */ if(BLOCK_IN_USE(blocksInfo->headers[i]) && (blocksInfo->headers[i].seqNum == 0)) blocksInfo->firstBlockIndex[j++] = i; } for(; j < NUM_FLASH_BLOCKS; j++) blocksInfo->firstBlockIndex[j] = NO_BLOCK;} /* ScanFlash */#endif #ifdef ADVANCED_FLASHvoid LoadBlocksToMem(tBlkInfo *blocksInfo, u8 which, u32 *baseAddr){/* Load a series of blocks to memory */ u8 blockOrder[NUM_FLASH_BLOCKS]; int numBlocks = blocksInfo->headers[which].totSeq; int i; u32 *srcAddr, *dstAddr = baseAddr; /* If the block isn't in use, fail silently. */ if(!BLOCK_IN_USE(blocksInfo->headers[which])) return; GetBlockOrder(blocksInfo, which, blockOrder); for(i = 0; i < numBlocks; i++) { srcAddr = FLASH_BLOCK_BASE + blockOrder[i] * FLASH_BLOCK_SIZE + sizeof(tBlkHdr); MyMemCpy(dstAddr, srcAddr, blocksInfo->headers[i].bytesInBlock / 4); dstAddr += blocksInfo->headers[i].bytesInBlock / 4; }} /* LoadBlocksToMem */#endif/* The spooky functions that write to the same flash that we're executing from */u32 data_from_flash(u32 what);u32 data_to_flash(u32 what);#if defined SHANNON || defined NESA#define READ_ARRAY 0x00F000F0#define UNLOCK1 0x00AA00AA#define UNLOCK2 0x00550055#define ERASE_SETUP 0x00800080#define ERASE_CONFIRM 0x00300030#define PGM_SETUP 0x00A000A0#define UNLOCK_BYPASS 0x00200020#define FLASH_ADDR1 (0x00000555 << 2)#define FLASH_ADDR2 (0x000002AA << 2)#define ERASE_DONE 0x00800080#define RDY_MASK 0x00800080#define STATUS_PGM_ERR 0x00200020#define STATUS_ERASE_ERR 0x00000001#else#define READ_ARRAY 0x00FF00FF#define ERASE_SETUP 0x00200020#define ERASE_CONFIRM 0x00D000D0#define PGM_SETUP 0x00400040#define STATUS_READ 0x00700070#define STATUS_CLEAR 0x00500050#define STATUS_BUSY 0x00800080#define STATUS_ERASE_ERR 0x00200020#define STATUS_PGM_ERR 0x00100010#endifvoid EraseBlocks(tBlockType which) { char *thisBlock; int numBlocks, i; switch(which) { case blBlob: thisBlock = (char *)BLOB_START; numBlocks = NUM_BLOB_BLOCKS; break; case blKernel: thisBlock = (char *)KERNEL_START; numBlocks = NUM_KERNEL_BLOCKS; break; case blRamdisk: thisBlock = (char *)INITRD_START; numBlocks = NUM_INITRD_BLOCKS; break; default: /* this should not happen */ return; } for(i = 0; i < numBlocks; i++, thisBlock += MAIN_BLOCK_SIZE) { SerialOutputByte('.'); led_toggle(); if((EraseOne(thisBlock) & STATUS_ERASE_ERR) != 0) { SerialOutputString("\n*** Erase error at address 0x"); SerialOutputHex((u32)thisBlock); SerialOutputByte('\n'); return; } }} /* EraseBlocks */void WriteBlocksFromMem(tBlockType type, const u32 *source, int length){ volatile u32 *flashBase; u32 result; int maxLength, i; #if defined SHANNON || defined NESA#define READY 1#define ERR 2 int chip1, chip2;#endif if((u32)source & 0x03) { SerialOutputString("*** Source is not on a word boundary: 0x"); SerialOutputHex((u32)source); SerialOutputByte('\n'); return; } if(length & 0x03) length += 0x04; length &= ~((u32) 0x03); switch(type) { case blBlob: flashBase = (u32 *)BLOB_START; maxLength = BLOB_LEN; break; case blKernel: flashBase = (u32 *)KERNEL_START; maxLength = KERNEL_LEN; break; case blRamdisk: flashBase = (u32 *)INITRD_START; maxLength = INITRD_LEN; break; default: /* this should not happen */ return; } if(length > maxLength) length = maxLength;#ifdef BLOB_DEBUG SerialOutputString(__FUNCTION__ "(): Flashing 0x"); SerialOutputHex((u32)length); SerialOutputString(" bytes from 0x"); SerialOutputHex((u32)source); SerialOutputString(" to 0x"); SerialOutputHex((u32)flashBase); SerialOutputByte('\n');#endif#if defined SHANNON || defined NESA *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1); *(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2); *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK_BYPASS);#endif for(i = 0; i < length; i+= 4, flashBase++, source++) { if((i % MAIN_BLOCK_SIZE) == 0) { SerialOutputByte('.'); led_toggle(); } *flashBase = data_to_flash(PGM_SETUP); *flashBase = *source;#if defined SHANNON || defined NESA /* This is a pretty similar situation to the erasing status below * Bit 7 is ~(data bit 7) until the flash is complete. If bit 5 * gets set before this happens, there is an error, but this could * happen near the clock edge, and bit 5 could be the actual data * before bit 7 changes, so we have to read again. */ chip1 = chip2 = 0; do { result = data_from_flash(*flashBase); if (!chip1 && ((result & 0x80) == (*source & 0x80))) chip1 = READY; if (!chip1 && ((result & 0xFFFF) & STATUS_PGM_ERR)) { result = data_from_flash(*flashBase); if ((result & 0x80) == (*source & 0x80)) chip1 = READY; else chip1 = ERR; } if (!chip2 && ((result & (0x80 << 16)) == (*source & (0x80 << 16)))) chip2 = READY; if (!chip2 && ((result >> 16) & STATUS_PGM_ERR)) { result = data_from_flash(*flashBase); if ((result & (0x80 << 16)) == (*source & (0x80 << 16))) chip2 = READY; else chip2 = ERR; } } while (!chip1 || !chip2); if (chip1 == ERR || chip2 == ERR || *flashBase != *source) { #else do { *flashBase = data_to_flash(STATUS_READ); result = data_from_flash(*flashBase); } while((~result & STATUS_BUSY) != 0); *flashBase = data_to_flash(READ_ARRAY); if((result & STATUS_PGM_ERR) != 0 || *flashBase != *source) {#endif SerialOutputString("\n*** Write error at address 0x"); SerialOutputHex((u32)flashBase); SerialOutputByte('\n'); return; } } #if defined SHANNON || defined NESA *(u32 *)FLASH_ADDR1 = data_to_flash(READ_ARRAY);#endif} /* WriteBlocksFromMem */static u32 EraseOne(const char *whichOne){/* Routine to erase one block of flash */ volatile u32 *writeMe = (u32 *)whichOne; u32 result;#if defined SHANNON || defined NESA int chip1, chip2;#endif#ifdef BLOB_DEBUG SerialOutputString(__FUNCTION__ "(): erasing block at address 0x"); SerialOutputHex((u32)whichOne); SerialOutputByte('\n');#endif #if defined SHANNON || defined NESA *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1); *(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2); *(u32 *)FLASH_ADDR1 = data_to_flash(ERASE_SETUP); *(u32 *)FLASH_ADDR1 = data_to_flash(UNLOCK1); *(u32 *)FLASH_ADDR2 = data_to_flash(UNLOCK2); *writeMe = data_to_flash(ERASE_CONFIRM); /* I just can't find clean ways of dealing with this flash... * The error bit is a *set* bit, so if its read, and bit 7 is 0, * but bit 5 is 1, its an error, however, after these status reads * are done, erased flash goes to 0xff...sooo...each chip has to * be caught where the bits are the status bits */ chip1 = chip2 = 0; do { result = data_from_flash(*writeMe); if (!chip1 && (result & 0xFFFF) & ERASE_DONE) chip1 = READY; if (!chip1 && (result & 0xFFFF) & STATUS_PGM_ERR) chip1 = ERR; if (!chip2 && (result >> 16) & ERASE_DONE) chip2 = READY; if (!chip2 && (result >> 16) & STATUS_PGM_ERR) chip2 = ERR; } while(!chip1 || !chip2); *(u32 *)FLASH_ADDR1 = data_to_flash(READ_ARRAY); if (chip1 == ERR || chip2 == ERR) return 1; return 0;#else *writeMe = data_to_flash(ERASE_SETUP); *writeMe = data_to_flash(ERASE_CONFIRM); do { *writeMe = data_to_flash(STATUS_READ); result = data_from_flash(*writeMe); } while((~result & STATUS_BUSY) != 0); *writeMe = data_to_flash(READ_ARRAY); return result;#endif} /* EraseOne */#ifdef ADVANCED_FLASHstatic void GetBlockOrder(tBlkInfo *blocksInfo, u8 which, u8 blockOrder[NUM_FLASH_BLOCKS]){ tBlockType type = blocksInfo->headers[which].type; char *name = blocksInfo->headers[which].name; int i; /* If the block isn't in use, fail silently. */ if(!BLOCK_IN_USE(blocksInfo->headers[which])) return; for(i = 0; i < NUM_FLASH_BLOCKS; i++) { if(BLOCK_IN_USE(blocksInfo->headers[i]) && (blocksInfo->headers[i].type == type) && !MyStrNCmp(blocksInfo->headers[i].name, name, BLOCK_NAME_LEN)) { blockOrder[blocksInfo->headers[i].seqNum] = i; } }} /* GetBlockOrder */#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -