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

📄 flash.c

📁 PXA250上的XBOOT
💻 C
字号:
/*  * $Id: flash.c,v 1.3 2003/09/26 07:11:55 jfabo Exp $ * * Copyright (C) 2001, 2002 ETC s.r.o. * * 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. * * Written by Marcel Telka <marcel@telka.sk>, 2001, 2002. * */#include ".config.h"#include <stdint.h>#include <flash/cfi.h>#include <flash/intel.h>#include "board.h"#include "except.h"#include "flash.h"#include "format.h"#include "splash.h"#define	FLASH(addr)	(*(volatile uint32_t *)(MEM_VIRT_FLASH + ((addr) << 2)))#define MAXBUFSIZE	1024#define MAXBLOCKS	256static uint32_t flashoffset;static uint8_t flashbuf[MAXBUFSIZE];static size_t flashbufsize;static uint32_t flashbufptr;static int erasedblocks[MAXBLOCKS];static size_t blocksize;static voiderase( int block ){	if (!erasedblocks[block]) {		EdbgOutputDebugString( "Erasing block #%d%s\n", block,				block ? "" : "   WARNING: Overwriting xboot!" );		if (FlashClearBlockLockBit( block ))			Throw E_FL_BLOCKUNLOCK;		if (FlashBlockErase( block ))			Throw E_FL_BLOCKERASE;		erasedblocks[block] = 1;	}}static voidflash( void *dst, const void *src, size_t count ){	size_t offset = (size_t) dst - MEM_VIRT_FLASH;	if ((offset % sizeof (size_t)) || (count % sizeof (size_t)))		Throw E_FL_DATAALIGNMENT;	/* TODO: check offset and offset + count to be in flashsize */	while (count) {		size_t len;		int block = offset / blocksize;		size_t nbo = (block + 1) * blocksize;		if ((len = (nbo - offset)) > count)			len = count;		erase( block );		count -= len;		while (len) {			size_t flen = (len > flashbufsize) ? flashbufsize : len;			if (FlashWriteToBuffer( offset, src, flen / 4 ))				Throw E_FL_WRITETOBUFFER;			offset += flen;			len -= flen;			src = (void *) ((size_t) src + flen);		}	}}static voidWriteFlashBuf( void ){	uint32_t block = flashoffset / blocksize;	erase( block );	if (FlashWriteToBuffer( flashoffset, (uint32_t *) &flashbuf, (flashbufptr + 3) / 4 ))		Throw E_FL_WRITETOBUFFER;	flashoffset += flashbufptr;}static voidWriteByte( uint8_t c ){	flashbuf[flashbufptr++] = c;	if (flashbufptr == flashbufsize) {		WriteFlashBuf();		flashbufptr = 0;	}}static voidWriteDWord( uint32_t dw ){	WriteByte( (uint8_t) (dw & 0xFF) );	WriteByte( (uint8_t) ((dw >> 8) & 0xFF) );	WriteByte( (uint8_t) ((dw >> 16) & 0xFF) );	WriteByte( (uint8_t) ((dw >> 24) & 0xFF) );}static voidStartFlash( uint32_t offset, struct FlashInfo *fi ){	int i;	if ((fi->wbufsize > MAXBUFSIZE) || (fi->eblocks > MAXBLOCKS))		Throw E_FL_OUTOFMEMORY;	flashoffset = offset;	flashbufsize = fi->wbufsize;	flashbufptr = 0;	blocksize = fi->eblocksize;	for (i = 0; i < fi->eblocks; i++)		erasedblocks[i] = 0;}static voidEndFlash( void ){	if (flashbufptr > 0)		WriteFlashBuf();	FlashReadArray();}voidFlashXIP( struct imginfo *img ){	unsigned int *rec = (void *) img->target;#ifdef CONFIG_SPLASH_SCREEN	unsigned int total_length = 0;	unsigned char progress_percentage = 0;#endif	switch (img->start & 0xFF000000) {		case MEM_VIRT_FLASH:			img->target = img->start;			break;		case MEM_PHYS_FLASH:			img->target = img->start + MEM_VIRT_FLASH - MEM_PHYS_FLASH;			break;		default:			Throw E_FL_UNKNOWNMEMORY;	}	for (;;) {		unsigned int addr = *rec++;		unsigned int len = *rec++;		unsigned int sum = *rec++;#ifdef CONFIG_SPLASH_SCREEN		unsigned int step = 0, current = 0;#endif		if (!addr && !sum) {			FlashReadArray();#ifdef CONFIG_SPLASH_SCREEN						progress_bar(100, 0);#endif						return;		}#ifdef CONFIG_SPLASH_SCREEN#define	LARGE_BLOCK	262144		step = (LARGE_BLOCK < len) ? LARGE_BLOCK : len;		current = 0;		while (current < len) {			total_length += step;			if (((total_length * 100 )/ img->len ) > progress_percentage ){				progress_percentage = (unsigned char)((total_length * 100 )/ img->len );				progress_bar(progress_percentage, 0);			}			flash( (void *) (addr - img->start + img->target + current), rec + current/4, step );			current +=step;			step = (LARGE_BLOCK < (len - current)) ? LARGE_BLOCK : (len - current);		}			#else		flash( (void *) (addr - img->start + img->target), rec, len );#endif		rec += len / sizeof *rec;	}}voidFlashImage( struct imginfo *img, unsigned int FlashOffset ){	struct FlashInfo fi;	unsigned int *rec;	if (!FlashReadInfo( &fi ))		Throw E_FL_READINFO;	EdbgOutputDebugString( "Flash size: %d (0x%X)\n", fi.size, fi.size );	EdbgOutputDebugString( "Write buffer size: %d\n", fi.wbufsize );	EdbgOutputDebugString( "Number of blocks: %d\n", fi.eblocks );	EdbgOutputDebugString( "Block size: %d (0x%X)\n", fi.eblocksize, fi.eblocksize );	EdbgOutputDebugString( "\n" );	StartFlash( FlashOffset, &fi );	if (img->copy) {		FlashXIP( img );		return;	}	WriteByte( 'B' );	WriteByte( '0' );	WriteByte( '0' );	WriteByte( '0' );	WriteByte( 'F' );	WriteByte( 'F' );	WriteByte( '\n' );	WriteDWord( img->start );	WriteDWord( img->len );	rec = (void *) (img->target + img->len);	for (;;) {		unsigned int addr = *rec++;		unsigned int len = *rec++;		unsigned int sum = *rec++;		unsigned int calcCRC = 0;		unsigned int i;		WriteDWord( addr );		WriteDWord( len );		WriteDWord( sum );		if (!addr && !sum) {			EndFlash();			return;		}		for (i = 0; i < len; i++) {			unsigned char d = *(unsigned char *) (addr++ - img->start + img->target);			WriteByte( d );			calcCRC += d;		}		if (calcCRC != sum)			Throw E_FL_CHECKSUM;	}}static voidFlashCommand( uint8_t cmd, uint32_t addr ){	uint32_t command = cmd;	FLASH( addr ) = (command << 16) | command;}/* 4.1 */voidFlashReadArray( void ){	FlashCommand( CFI_CMD_READ_ARRAY1, 0x00 );}/* 4.2 */#define	DOUBLETEST(val)		{ if (((val) & 0xFFFF) != ((val) >> 16)) return 0; }#define	COMBINEREAD(adr1, adr2)	((FLASH( adr1 ) & 0xFF00FF) | ((FLASH( adr2 ) & 0xFF00FF) << 8))intFlashReadInfo( struct FlashInfo *fi ){	uint32_t dw;	FlashCommand( CFI_CMD_QUERY, CFI_CMD_QUERY_OFFSET );	/* 	 * 4.2.1 - 4.2.3	 */	/* (nothing to do) */	/* 	 * 4.2.4 CFI Query Interface String	 */	/* check query-unique ascii string */	if (FLASH( CFI_QUERY_ID_OFFSET ) != 0x00510051)		return 0;			/* Q */	if (FLASH( CFI_QUERY_ID_OFFSET + 1 ) != 0x00520052)		return 0;			/* R */	if (FLASH( CFI_QUERY_ID_OFFSET + 2) != 0x00590059)		return 0;			/* Y */	/* check vendor specific algorithm */	if (COMBINEREAD( 0x13, 0x14 ) != 0x00010001)		return 0;	/* check extended query table primary algorithm address */	if (COMBINEREAD( 0x15, 0x16 ) != 0x00310031)		return 0;	/* check alternate vendor command set */	if (COMBINEREAD( 0x17, 0x18 ) != 0x00000000)		return 0;	/* check secondary algorithm extended query table address */	if (COMBINEREAD( 0x19, 0x1A ) != 0x00000000)		return 0;	/* 	 * 4.2.5 System Interface Information	 */	/* check Vcc logic supply minimum program/erase voltage */	if (FLASH( 0x1B ) != 0x00270027)		return 0;	/* check Vcc logic supply maximum program/erase voltage */	if (FLASH( 0x1C ) != 0x00360036)		return 0;	/* check Vpp [programming] supply minimum program/erase voltage */	if (FLASH( 0x1D ) != 0x00000000)		return 0;	/* check Vpp [programming] supply maximum program/erase voltage */	if (FLASH( 0x1E ) != 0x00000000)		return 0;	/* TODO: addresses 0x1F - 0x26 */	/* 	 * 4.2.6 Device Geometry Definition	 */	/* read device size */	DOUBLETEST( dw = FLASH( 0x27 ) );	/* device size is multiplied by two, because we have two ICs */	fi->size = (1 << (dw & 0xFFFF)) * 2;	/* read max. number of bytes in write buffer */	DOUBLETEST( dw = COMBINEREAD( 0x2A, 0x2B ) );	/* write buffer size is multiplied by two, because we have two ICs */	fi->wbufsize = (1 << (dw & 0xFFFF)) * 2;	/* check number of erase block regions */	if (FLASH( 0x2C ) != 0x00010001)		return 0;	/* read number of erase blocks */	DOUBLETEST( dw = COMBINEREAD( 0x2D, 0x2E ) );	fi->eblocks = (uint16_t) ((dw & 0xFFFF) + 1);	/* read erase block size */	DOUBLETEST( dw = COMBINEREAD( 0x2F, 0x30 ) );	/* erase block size is multiplied by two, because we have two ICs */	fi->eblocksize = ((dw & 0xFFFF) << 8) * 2;	/* 	 * 4.2.7 Primary-Vendor Specific Extended Query Table	 * TODO	 */	return 1;}#undef COMBINEREAD#undef DOUBLETEST/* 4.3 */intFlashReadID( void ){	FlashCommand( 0x90, 0x00 );	/* check Manufacturer Code */	if (FLASH( 0x00 ) != 0x890089)		return 0;	/* check Device Code */	switch (FLASH( 0x01 )) {		case 0x160016:			return 0x16;		case 0x170017:			return 0x17;		case 0x180018:			return 0x18;	}	return 0;}/* 4.4 TODO */uint32_tFlashReadStatusRegister( void ){	FlashCommand( 0x70, 0x00 );	return FLASH( 0x00 );}/* 4.5 */voidFlashClearStatusRegister( void ){	FlashCommand( 0x50, 0x00 );}/* 4.6 */uint32_tFlashBlockErase( int block ){	FlashClearStatusRegister();	FlashCommand( 0x20, block << 16 );	/* Block Erase Command */	FlashCommand( 0xD0, block << 16 );	/* confirm */	while ((FlashReadStatusRegister() & 0x00800080) != 0x00800080)	/* wait for SR.7 = 1 */		;	return FlashReadStatusRegister() & 0x007E007E;	/* return masked SR */}/* 4.8 */uint32_tFlashWriteToBuffer( uint32_t dst, const uint32_t *src, uint32_t size ){	uint32_t i;	dst >>= 2;	FlashClearStatusRegister();		/* clear status register */	do {		FlashCommand( 0xE8, dst );	/* Write to Buffer Command */	} while ((FLASH( dst ) & 0x00800080) != 0x00800080);	/* repeat until XSR.7 = 1 */	FlashCommand( (uint8_t) (size - 1), dst );	/* set word count */	for (i = 0; i < size; i++)		FLASH( dst++ ) = *src++;	/* copy data to write buffer */	FlashCommand( 0xD0, 0x00 );		/* confirm */	while ((FlashReadStatusRegister() & 0x00800080) != 0x00800080)	/* wait for SR.7 = 1 */		;	return FlashReadStatusRegister() & 0x007E007E;	/* return masked SR */}/* 4.14 */uint32_tFlashClearBlockLockBit( int block ){	FlashClearStatusRegister();	FlashCommand( CFI_INTEL_CMD_LOCK_SETUP, block << 16 );	FlashCommand( CFI_INTEL_CMD_UNLOCK_BLOCK, block << 16 );	while ((FlashReadStatusRegister() & 0x00800080) != 0x00800080)	/* wait for SR.7 = 1 */		;	return FlashReadStatusRegister() & 0x007E007E;	/* return masked SR */}

⌨️ 快捷键说明

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