⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 flash.c

📁 针对于sa1100的bootloader。blob2.04是一个功能比较强大的bootloader
💻 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 + -