diff options
| author | Lunsheng Wang <lunsheng@sohu.com> | 2005-07-29 10:20:29 -0500 | 
|---|---|---|
| committer | Jon Loeliger <jdl@freescale.com> | 2005-07-29 10:20:29 -0500 | 
| commit | b0e32949239c7870d409ca687a2dfc1261a3d838 (patch) | |
| tree | ca388e33fad2066128d6d34ceb54eeeb07a71710 /board/mpc8540eval/flash.c | |
| parent | a720fd99b614ba36293565771bcd19799bc53959 (diff) | |
| download | olio-uboot-2014.01-b0e32949239c7870d409ca687a2dfc1261a3d838.tar.xz olio-uboot-2014.01-b0e32949239c7870d409ca687a2dfc1261a3d838.zip | |
* Patch by Ron Alder, 11 July 2005
    Add Xianghua Xiao and Lunsheng Wang's support for the
    GDA MPC8540 EVAL board.
Diffstat (limited to 'board/mpc8540eval/flash.c')
| -rw-r--r-- | board/mpc8540eval/flash.c | 892 | 
1 files changed, 892 insertions, 0 deletions
| diff --git a/board/mpc8540eval/flash.c b/board/mpc8540eval/flash.c new file mode 100644 index 000000000..7300a041a --- /dev/null +++ b/board/mpc8540eval/flash.c @@ -0,0 +1,892 @@ +/* + * (C) Copyright 2003 Motorola Inc. + *  Xianghua Xiao,(X.Xiao@motorola.com) + * + * (C) Copyright 2000, 2001 + *  Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2001, Stuart Hughes, Lineo Inc, stuarth@lineo.com + * Add support the Sharp chips on the mpc8260ads. + * I started with board/ip860/flash.c and made changes I found in + * the MTD project by David Schleef. + * + * 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> + +#if !defined(CFG_NO_FLASH) + +flash_info_t	flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips	*/ + +#if defined(CFG_ENV_IS_IN_FLASH) +# ifndef  CFG_ENV_ADDR +#  define CFG_ENV_ADDR	(CFG_FLASH_BASE + CFG_ENV_OFFSET) +# endif +# ifndef  CFG_ENV_SIZE +#  define CFG_ENV_SIZE	CFG_ENV_SECT_SIZE +# endif +# ifndef  CFG_ENV_SECT_SIZE +#  define CFG_ENV_SECT_SIZE  CFG_ENV_SIZE +# endif +#endif + +/* + * The variable should be in the flash info structure. Since it + * is only used in this board specific file it is declared here. + * In the future I think an endian flag should be part of the + * flash_info_t structure. (Ron Alder) + */ +static ulong big_endian = 0; + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size (vu_long *addr, flash_info_t *info); +static int write_block (flash_info_t *info, uchar * src, ulong dest, ulong cnt); +static int write_short (flash_info_t *info, ulong dest, ushort data); +static int write_word (flash_info_t *info, ulong dest, ulong data); +static int clear_block_lock_bit(flash_info_t *info, vu_long * addr); +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init (void) +{ +	unsigned long size; +	int i; + +	/* Init: enable write, +	 * or we cannot even write flash commands +	 */ +	for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) { +		flash_info[i].flash_id = FLASH_UNKNOWN; + +		/* set the default sector offset */ +	} + +	/* Static FLASH Bank configuration here - FIXME XXX */ + +	size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]); + +	if (flash_info[0].flash_id == FLASH_UNKNOWN) { +		printf ("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n", +			size, size<<20); +	} + +	/* Re-do sizing to get full correct info */ +	size = flash_get_size((vu_long *)CFG_FLASH_BASE, &flash_info[0]); + +	flash_info[0].size = size; + +#if !defined(CONFIG_RAM_AS_FLASH) +#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_info[0]); +#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_SECT_SIZE-1, +		      &flash_info[0]); +#endif +#endif +	return (size); +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info  (flash_info_t *info) +{ +	int i; + +	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; +	case FLASH_MAN_SHARP:   printf ("Sharp ");		break; +	default:		printf ("Unknown Vendor ");	break; +	} + +	switch (info->flash_id & FLASH_TYPEMASK) { +	case FLASH_28F016SV:	printf ("28F016SV (16 Mbit, 32 x 64k)\n"); +				break; +	case FLASH_28F160S3:	printf ("28F160S3 (16 Mbit, 32 x 512K)\n"); +				break; +	case FLASH_28F320S3:	printf ("28F320S3 (32 Mbit, 64 x 512K)\n"); +				break; +	case FLASH_LH28F016SCT: printf ("28F016SC (16 Mbit, 32 x 64K)\n"); +				break; +	case FLASH_28F640J3A:   printf ("28F640J3A (64 Mbit, 64 x 128K)\n"); +				break; +	default:		printf ("Unknown Chip Type\n"); +				break; +	} + +	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"); +} + + /* only deal with 16 bit and 32 bit port width, 16bit chip */ +static ulong flash_get_size (vu_long *addr, flash_info_t *info) +{ +	short i; +	ulong value,va,vb,vc,vd; +	ulong base = (ulong)addr; +	ulong sector_offset; + +#ifdef DEBUG +	printf("Check flash at 0x%08x\n",(uint)addr); +#endif +	/* Write "Intelligent Identifier" command: read Manufacturer ID */ +	*addr = 0x90909090; +	udelay(20); +	asm("sync"); + +#ifndef CFG_FLASH_CFI +	printf("Not define CFG_FLASH_CFI\n"); +	return (0); +#else +	value = addr[0]; +	va=(value & 0xFF000000)>>24; +	vb=(value & 0x00FF0000)>>16; +	vc=(value & 0x0000FF00)>>8; +	vd=(value & 0x000000FF); +	if ((va==0) && (vb==0)) { +		printf("cannot identify Flash\n"); +		info->flash_id = FLASH_UNKNOWN; +		info->sector_count = 0; +		info->size = 0; +		return (0);			/* no or unknown flash	*/ +	} +	else if ((va==0) && (vb!=0)) { +		big_endian = 1; +		info->chipwidth = FLASH_CFI_BY16; +		if(vb == vd) info->portwidth = FLASH_CFI_32BIT; +		else info->portwidth = FLASH_CFI_16BIT; +	} +	else if ((va!=0) && (vb==0)) { +		big_endian = 0; +		info->chipwidth = FLASH_CFI_BY16; +		if(va == vc) info->portwidth = FLASH_CFI_32BIT; +		else info->portwidth = FLASH_CFI_16BIT; +	} +	else if ((va!=0) && (vb!=0)) { +		big_endian = 1;		/* no meaning for 8bit chip */ +		info->chipwidth = FLASH_CFI_BY8; +		if(va == vb) info->portwidth = FLASH_CFI_16BIT; +		else info->portwidth = FLASH_CFI_8BIT; +	} +#ifdef DEBUG +	switch (info->portwidth) { +		case FLASH_CFI_8BIT: +			printf("port width is 8 bit.\n"); +			break; +		case FLASH_CFI_16BIT: +			printf("port width is 16 bit, "); +			break; +		case FLASH_CFI_32BIT: +			printf("port width is 32 bit, "); +			break; +	} +	switch (info->chipwidth) { +		case FLASH_CFI_BY16: +			printf("chip width is 16 bit, "); +			switch (big_endian) { +				case 0: +					printf("Little Endian.\n"); +					break; +				case 1: +					printf("Big Endian.\n"); +					break; +			} +			break; +	} +#endif +#endif		/*#ifdef CFG_FLASH_CFI*/ + +	if (big_endian==0) value = (addr[0] & 0xFF000000) >>8; +	else value = (addr[0] & 0x00FF0000); +#ifdef DEBUG +	printf("manufacturer=0x%x\n",(uint)(value>>16)); +#endif +	switch (value) { +	case MT_MANUFACT & 0xFFFF0000:	/* SHARP, MT or => Intel */ +	case INTEL_ALT_MANU & 0xFFFF0000: +		info->flash_id = FLASH_MAN_INTEL; +		break; +	default: +		printf("unknown manufacturer: %x\n", (unsigned int)value); +		info->flash_id = FLASH_UNKNOWN; +		info->sector_count = 0; +		info->size = 0; +		return (0);			/* no or unknown flash	*/ +	} + +	if (info->portwidth==FLASH_CFI_16BIT) { +		switch (big_endian) { +			case 0: +				value = (addr[0] & 0x0000FF00)>>8; +				break; +			case 1: +				value = (addr[0] & 0x000000FF); +				break; +		} +	} +	else if (info->portwidth == FLASH_CFI_32BIT) { +		switch (big_endian) { +			case 0: +				value = (addr[1] & 0x0000FF00)>>8; +				break; +			case 1: +				value = (addr[1] & 0x000000FF); +				break; +		} +	} + +#ifdef DEBUG +	printf("deviceID=0x%x\n",(uint)value); +#endif +	switch (value) { +	case (INTEL_ID_28F016S & 0x0000FFFF): +		info->flash_id += FLASH_28F016SV; +		info->sector_count = 32; +		sector_offset = 0x10000; +		break;				/* => 2 MB		*/ + +	case (INTEL_ID_28F160S3 & 0x0000FFFF): +		info->flash_id += FLASH_28F160S3; +		info->sector_count = 32; +		sector_offset = 0x10000; +		break;				/* => 2 MB		*/ + +	case (INTEL_ID_28F320S3 & 0x0000FFFF): +		info->flash_id += FLASH_28F320S3; +		info->sector_count = 64; +		sector_offset = 0x10000; +		break;				/* => 4 MB		*/ + +	case (INTEL_ID_28F640J3A & 0x0000FFFF): +		info->flash_id += FLASH_28F640J3A; +		info->sector_count = 64; +		sector_offset = 0x20000; +		break;                          /* => 8 MB             */ + +	case SHARP_ID_28F016SCL & 0x0000FFFF: +	case SHARP_ID_28F016SCZ & 0x0000FFFF: +		info->flash_id      = FLASH_MAN_SHARP | FLASH_LH28F016SCT; +		info->sector_count  = 32; +		sector_offset = 0x10000; +		break;				/* => 2 MB		*/ + + +	default: +		info->flash_id = FLASH_UNKNOWN; +		return (0);			/* => no or unknown flash */ + +	} + +	sector_offset = sector_offset * (info->portwidth / info->chipwidth); +	info->size = info->sector_count * sector_offset; + +	/* set up sector start address table */ +	for (i = 0; i < info->sector_count; i++) { +		info->start[i] = base; +		base += sector_offset; +		/* don't know how to check sector protection */ +		info->protect[i] = 0; +	} + +	/* +	 * Prevent writes to uninitialized FLASH. +	 */ +	if (info->flash_id != FLASH_UNKNOWN) { +		addr = (vu_long *)info->start[0]; +		*addr = 0xFFFFFF;	/* reset bank to read array mode */ +		asm("sync"); +	} + +	return (info->size); +} + + +/*----------------------------------------------------------------------- + */ + +int	flash_erase (flash_info_t *info, int s_first, int s_last) +{ +	int flag, prot, sect; +	ulong start, now, last, ready, erase_err_status; + +	if (big_endian == 1) { +		ready = 0x0080; +		erase_err_status = 0x00a0; +	} +	else { +		ready = 0x8000; +		erase_err_status = 0xa000; +	} +	if ((info->portwidth / info->chipwidth)==2) { +		ready += (ready <<16); +		erase_err_status += (erase_err_status <<16); +	} + +#ifdef DEBUG +	printf ("\nReady flag is 0x%lx\nErase error flag is 0x%lx", ready, erase_err_status); +#endif + +	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; +	} + +	if (    ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_INTEL) +	     && ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_SHARP) ) { +		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!\n", +			prot); +	} else { +		printf ("\n"); +	} + +#ifdef DEBUG +	printf("\nFlash Erase:\n"); +#endif +	/* Make Sure Block Lock Bit is not set. */ +	if(clear_block_lock_bit(info, (vu_long *)(info->start[s_first]))){ +		return 1; +	} + +	/* Start erase on unprotected sectors */ +#if defined(DEBUG) +	printf("Begin to erase now,s_first=0x%x s_last=0x%x...\n",s_first,s_last); +#endif +	for (sect = s_first; sect<=s_last; sect++) { +		if (info->protect[sect] == 0) {	/* not protected */ +			vu_short *addr16 = (vu_short *)(info->start[sect]); +			vu_long *addr   = (vu_long *)(info->start[sect]); +			printf("."); +			switch (info->portwidth) { +				case FLASH_CFI_16BIT: +					asm("sync"); +					last = start = get_timer (0); +					/* Disable interrupts which might cause a timeout here */ +					flag = disable_interrupts(); +					/* Reset Array */ +					*addr16 = 0xffff; +					asm("sync"); +					/* Clear Status Register */ +					*addr16 = 0x5050; +					asm("sync"); +					/* Single Block Erase Command */ +					*addr16 = 0x2020; +					asm("sync"); +					/* Confirm */ +					*addr16 = 0xD0D0; +					asm("sync"); +					if((info->flash_id & FLASH_TYPEMASK) != FLASH_LH28F016SCT) { +					    /* Resume Command, as per errata update */ +					    *addr16 = 0xD0D0; +					    asm("sync"); +					} +					/* re-enable interrupts if necessary */ +					if (flag) +						enable_interrupts(); +					/* wait at least 80us - let's wait 1 ms */ +					*addr16 = 0x7070; +					udelay (1000); +					while ((*addr16 & ready) != ready) { +						if((*addr16 & erase_err_status)== erase_err_status){ +							printf("Error in Block Erase - Lock Bit may be set!\n"); +							printf("Status Register = 0x%X\n", (uint)*addr16); +							*addr16 = 0xFFFF;	/* reset bank */ +							asm("sync"); +							return 1; +						} +						if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) { +							printf ("Timeout\n"); +							*addr16 = 0xFFFF;	/* reset bank */ +							asm("sync"); +							return 1; +						} +						/* show that we're waiting */ +						if ((now - last) > 1000) {	/* every second */ +							putc ('.'); +							last = now; +						} +					} +					/* reset to read mode */ +					*addr16 = 0xFFFF; +					asm("sync"); +					break; +				case FLASH_CFI_32BIT: +					asm("sync"); +					last = start = get_timer (0); +					/* Disable interrupts which might cause a timeout here */ +					flag = disable_interrupts(); +					/* Reset Array */ +					*addr = 0xffffffff; +					asm("sync"); +					/* Clear Status Register */ +					*addr = 0x50505050; +					asm("sync"); +					/* Single Block Erase Command */ +					*addr = 0x20202020; +					asm("sync"); +					/* Confirm */ +					*addr = 0xD0D0D0D0; +					asm("sync"); +					if((info->flash_id & FLASH_TYPEMASK) != FLASH_LH28F016SCT) { +					    /* Resume Command, as per errata update */ +					    *addr = 0xD0D0D0D0; +					    asm("sync"); +					} +					/* re-enable interrupts if necessary */ +					if (flag) +						enable_interrupts(); +					/* wait at least 80us - let's wait 1 ms */ +					*addr = 0x70707070; +					udelay (1000); +					while ((*addr & ready) != ready) { +						if((*addr & erase_err_status)==erase_err_status){ +							printf("Error in Block Erase - Lock Bit may be set!\n"); +							printf("Status Register = 0x%X\n", (uint)*addr); +							*addr = 0xFFFFFFFF;	/* reset bank */ +							asm("sync"); +							return 1; +						} +						if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) { +							printf ("Timeout\n"); +							*addr = 0xFFFFFFFF;	/* reset bank */ +							asm("sync"); +							return 1; +						} +						/* show that we're waiting */ +						if ((now - last) > 1000) {	/* every second */ +							putc ('.'); +							last = now; +						} +					} +					/* reset to read mode */ +					*addr = 0xFFFFFFFF; +					asm("sync"); +					break; +			}	/* end switch */ +		}		/* end if */ +	}			/* end for */ + +	printf ("flash erase done\n"); +	return 0; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ + +#define FLASH_BLOCK_SIZE 32 + +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ +	ulong cp, wp, data, count, temp; +/*	ulong temp[FLASH_BLOCK_SIZE/4];*/ +	int i, l, rc; + +	count = cnt; +	wp = (addr & ~3);	/* get lower word aligned address */ + +	/* +	 * handle unaligned start bytes +	 */ +	if ((l = addr - wp) != 0) { +		data = 0; +		for (i=0, cp=wp; i<l; ++i, ++cp) { +			data = (data << 8) | (*(uchar *)cp); +		} +		for (; i<4 && cnt>0; ++i) { +			data = (data << 8) | *src++; +			--cnt; +			++cp; +		} +		for (; cnt==0 && i<4; ++i, ++cp) { +			data = (data << 8) | (*(uchar *)cp); +		} + +		if ((rc = write_word(info, wp, data)) != 0) { +			return (rc); +		} +		wp += 4; +	} + +	cp = wp; +	/* handle unaligned block bytes , flash block size = 16bytes */ +	wp = (cp+FLASH_BLOCK_SIZE-1) & ~(FLASH_BLOCK_SIZE-1); +	if ((wp-cp)>=cnt) { +		if ((rc = write_block(info,src,cp,wp-cp)) !=0) +			return (rc); +		src += wp-cp; +		cnt -= wp-cp; +	} +	/* handle aligned block bytes */ +	temp = 0; +	printf("\n"); +	while ( cnt >= FLASH_BLOCK_SIZE) { +		if ((rc = write_block(info,src,cp,FLASH_BLOCK_SIZE)) !=0) { +			return (rc); +		} +		src += FLASH_BLOCK_SIZE; +		cp += FLASH_BLOCK_SIZE; +		cnt -= FLASH_BLOCK_SIZE; +		if (((count-cnt)>>10)>temp) { +			temp=(count-cnt)>>10; +			printf("\r%d KB",temp); +		} +	} +	printf("\n"); +	wp = cp; +	/* +	 * handle word aligned part +	 */ +	while (cnt >= 4) { +		data = 0; +		for (i=0; i<4; ++i) { +			data = (data << 8) | *src++; +		} +		if ((rc = write_word(info, wp, data)) != 0) { +			return (rc); +		} +		wp  += 4; +		cnt -= 4; +	} + +	if (cnt == 0) { +		return (0); +	} + +	/* +	 * handle unaligned tail bytes +	 */ +	data = 0; +	for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { +		data = (data << 8) | *src++; +		--cnt; +	} +	for (; i<4; ++i, ++cp) { +		data = (data << 8) | (*(uchar *)cp); +	} + +	return (write_word(info, wp, data)); +} +#undef FLASH_BLOCK_SIZE + +/*----------------------------------------------------------------------- + * Write block to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + * -1  Error + */ +static int write_block(flash_info_t *info, uchar * src, ulong dest, ulong cnt) +{ +	vu_short *baddr, *addr = (vu_short *)dest; +	ushort data; +	ulong start, now, xsr,csr, ready; +	int flag; + +	if (cnt==0) return 0; +	else if(cnt != (cnt& ~1)) return -1; + +	/* Check if Flash is (sufficiently) erased */ +	data = * src; +	data = (data<<8) | *(src+1); +	if ((*addr & data) != data) { +		return (2); +	} +	if (big_endian == 1) { +		ready = 0x0080; +	} +	else { +		ready = 0x8000; +	} +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts(); + +		do { +			/* Write Command */ +			*addr = 0xe8e8; +			asm("sync"); +			xsr = *addr; +			asm("sync"); +		} while (!(xsr & ready));	/*wait until read */ +		/*write count=BLOCK SIZE -1 */ +		data=(cnt>>1)-1; +		data=(data<<8)|data; +		*addr = data;		/* word mode, cnt/2 */ +		asm("sync"); +		baddr = addr; +		while(cnt) { +			data = * src++; +			data = (data<<8) | *src++; +			asm("sync"); +			*baddr = data; +			asm("sync"); +			++baddr; +			cnt = cnt -2; +		} +		*addr = 0xd0d0;			/* confirm write */ +		start = get_timer(0); +		asm("sync"); +		if (flag) +			enable_interrupts(); +		/* data polling for D7 */ +		flag  = 0; +		while (((csr = *addr) & ready) != ready) { +			if ((now=get_timer(start)) > CFG_FLASH_WRITE_TOUT) { +				flag = 1; +				break; +			} +		} +		if (csr & 0x4040) { +			printf ("CSR indicates write error (%04x) at %08lx\n", csr, (ulong)addr); +			flag = 1; +		} +		/* Clear Status Registers Command */ +		*addr = 0x5050; +		asm("sync"); +		/* Reset to read array mode */ +		*addr = 0xFFFF; +		asm("sync"); +	return (flag); +} + + +/*----------------------------------------------------------------------- + * Write a short word to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_short (flash_info_t *info, ulong dest, ushort data) +{ +	vu_short *addr = (vu_short *)dest; +	ulong start, now, csr, ready; +	int flag; + +	/* Check if Flash is (sufficiently) erased */ +	if ((*addr & data) != data) { +		return (2); +	} +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts(); + +		/* Write Command */ +		*addr = 0x1010; +		start = get_timer (0); +		asm("sync"); +		/* Write Data */ +		*addr = data; +		asm("sync"); +		/* re-enable interrupts if necessary */ +		if (flag) +			enable_interrupts(); +		if (big_endian == 1) { +			ready = 0x0080; +		} +		else { +			ready = 0x8000; +		} +		/* data polling for D7 */ +		flag  = 0; +		while (((csr = *addr) & ready) != ready) { +			if ((now=get_timer(start)) > CFG_FLASH_WRITE_TOUT) { +				flag = 1; +				break; +			} +		} +		if (csr & 0x4040) { +			printf ("CSR indicates write error (%04x) at %08lx\n", csr, (ulong)addr); +			flag = 1; +		} +		/* Clear Status Registers Command */ +		*addr = 0x5050; +		asm("sync"); +		/* Reset to read array mode */ +		*addr = 0xFFFF; +		asm("sync"); +	return (flag); +} + +/*----------------------------------------------------------------------- + * Write a word to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_word (flash_info_t *info, ulong dest, ulong data) +{ +	vu_long *addr = (vu_long *)dest; +	ulong start, csr, ready; +	int flag=0; + +	switch (info->portwidth) { +	case FLASH_CFI_32BIT: +		/* Check if Flash is (sufficiently) erased */ +		if ((*addr & data) != data) { +			return (2); +		} +		/* Disable interrupts which might cause a timeout here */ +		flag = disable_interrupts(); + +		if (big_endian == 1) { +			ready = 0x0080; +		} +		else { +			ready = 0x8000; +		} +		if ((info->portwidth / info->chipwidth)==2) { +			ready += (ready <<16); +		} +		else { +			ready = ready << 16; +		} +		/* Write Command */ +		*addr = 0x10101010; +		asm("sync"); +		/* Write Data */ +		*addr = data; +		/* re-enable interrupts if necessary */ +		if (flag) +			enable_interrupts(); +		/* data polling for D7 */ +		start = get_timer (0); +		flag  = 0; +		while (((csr = *addr) & ready) != ready) { +			if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { +				flag = 1; +				break; +			} +		} +		if (csr & 0x40404040) { +			printf ("CSR indicates write error (%08lx) at %08lx\n", csr, (ulong)addr); +			flag = 1; +		} +		/* Clear Status Registers Command */ +		*addr = 0x50505050; +		asm("sync"); +		/* Reset to read array mode */ +		*addr = 0xFFFFFFFF; +		asm("sync"); +		break; +	case FLASH_CFI_16BIT: +		flag = write_short (info, dest,  (unsigned short) (data>>16)); +		if (flag == 0) +			flag = write_short (info, dest+2,  (unsigned short) (data)); +		break; +	} +	return (flag); +} + +/*----------------------------------------------------------------------- + * Clear Block Lock Bit, returns: + * 0 - OK + * 1 - Timeout + */ + +static int clear_block_lock_bit(flash_info_t * info, vu_long  * addr) +{ +	ulong start, now, ready; + +	/* Reset Array */ +	*addr = 0xffffffff; +	asm("sync"); +	/* Clear Status Register */ +	*addr = 0x50505050; +	asm("sync"); + +	*addr = 0x60606060; +	asm("sync"); +	*addr = 0xd0d0d0d0; +	asm("sync"); + + +	if (big_endian == 1) { +		ready = 0x0080; +	} +	else { +		ready = 0x8000; +	} +	if ((info->portwidth / info->chipwidth)==2) { +		ready += (ready <<16); +	} +	else { +		ready = ready << 16; +	} +#ifdef DEBUG +	printf ("%s: Ready flag is 0x%8lx\n", __FUNCTION__, ready); +#endif +	*addr = 0x70707070;	/* read status */ +	start = get_timer (0); +	while((*addr & ready) != ready){ +		if ((now=get_timer(start)) > CFG_FLASH_ERASE_TOUT) { +			printf ("Timeout on clearing Block Lock Bit\n"); +			*addr = 0xFFFFFFFF;	/* reset bank */ +			asm("sync"); +			return 1; +		} +	} +	return 0; +} + +#endif /* !CFG_NO_FLASH */ |