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

📄 flash.c

📁 UBOOT源码,希望能给大家一点帮助,费了好大心思弄来的.
💻 C
字号:
/*------------------------------------------------------------------------- * Filename:      flash.c * Version:       $Id: flash.c,v 1.11 2002/01/03 16:07:17 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) 2001  Erik Mouw (J.A.K.Mouw@its.tudelft.nl) * 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.11 2002/01/03 16:07:17 erikm Exp $"#ifdef HAVE_CONFIG_H# include <blob/config.h>#endif#include <blob/arch.h>#include <blob/errno.h>#include <blob/error.h>#include <blob/led.h>#include <blob/util.h>#include <blob/serial.h>#include <blob/flash.h>#include <blob/init.h>#include <blob/command.h>/* this is enough for a 16MB flash with 128kB blocks */#define NUM_FLASH_BLOCKS	(128)typedef struct {	u32 start;	u32 size;	int lockable;} flash_block_t;static flash_block_t flash_blocks[NUM_FLASH_BLOCKS];static int num_flash_blocks;flash_descriptor_t *flash_descriptors;flash_driver_t *flash_driver;/* dummy function for enable_vpp and disable_vpp */int flash_dummy_ok(void){	return 0;}/* initialise the flash blocks table */static void init_flash(void){	int i = 0;	int j;	u32 start = 0;	#ifdef BLOB_DEBUG	if(flash_descriptors == NULL) {		printerrprefix();		SerialOutputString("undefined flash_descriptors\n");		return;	}	if(flash_driver == NULL) {		printerrprefix();		SerialOutputString("undefined flash_driver\n");		return;	}#endif		/* fill out missing flash driver functions */	if(flash_driver->enable_vpp == NULL)		flash_driver->enable_vpp = flash_dummy_ok;	if(flash_driver->disable_vpp == NULL)		flash_driver->disable_vpp = flash_dummy_ok;	/* initialise flash blocks table */	num_flash_blocks = 0;	while(flash_descriptors[i].size != 0) {#ifdef BLOB_DEBUG		SerialOutputDec(flash_descriptors[i].num);		SerialOutputString("x 0x");		SerialOutputHex(flash_descriptors[i].size);		SerialOutputString(", ");		if(!flash_descriptors[i].lockable)			SerialOutputString("not ");		SerialOutputString("lockable\n");#endif		for(j = 0; j < flash_descriptors[i].num; j++) {			flash_blocks[num_flash_blocks].start = start;			flash_blocks[num_flash_blocks].size =				flash_descriptors[i].size;			flash_blocks[num_flash_blocks].lockable =				flash_descriptors[i].lockable;			start += flash_descriptors[i].size;			num_flash_blocks++;			if(num_flash_blocks >= NUM_FLASH_BLOCKS) {				printerrprefix();				SerialOutputString("not enough flash_blocks\n");				break;			}		}		i++;	}#ifdef BLOB_DEBUG	SerialOutputString("Flash map:\n");	for(i = 0; i < num_flash_blocks; i++) {		SerialOutputString("  0x");		SerialOutputHex(flash_blocks[i].size);		SerialOutputString(" @ 0x");		SerialOutputHex(flash_blocks[i].start);		SerialOutputString(" (");		SerialOutputDec(flash_blocks[i].size / 1024);		SerialOutputString(" kB), ");		if(!flash_blocks[i].lockable)			SerialOutputString("not ");		SerialOutputString("lockable\n");	}#endif}__initlist(init_flash, INIT_LEVEL_OTHER_STUFF + 1);int flash_erase_region(u32 *start, u32 nwords){	u32 *cur;	u32 *end;	int rv;	cur = start;	end = start + nwords;#if BLOB_DEBUG	SerialOutputString(__FUNCTION__ "(): erasing 0x");	SerialOutputHex(nwords);	SerialOutputString(" (");	SerialOutputDec(nwords);	SerialOutputString(") words at 0x");	SerialOutputHex((u32)start);	serial_write('\n');#endif	flash_driver->enable_vpp();	while(cur < end) {		if(*cur != 0xffffffff) {			SerialOutputString("erasing dirty block at 0x");			SerialOutputHex((u32)cur);			serial_write('\n');			/* dirty block */			rv = flash_driver->erase(cur);			if(rv < 0) {				printerrprefix();				SerialOutputString("flash erase error at 0x");				SerialOutputHex((u32)cur);				serial_write('\n');				flash_driver->disable_vpp();				return rv;			}			continue;		}		cur ++;	}		flash_driver->disable_vpp();	return 0;}/* Write a flash region with a minimum number of erase operations. * * Flash chips wear from erase operations (that's why flash lifetime * is specified in erase cycles), so we try to limit the number of * erase operations in this function. Luckily the flash helps us a * little bit with this, because it only allows you to change a '1' * bit into a '0' during a write operation. This means that 0xffff can * be changed into 0x1010, and 0x1010 into 0x0000, but 0x0000 can't be * changed into anything else anymore because there are no '1' bits * left. */int flash_write_region(u32 *dst, const u32 *src, u32 nwords){	int rv;	u32 nerrors = 0;	u32 i = 0;	u32 nerase = 0;	u32 nwrite = 0;	u32 nscandown = 0;	u32 nskip = 0;#if defined BLOB_DEBUG	SerialOutputString(__FUNCTION__ "(): flashing 0x");	SerialOutputHex(nwords);	SerialOutputString(" (");	SerialOutputDec(nwords);	SerialOutputString(") words from 0x");	SerialOutputHex((u32)src);	SerialOutputString(" to 0x");	SerialOutputHex((u32)dst);	serial_write('\n');#endif	flash_driver->enable_vpp();	while(i < nwords) {		/* nothing to write */		if(dst[i] == src[i]) {			i++;			nskip++;			continue;		}		/* different, so write to this location */		rv = flash_driver->write(&dst[i], &src[i]);		nwrite++;				if(rv == 0) {			i++;		} else {			nerrors++;						SerialOutputString("erasing at 0x");			SerialOutputHex((u32)&dst[i]);			SerialOutputString("...");			/* erase block at current location */			rv = flash_driver->erase(&dst[i]);			nerase++;			if(rv < 0) {				/* something is obviously wrong */				SerialOutputString(" error\n");				flash_driver->disable_vpp();				return rv;			}							SerialOutputString(" scanning down...");			/* scan down until we find the first                           non-erased location and restart writing                           again from that location */			while((i > 0) &&			      ((dst[i] != src[i]) || (dst[i] == 0xffffffff))) {				i--;				nscandown++;			}			SerialOutputString(" resume writing at 0x");			SerialOutputHex((u32)&dst[i]);			serial_write('\n');		}				/* there is something seriously wrong if this is true */		if(nerrors > 2 * nwords) {			printerrprefix();			SerialOutputString("too many flash errors, probably hardware error\n");			flash_driver->disable_vpp();			return -EFLASHPGM;		}	}#ifdef BLOB_DEBUG	SerialOutputDec(nwords);	SerialOutputString(" words source image\n");	SerialOutputDec(nwrite);	SerialOutputString(" words written to flash\n");	SerialOutputDec(nskip);	SerialOutputString(" words skipped\n");	SerialOutputDec(nerase);	SerialOutputString(" erase operations\n");	SerialOutputDec(nscandown);	SerialOutputString(" words scanned down\n");	serial_write('\n');#endif	flash_driver->disable_vpp();	return 0;}/* given an address, return the flash block index number (or negative * error number otherwise */static int find_block(u32 address){	int i;	for (i = 0; i < num_flash_blocks; i++) {		u32 start = flash_blocks[i].start;		int length = flash_blocks[i].size;		u32 endIncl = start + length - 1;		if (address >= start && address <= endIncl)			return i;	}	return -ERANGE;}/* convert address range to range of flash blocks. returns 0 on * success or negative error number on failure. */static int address_range_to_block_range(u32 startAddress, int length, 					int *startBlock, int *endInclBlock){	int sb, eib;#ifdef FLASH_DEBUG	SerialOutputString(__FUNCTION__ ": startAddress = 0x");	SerialOutputHex(startAddress);	SerialOutputString(", length = 0x");	SerialOutputHex(length);	SerialOutputString("\n");#endif	sb = find_block(startAddress);	eib = find_block(startAddress + length - 1);	if(sb < 0)		return sb;	if(eib < 0)		return eib;#ifdef FLASH_DEBUG	SerialOutputString("sb: ");	SerialOutputDec(sb);	SerialOutputString(", eib: ");	SerialOutputDec(eib);	SerialOutputString("\n");#endif	// would be nice to warn if sb isn't at the beginning of	// its block or eib isn't at the very end of its block.	*startBlock = sb;	*endInclBlock = eib;	return 0;}static int do_flash_lock(u32 *start, u32 nwords, int lock){	int sb, eib;	int rv;	int i;	u32 *addr;#ifdef BLOB_DEBUG	SerialOutputString(__FUNCTION__ "(): ");	if(lock == 0)		SerialOutputString("un");		SerialOutputString("lock at 0x");	SerialOutputHex((u32)start);	SerialOutputString(", nwords = 0x");	SerialOutputHex(nwords);	serial_write('\n');#endif	rv = address_range_to_block_range((u32) start, nwords * sizeof(u32),					  &sb, &eib);	if(rv < 0)		return rv;	/* check if it is lockable at all */	for(i = sb; i <= eib; i++) {		if(!flash_blocks[i].lockable) {#ifdef BLOB_DEBUG			printerrprefix();			SerialOutputString("can't (un)lock unlockable blocks\n");#endif			return -EFLASHPGM;		}	}		flash_driver->enable_vpp();	for(i = sb; i <= eib; i++) {		addr = (u32 *)flash_blocks[i].start;		if(lock)			rv = flash_driver->lock_block(addr);		else			rv = flash_driver->unlock_block(addr);		if(rv < 0) {			flash_driver->disable_vpp();#ifdef BLOB_DEBUG			printerrprefix();			SerialOutputString("can't (un)lock block at 0x");			SerialOutputHex((u32)addr);			serial_write('\n');#endif			return rv;		}	}		flash_driver->disable_vpp();	return 0;}int flash_lock_region(u32 *start, u32 nwords){	return do_flash_lock(start, nwords, 1);}int flash_unlock_region(u32 *start, u32 nwords){	return do_flash_lock(start, nwords, 0);}/* return number of blocks in the region locked, 0 if everything is * unlocked, or negative error number otherwise */int flash_query_region(u32 *start, u32 nwords){	int sb, eib, rv, i;	int cnt = 0;	u32 *addr;	rv = address_range_to_block_range((u32) start, nwords * sizeof(u32),					  &sb, &eib);	if(rv < 0)		return rv;	for(i = sb; i <= eib; i++) {		addr = (u32 *)flash_blocks[i].start;				if(flash_blocks[i].lockable) {			rv = flash_driver->query_block_lock(addr);			if(rv < 0) 				return rv;			if(rv > 0)				cnt++;		}	}	return cnt;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -