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

📄 flash.c

📁 Uboot源代码,适合编写或修改Uboot的开发者
💻 C
字号:
/* * (C) Copyright 2005 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * flash_real_protect() routine based on boards/alaska/flash.c * (C) Copyright 2001 * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net * * See file CREDITS for list of people who contributed to this * project. * * 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 */#include <common.h>/* Intel-compatible flash commands */#define INTEL_ERASE	0x20#define INTEL_PROGRAM	0x40#define INTEL_CLEAR	0x50#define INTEL_LOCKBIT	0x60#define INTEL_PROTECT	0x01#define INTEL_STATUS	0x70#define INTEL_READID	0x90#define INTEL_READID	0x90#define INTEL_SUSPEND	0xB0#define INTEL_CONFIRM	0xD0#define INTEL_RESET	0xFF/* Intel-compatible flash status bits */#define INTEL_FINISHED	0x80#define INTEL_OK	0x80typedef unsigned char FLASH_PORT_WIDTH;typedef volatile unsigned char FLASH_PORT_WIDTHV;#define FPW		FLASH_PORT_WIDTH#define FPWV		FLASH_PORT_WIDTHV#define	FLASH_ID_MASK	0xFF#define ORMASK(size) ((-size) & OR_AM_MSK)#define FLASH_CYCLE1	0x0555#define FLASH_CYCLE2	0x02aaflash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips *//*----------------------------------------------------------------------- * Functions */static ulong flash_get_size(FPWV *addr, flash_info_t *info);static void flash_reset(flash_info_t *info);static flash_info_t *flash_get_info(ulong base);static int write_data (flash_info_t *info, FPWV *dest, FPW data); /* O2D */static void flash_sync_real_protect (flash_info_t * info);static unsigned char intel_sector_protected (flash_info_t *info, ushort sector);/*----------------------------------------------------------------------- * flash_init() * * sets up flash_info and returns size of FLASH (bytes) */unsigned long flash_init (void){	unsigned long size = 0;	int i;	extern void flash_preinit(void);	extern void flash_afterinit(ulong);	flash_preinit();	/* Init: no FLASHes known */	for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) {		memset(&flash_info[i], 0, sizeof(flash_info_t));		flash_info[i].flash_id = FLASH_UNKNOWN;	}	/* Query flash chip */	flash_info[0].size =		flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]);	size += flash_info[0].size;	/* get the h/w and s/w protection status in sync */	flash_sync_real_protect(&flash_info[0]);#if CFG_MONITOR_BASE >= CFG_FLASH_BASE	/* monitor protection ON by default */	flash_protect(FLAG_PROTECT_SET,			CFG_MONITOR_BASE,			CFG_MONITOR_BASE+monitor_flash_len-1,			flash_get_info(CFG_MONITOR_BASE));#endif#ifdef	CFG_ENV_IS_IN_FLASH	/* ENV protection ON by default */	flash_protect(FLAG_PROTECT_SET,			CFG_ENV_ADDR,			CFG_ENV_ADDR+CFG_ENV_SIZE-1,			flash_get_info(CFG_ENV_ADDR));#endif	flash_afterinit(size);	return (size ? size : 1);}/*----------------------------------------------------------------------- */static void flash_reset(flash_info_t *info){	FPWV *base = (FPWV *)(info->start[0]);	/* Put FLASH back in read mode */	if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL)		*base = (FPW) INTEL_RESET;	/* Intel Read Mode */}/*----------------------------------------------------------------------- */static flash_info_t *flash_get_info(ulong base){	int i;	flash_info_t * info;	for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) {		info = & flash_info[i];		if (info->size &&				info->start[0] <= base &&				base <= info->start[0] + info->size - 1)			break;	}	return (i == CFG_MAX_FLASH_BANKS ? 0 : info);}/*----------------------------------------------------------------------- */void flash_print_info (flash_info_t *info){	int i;	uchar *boottype;	uchar *bootletter;	char *fmt;	uchar botbootletter[] = "B";	uchar topbootletter[] = "T";	uchar botboottype[] = "bottom boot sector";	uchar topboottype[] = "top boot sector";	if (info->flash_id == FLASH_UNKNOWN) {		printf ("missing or unknown FLASH type\n");		return;	}	switch (info->flash_id & FLASH_VENDMASK) {		case FLASH_MAN_INTEL:			printf ("INTEL ");			break;		default:			printf ("Unknown Vendor ");			break;	}	/* check for top or bottom boot, if it applies */	if (info->flash_id & FLASH_BTYPE) {		boottype = botboottype;		bootletter = botbootletter;	} else {		boottype = topboottype;		bootletter = topbootletter;	}	switch (info->flash_id & FLASH_TYPEMASK) {		case FLASH_28F128J3A:			fmt = "28F128J3 (128 Mbit, uniform sectors)\n";			break;		default:			fmt = "Unknown Chip Type\n";			break;	}	printf (fmt, bootletter, boottype);	printf ("  Size: %ld MB in %d Sectors\n",			info->size >> 20,			info->sector_count);	printf ("  Sector Start Addresses:");	for (i=0; i<info->sector_count; ++i) {		if ((i % 5) == 0)			printf ("\n   ");		printf (" %08lX%s", info->start[i],				info->protect[i] ? " (RO)" : "     ");	}	printf ("\n");}/*----------------------------------------------------------------------- *//* * The following code cannot be run from FLASH! */ulong flash_get_size (FPWV *addr, flash_info_t *info){	int i;	/* Write auto select command: read Manufacturer ID */	/* Write auto select command sequence and test FLASH answer */	addr[FLASH_CYCLE1] = (FPW) INTEL_READID;	/* selects Intel or AMD */	/* The manufacturer codes are only 1 byte, so just use 1 byte.	 * This works for any bus width and any FLASH device width.	 */	udelay(100);	switch (addr[0] & 0xff) {		case (uchar)INTEL_MANUFACT:			info->flash_id = FLASH_MAN_INTEL;			break;		default:			info->flash_id = FLASH_UNKNOWN;			info->sector_count = 0;			info->size = 0;			break;	}	/* Strataflash is configurable to 8/16bit Bus,	 * but the Query-Structure is Word-orientated */	if (info->flash_id != FLASH_UNKNOWN) {		switch ((FPW)addr[2]) {			case (FPW)INTEL_ID_28F128J3:				info->flash_id += FLASH_28F128J3A;				info->sector_count = 128;				info->size = 0x01000000;				for( i = 0; i < info->sector_count; i++ )					info->start[i] = (ulong)addr + (i * 0x20000);				break;				/* => Intel Strataflash 16MB */			default:				printf("Flash_id != %xd\n", (FPW)addr[2]);				info->flash_id = FLASH_UNKNOWN;				info->sector_count = 0;				info->size = 0;				return (0);			/* => no or unknown flash */		}	}	/* Put FLASH back in read mode */	flash_reset(info);	return (info->size);}/*----------------------------------------------------------------------- */int flash_erase (flash_info_t *info, int s_first, int s_last){	FPWV *addr;	int flag, prot, sect;	ulong start, now, last;	int rcode = 0;	if ((s_first < 0) || (s_first > s_last)) {		if (info->flash_id == FLASH_UNKNOWN) {			printf ("- missing\n");		} else {			printf ("- no sectors to erase\n");		}		return 1;	}	switch (info->flash_id & FLASH_TYPEMASK) {		case FLASH_28F128J3A:			break;		case FLASH_UNKNOWN:		default:			printf ("Can't erase unknown flash type %08lx - aborted\n",					info->flash_id);			return 1;	}	prot = 0;	for (sect = s_first; sect <= s_last; ++sect)		if (info->protect[sect])			prot++;	if (prot)		printf ("- Warning: %d protected sectors will not be erased!",				prot);	printf ("\n");	last = get_timer(0);	/* Start erase on unprotected sectors */	for (sect = s_first; sect <= s_last && rcode == 0; sect++) {		if (info->protect[sect] != 0)	/* protected, skip it */			continue;		/* Disable interrupts which might cause a timeout here */		flag = disable_interrupts();		addr = (FPWV *)(info->start[sect]);		*addr = (FPW) INTEL_CLEAR; /* clear status register */		*addr = (FPW) INTEL_ERASE; /* erase setup */		*addr = (FPW) INTEL_CONFIRM; /* erase confirm */		/* re-enable interrupts if necessary */		if (flag)			enable_interrupts();		start = get_timer(0);		/* wait at least 80us for Intel - let's wait 1 ms */		udelay (1000);		while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) {			if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) {				printf ("Timeout\n");				*addr = (FPW) INTEL_SUSPEND;/* suspend erase */				flash_reset(info);	/* reset to read mode */				rcode = 1;		/* failed */				break;			}			/* show that we're waiting */			if ((get_timer(last)) > CFG_HZ) { /* every second */				putc ('.');				last = get_timer(0);			}		}		flash_reset(info);	/* reset to read mode */	}	printf (" done\n");	return rcode;}/*----------------------------------------------------------------------- * Copy memory to flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt){	FPW data = 0;	/* 16 or 32 bit word, matches flash bus width on MPC8XX */	int bytes;	/* number of bytes to program in current word		*/	int left;	/* number of bytes left to program			*/	int i, res;	for (left = cnt, res = 0;			left > 0 && res == 0;			addr += sizeof(data), left -= sizeof(data) - bytes) {		bytes = addr & (sizeof(data) - 1);		addr &= ~(sizeof(data) - 1);		/* combine source and destination data so can program		 * an entire word of 16 or 32 bits  */		for (i = 0; i < sizeof(data); i++) {			data <<= 8;			if (i < bytes || i - bytes >= left )				data += *((uchar *)addr + i);			else				data += *src++;		}		/* write one word to the flash */		switch (info->flash_id & FLASH_VENDMASK) {			case FLASH_MAN_INTEL:				res = write_data(info, (FPWV *)addr, data);				break;			default:				/* unknown flash type, error! */				printf ("missing or unknown FLASH type\n");				res = 1;	/* not really a timeout, but gives error */				break;		}	}	return (res);}/*----------------------------------------------------------------------- * Write a word or halfword to Flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */static int write_data (flash_info_t *info, FPWV *dest, FPW data){	FPWV *addr = dest;	ulong status;	ulong start;	int flag;	/* Check if Flash is (sufficiently) erased */	if ((*addr & data) != data) {		printf ("not erased at %08lx (%lx)\n", (ulong) addr, *addr);		return (2);	}	/* Disable interrupts which might cause a timeout here */	flag = disable_interrupts ();	*addr = (FPW) INTEL_PROGRAM;	/* write setup */	*addr = data;	/* arm simple, non interrupt dependent timer */	start = get_timer(0);	/* wait while polling the status register */	while (((status = *addr) & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) {		if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {			*addr = (FPW) INTEL_RESET;	/* restore read mode */			return (1);		}	}	*addr = (FPW) INTEL_RESET;	/* restore read mode */	if (flag)		enable_interrupts();	return (0);}/*----------------------------------------------------------------------- * Set/Clear sector's lock bit, returns: * 0 - OK * 1 - Error (timeout, voltage problems, etc.) */int flash_real_protect (flash_info_t * info, long sector, int prot){	ulong start;	int i;	int rc = 0;	FPWV *addr = (FPWV *) (info->start[sector]);	int flag = disable_interrupts ();	*addr = INTEL_CLEAR;	/* Clear status register    */	if (prot) {		/* Set sector lock bit      */		*addr = INTEL_LOCKBIT;	/* Sector lock bit          */		*addr = INTEL_PROTECT;	/* set                      */	} else {		/* Clear sector lock bit    */		*addr = INTEL_LOCKBIT;	/* All sectors lock bits    */		*addr = INTEL_CONFIRM;	/* clear                    */	}	start = get_timer (0);	while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) {		if (get_timer (start) > CFG_FLASH_UNLOCK_TOUT) {			printf ("Flash lock bit operation timed out\n");			rc = 1;			break;		}	}	if (*addr != INTEL_OK) {		printf ("Flash lock bit operation failed at %08X, CSR=%08X\n",			(uint) addr, (uint) * addr);		rc = 1;	}	if (!rc)		info->protect[sector] = prot;	/*	 * Clear lock bit command clears all sectors lock bits, so	 * we have to restore lock bits of protected sectors.	 */	if (!prot) {		for (i = 0; i < info->sector_count; i++) {			if (info->protect[i]) {				start = get_timer (0);				addr = (FPWV *) (info->start[i]);				*addr = INTEL_LOCKBIT;	/* Sector lock bit  */				*addr = INTEL_PROTECT;	/* set              */				while ((*addr & INTEL_FINISHED) !=				       INTEL_FINISHED) {					if (get_timer (start) >					    CFG_FLASH_UNLOCK_TOUT) {						printf ("Flash lock bit operation timed out\n");						rc = 1;						break;					}				}			}		}	}	if (flag)		enable_interrupts ();	*addr = INTEL_RESET;	/* Reset to read array mode */	return rc;}/* * This function gets the u-boot flash sector protection status * (flash_info_t.protect[]) in sync with the sector protection * status stored in hardware. */static void flash_sync_real_protect (flash_info_t * info){	int i;	switch (info->flash_id & FLASH_TYPEMASK) {	case FLASH_28F128J3A:		for (i = 0; i < info->sector_count; ++i) {			info->protect[i] = intel_sector_protected(info, i);		}		break;	default:		/* no h/w protect support */		break;	}}/* * checks if "sector" in bank "info" is protected. Should work on intel * strata flash chips 28FxxxJ3x in 8-bit mode. * Returns 1 if sector is protected (or timed-out while trying to read * protection status), 0 if it is not. */static unsigned char intel_sector_protected (flash_info_t *info, ushort sector){	FPWV *addr;	FPWV *lock_conf_addr;	ulong start;	unsigned char ret;	/*	 * first, wait for the WSM to be finished. The rationale for	 * waiting for the WSM to become idle for at most	 * CFG_FLASH_ERASE_TOUT is as follows. The WSM can be busy	 * because of: (1) erase, (2) program or (3) lock bit	 * configuration. So we just wait for the longest timeout of	 * the (1)-(3), i.e. the erase timeout.	 */	/* wait at least 35ns (W12) before issuing Read Status Register */	udelay(1);	addr = (FPWV *) info->start[sector];	*addr = (FPW) INTEL_STATUS;	start = get_timer (0);	while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) {		if (get_timer (start) > CFG_FLASH_ERASE_TOUT) {			*addr = (FPW) INTEL_RESET; /* restore read mode */			printf("WSM busy too long, can't get prot status\n");			return 1;		}	}	/* issue the Read Identifier Codes command */	*addr = (FPW) INTEL_READID;	/* wait at least 35ns (W12) before reading */	udelay(1);	/* Intel example code uses offset of 4 for 8-bit flash */	lock_conf_addr = (FPWV *) info->start[sector] + 4;	ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0;	/* put flash back in read mode */	*addr = (FPW) INTEL_RESET;	return ret;}

⌨️ 快捷键说明

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