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

📄 flash.c

📁 linux平台上的开放源代码的网络摄像机程序.实现视频捕捉,传输以及云台控制等.非常具有参考价值.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: flash.c,v 1.23 2001/11/21 15:52:44 jonashg Exp $ * June 15, 2002 - made flash length with MSB set - compare only) * May, 1, 2002 - support for Intel StrataFlash (and Micron) * modified by Andrey Filippov for Intel support 12/17/2001 (define MYINTEL) * * Stolen from the eLinux kernel and stripped down. * * HISTORY: * * $Log: flash.c,v $ * Revision 1.23  2001/11/21 15:52:44  jonashg * Almost readable. * * Revision 1.22  2001/11/21 15:24:38  jonashg * Increased readability and decreased size some 40bytes. * * Revision 1.21  2001/11/20 13:40:12  starvik * Corrected handling for CFI capable bottom boot flashes * Shorted some strings to make more space available * * Revision 1.20  2001/08/08 17:51:28  pkj * Made it possible to flash at a start offset other than zero when * there are more than one physical flash chip available. Previously * it always started flashing from the start of the first flash if * there were more than one, even though the start offset was set to * something else... * * Revision 1.19  2001/06/19 14:51:17  jonashg * Added support for non-CFI flash Toshiba TC58FVT800. * * Revision 1.18  2001/04/05 06:32:39  starvik * Works with flashes with multiple banks * * Revision 1.17  2001/03/06 15:21:16  jonashg * More output to user. * * Revision 1.16  2001/03/06 14:11:16  jonashg * * Switch to second device correctly when flashing images that extend past the *   first device. * * Only enter autoselect mode once saves a few bytes (not needed before reading *   device id, since it was done before reading manufacturer id). * * A few unnecessary resets removed to save another few bytes. * * Revision 1.15  2001/02/28 14:52:43  jonashg * * Reverted to old sector erase sequence (that was correct). * * A bit of executable size optimization (a few hundred bytes). * * Cleanup. * * Revision 1.14  2001/02/27 14:18:59  jonashg * * Write full erase command sequence to all sectors that should be erased. * * Write 16bit erase command to non-interleaved chips. * * Revision 1.13  2001/02/23 11:03:41  jonashg * Added support for 2 x 16Mb flashes (32-bits buswidth). * The CFI probe does not detect two parallel flash devices, but the normal * probe does (it should be easy to add that in the CFI-probe, but I didn't * have any hardware to try it on and the size of the executable is getting * pretty close to the size of the ETRAX cache). * * Revision 1.12  2001/02/12 13:59:00  jonashg * Bugfix: pointer arithmetics made bootsector calculation go wrong. * * Revision 1.11  2000/11/10 08:02:23  starvik * Added CFI support * * Revision 1.10  2000/10/26 13:47:32  johana * Added support for Fujitsu flash 16MBit (2MByte) MBM29LV160BE and MBM29LV160TE. * NOT VERIFIED YET! * * Revision 1.9  2000/06/28 13:02:50  bjornw * * Added support for SST39LF800 and SST39LF160 flashes * * Fixed some indentation issues * * Revision 1.8  2000/06/13 11:51:11  starvik * Support for two flashes. Second flash is erased and programmed if program * is larger than first flash. * * Revision 1.7  2000/04/13 16:06:15  macce * See if flash is empty before erasing it. Might save some production time. * * Revision 1.6  2000/01/27 17:52:07  bjornw * * Added Toshiba flashes * * Added proper bootblock erase for the different flashes *   (this caused the verify errors when trying to do ./flashitall before) * * Revision 1.5  2000/01/20 11:41:28  finn * Improved the verify error printouts in flash_write. * * Revision 1.4  1999/12/21 19:32:53  bjornw * Dont choke on full chip erases even though we dont implement it efficiently. * * Revision 1.3  1999/11/12 01:30:04  bjornw * Added wait for busy to be ready. Removed some warnings. * * Revision 1.2  1999/10/27 07:42:42  johana * Added support for ST M29W800T flash used in 5600 * * Revision 1.1  1999/10/27 01:37:12  bjornw * Wrote routines to erase and flash data into a flash ROM. * * * TODO: *   implement Unlock Bypass programming, to double the write speed *   NOTE: ST M29W800T does not support Unlock bypass! *   fix various loops for partitions than span more than one chip */#include "svinto_boot.h"#define MYINTEL// #define DEBUG#ifdef DEBUG#define FDEBUG(x) x#else#define FDEBUG(x)#endif#define MEM_DRAM_START 0x40000000 /* This is not a flash address */#define TYPE_X16	(16 / 8)#define nop() __asm__("nop")#define safe_printk send_serial_string/* Intel status bits */#define	INTEL_SRB_WSMS		0x80#define	INTEL_SRB_ESS		0x40#define	INTEL_SRB_ES		0x20#define	INTEL_SRB_PS		0x10#define	INTEL_SRB_VPPS		0x08#define	INTEL_SRB_PSS		0x04#define	INTEL_SRB_BLS		0x02/* Intel extended status bits */#define	INTEL_XSRB_WBS		0x80	/* Intel block lock status */#define	BLOCK_CONFIG_MASK	0xFFFFF000#define	BLOCK_CONFIG_ADDR	0x02enum {	/* Addresses */	ADDR_UNLOCK_1			= 0x0555,	ADDR_UNLOCK_2			= 0x02AA,	ADDR_MANUFACTURER		= 0x0000,	ADDR_DEVICE_ID			= 0x0001,	ADDR_CFI_QUERY			= 0x0055,	/* Commands */	CMD_UNLOCK_DATA_1		= 0x00AA,	CMD_UNLOCK_DATA_2		= 0x0055,	CMD_MANUFACTURER_UNLOCK_DATA	= 0x0090,	CMD_PROGRAM_UNLOCK_DATA		= 0x00A0,	CMD_RESET_DATA			= 0x00F0,	CMD_SECTOR_ERASE_UNLOCK_DATA_1	= 0x0080,	CMD_SECTOR_ERASE_UNLOCK_DATA_2	= 0x0030,	CMD_CFI_QUERY_DATA		= 0x0098,	/* Intel CMDs */	CMDI_READ_ARRAY			= 0xFF,	CMDI_READ_CONFIG		= 0x90,	CMDI_READ_QRY			= 0x98,	CMDI_READ_STATUS		= 0x70,	CMDI_CLEAR_STATUS		= 0x50,	CMDI_PROGRAM			= 0x40,	CMDI_BLOCK_ERASE		= 0x20,	CMDI_BLOCK_CONFIRM		= 0xD0,	CMDI_SUSPEND			= 0xB0,	CMDI_RESUME			= 0xD0,	CMDI_LOCK_CONFIG		= 0x60,	CMDI_LOCK			= 0x01,	CMDI_UNLOCK			= 0xD0,	CMDI_LOCKDOWN			= 0x2F,	CMDI_PROTECT_PROGRAM		= 0xC0,	CMDI_WRITE_BUFFER		= 0xE8,	CMDI_WRITE_BUFFER_CONFIRM	= 0xD0, 		/* Offsets */	OFFSET_CFI_ID			= 0x10,	OFFSET_CFI_SIZE			= 0x27,	OFFSET_CFI_BUFFER_SIZE		= 0x2A,	OFFSET_CFI_BLOCK_COUNT		= 0x2C,	OFFSET_CFI_BLOCK		= 0x2D,	/* Manufacturers */	MANUFACTURER_AMD		= 0x01,	MANUFACTURER_FUJITSU		= 0x04,	MANUFACTURER_SST		= 0xBF,	MANUFACTURER_ST			= 0x20,	MANUFACTURER_TOSHIBA		= 0x98,	MANUFACTURER_INTEL		= 0x89,	/* Intel devices */	TE28F800C3T			= 0x88C0,	TE28F800C3B			= 0x88C1,	TE28F160C3T			= 0x88C2,	TE28F160C3B			= 0x88C3,	TE28F320C3T			= 0x88C4,	TE28F320C3B			= 0x88C5,	TE28F640C3T			= 0x88CC,	TE28F640C3B			= 0x88CD,	TE28F320J3A			= 0x0016,	TE28F640J3A			= 0x0017,	TE28F128J3A			= 0x0018,	/* AMD devices */	AM29F800BB			= 0x2258,	AM29F800BT			= 0x22D6,	AM29LV800BB			= 0x225B,	AM29LV800BT			= 0x22DA,	AM29LV160BT			= 0x22C4,	/* Fujitsu devices */	MBM29LV160TE			= 0x22C4,	MBM29LV160BE			= 0x2249,	/* SST devices */	SST39LF800			= 0x2781,	SST39LF160			= 0x2782,	/* ST devices */	M29W800T			= 0x00D7, /* Used in 5600, similar to						  * AM29LV800, but no unlock						  * bypass						  */	/* Toshiba devices */	TC58FVT160			= 0x00C2,	TC58FVB160			= 0x0043,	TC58FVT800			= 0x004F,	/* Toggle bit mask */	D6_MASK				= 0x40};typedef struct flash_type {	volatile unsigned char *base;	udword type;	byte interleave;	byte buswidth;	volatile unsigned char *boot_sector;	udword mfr;	udword dev_id;	unsigned int size;	unsigned int sector_size;	unsigned int boot_sector_size[8];	unsigned int buffer_size;		// StrataFlash} flash_t;/* Allocate flash structures and initialize base. */static flash_t flashes[2] = {	{ (unsigned char *)0x80000000 },	{ (unsigned char *)0x84000000 }};static intwide_read(flash_t *flash, unsigned long offset) {	switch (flash->buswidth) {		case 2:FDEBUG(send_serial_hex((uword *)(flash->base + offset), 0);)FDEBUG(safe_printk(" => ");)FDEBUG(send_serial_hex(*((uword *)(flash->base + offset)), NL);)			return *((uword *)(flash->base + offset));		case 4:FDEBUG(send_serial_hex((udword *)(flash->base + offset), 0);)FDEBUG(safe_printk(" => ");)FDEBUG(send_serial_hex(*((udword *)(flash->base + offset)), NL);)			return *((udword *)(flash->base + offset));	}	return 0;}static intwide_write_chunk(flash_t *flash, unsigned long offset,		 const unsigned char *chunk) {	switch (flash->buswidth) {		case 2:			*((uword *)(flash->base + offset)) = *((uword *)chunk);FDEBUG(send_serial_hex(((uword *)(flash->base + offset)), 0);)FDEBUG(safe_printk(" <= ");)FDEBUG(send_serial_hex(*((uword *)chunk), NL);)			return 2;		case 4:			*((udword *)(flash->base + offset)) =				*((udword *)chunk);FDEBUG(send_serial_hex(((udword *)(flash->base + offset)), 0);)FDEBUG(safe_printk(" <= ");)FDEBUG(send_serial_hex(*((udword *)chunk), NL);)			return 4;	}	return 0;}static voidwide_cmd(flash_t *flash, udword cmd, unsigned long offset) {	if ((flash->interleave == 1) && (flash->type == TYPE_X16)) {		offset <<= 1;	} else if ((flash->interleave == 2) && (flash->type == TYPE_X16)) {		cmd |= (cmd << 16);		offset <<= 2;	} else {		safe_printk("Unsupported!\n");		return;	}FDEBUG(send_serial_hex(flash->base + offset, 0);)FDEBUG(safe_printk(" cmd ");)FDEBUG(send_serial_hex(cmd, NL);)	switch (flash->buswidth) {		case 2:			*((uword *)(flash->base + offset)) = (uword)cmd;			break;		case 4:			*((udword *)(flash->base + offset)) = cmd;			break;	}}// differs from here#ifdef MYINTELstatic intwait_flash_ready(flash_t *flash){	udword data32;		/* give time for busy signal to be ready */	nop(); nop(); nop(); nop(); nop();	nop(); nop(); nop(); nop(); nop();	if (flash->interleave == 2) {	// wait write operation is over	  while ((~(data32=wide_read(flash, 0))) & ((INTEL_SRB_WSMS) | (INTEL_SRB_WSMS << 16)));	  return (data32 | (data32>>16)) & (		INTEL_SRB_ESS |		INTEL_SRB_ES |		INTEL_SRB_PS |		INTEL_SRB_VPPS |		INTEL_SRB_PSS |		INTEL_SRB_BLS );	} else {	  while ((~(data32=wide_read(flash, 0))) & INTEL_SRB_WSMS);	  return data32 & (		INTEL_SRB_ESS |		INTEL_SRB_ES |		INTEL_SRB_PS |		INTEL_SRB_VPPS |		INTEL_SRB_PSS |		INTEL_SRB_BLS );	}	}#elsestatic voidflash_unlock(flash_t *flash) {	wide_cmd(flash, CMD_UNLOCK_DATA_1, ADDR_UNLOCK_1);	wide_cmd(flash, CMD_UNLOCK_DATA_2, ADDR_UNLOCK_2);}static intflash_is_busy(flash_t *flash, unsigned long offset){	if (flash->interleave == 2) {		udword read1, read2;		read1 = wide_read(flash, offset);		read2 = wide_read(flash, offset);		return (((read1 >> 16) & D6_MASK) !=			((read2 >> 16) & D6_MASK)) ||		       (((read1 & 0xffff) & D6_MASK) !=		        ((read2 & 0xffff) & D6_MASK));	}	return ((wide_read(flash, offset) & D6_MASK) !=		(wide_read(flash, offset) & D6_MASK));}#endifstatic int try_cfi(flash_t *flash){	int offset_shift = 1;	if (flash->interleave == 2) {		offset_shift = 2;	}	/* Enter CFI mode */	wide_cmd(flash, CMD_CFI_QUERY_DATA, ADDR_CFI_QUERY);	/* Check if flash responds correctly */	if ((byte)wide_read(flash, (OFFSET_CFI_ID+0) << offset_shift) == 'Q' &&	    (byte)wide_read(flash, (OFFSET_CFI_ID+1) << offset_shift) == 'R' &&	    (byte)wide_read(flash, (OFFSET_CFI_ID+2) << offset_shift) == 'Y') {		int block;            /* Current block */		int block_count;      /* Number of blocks */ 		char boot_sector = 0; /* Current boot sector */		int offset = 0;       /* Offset into flash */		int reverse = 0;      /* Reverse block table */		int primary;          /* Offset to vendor specific table */    		safe_printk("CFI dev "); 		send_serial_hex((udword)flash->base, NL);    		flash->size =			1 << wide_read(flash, OFFSET_CFI_SIZE << offset_shift);/* Buffer write support */		flash->buffer_size =			1 << wide_read(flash, OFFSET_CFI_BUFFER_SIZE << offset_shift);		flash->buffer_size >>=1; // (bytes -> words)		/* CFI stores flash organization in blocks. Each block contains		 * a number of sectors with the same size		 */		block_count = wide_read(flash, OFFSET_CFI_BLOCK_COUNT <<					       offset_shift);    		/* Check if table is reversed */		primary = wide_read(flash, (OFFSET_CFI_ID+5) << offset_shift);		/* For CFI version 1.0 we don't know. Assume that id & 0x80 */		/* indicates top boot */ #ifdef MYINTEL        reverse=0;#else		if ((byte)wide_read(flash, (primary+4) << offset_shift) == 0x30)		{			/* read device id */			wide_cmd(flash, CMD_RESET_DATA, ADDR_UNLOCK_1);			flash_unlock(flash);			wide_cmd(flash, CMD_MANUFACTURER_UNLOCK_DATA, ADDR_UNLOCK_1);			reverse = wide_read(flash, ADDR_DEVICE_ID * TYPE_X16 * flash->interleave) & 0x80;			wide_cmd(flash, CMD_CFI_QUERY_DATA, ADDR_CFI_QUERY);		}		else		{			reverse = ((byte)wide_read(flash, (primary+15) << offset_shift) == 3);		}#endif                /* Blocks are stored backwards compared to flash organization */		for (block = reverse ? block_count - 1 : 0; 		     reverse ? block >= 0 : block < block_count; 		     reverse ? block-- : block++) {			/* Size of each sector in block. Size is stored as			 * sector_size / 256.			 */			int sector_size =			    (wide_read(flash, (OFFSET_CFI_BLOCK+block * 4+2) <<			    		      offset_shift)				|			    (wide_read(flash, (OFFSET_CFI_BLOCK+block * 4+3) <<			    		      offset_shift) << 8)			    ) << 8;			/* Number of sectors */			int sector_count =			    (wide_read(flash, (OFFSET_CFI_BLOCK+block * 4+0) <<			    		      offset_shift)				|			    (wide_read(flash, (OFFSET_CFI_BLOCK+block * 4+1) <<			    		      offset_shift) << 8)			    ) + 1;			    			if (sector_count > 8) {				/* Not boot sectors */					int temp;								flash->sector_size = sector_size;				/* Can't use multiplication (we have no lib). */				for (temp = 0 ; temp < sector_count ; temp++) {					offset += sector_size;                                }			} else {				/* Boot sectors */				if (boot_sector == 0) {					/* Set boot sector start */					flash->boot_sector =						flash->base + offset;				}        				for (; sector_count > 0; sector_count--) {					flash->boot_sector_size[						(udword)(boot_sector++)					] = sector_size;                                        offset += sector_size;				}			}                                                /* Some flashes (SST) store information about alternate			 * block sizes. Ignore those by breaking when the sum			 * of the sector sizes == flash size.			 */                        if (offset == flash->size) {				break;                        }		}		/* reset */#ifdef MYINTEL		/* switch to read array mode */		wide_cmd(flash, CMDI_READ_ARRAY, 0);#else		flash_unlock(flash);		wide_cmd(flash, CMD_RESET_DATA, ADDR_UNLOCK_1);#endif		return 1;	}	/* reset */#ifdef MYINTEL	/* switch to read array mode */	wide_cmd(flash, CMDI_READ_ARRAY, 0);#else	flash_unlock(flash);	wide_cmd(flash, CMD_RESET_DATA, ADDR_UNLOCK_1);#endif  	return 0;}static intflash_probe(flash_t *flash){#ifndef MYINTEL	char *message;#endif	if (try_cfi(flash)) {		return 1;	} else if (flash->interleave == 1) {		safe_printk("No 1x CFI at ");		send_serial_hex((udword)flash->base, NL);	}#ifdef MYINTEL	return 0; // no cfi found#else	/* read manufacturer */	flash_unlock(flash);	wide_cmd(flash, CMD_MANUFACTURER_UNLOCK_DATA, ADDR_UNLOCK_1);

⌨️ 快捷键说明

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