diff options
Diffstat (limited to 'board/emk/top860/flash.c')
| -rw-r--r-- | board/emk/top860/flash.c | 490 | 
1 files changed, 490 insertions, 0 deletions
| diff --git a/board/emk/top860/flash.c b/board/emk/top860/flash.c new file mode 100644 index 000000000..a9a977114 --- /dev/null +++ b/board/emk/top860/flash.c @@ -0,0 +1,490 @@ +/* + * (C) Copyright 2003 + * EMK Elektronik GmbH <www.emk-elektronik.de> + * Reinhard Meyer <r.meyer@emk-elektronik.de> + *
 + * copied from the BMW Port - seems that its similiar enough
 + * to be easily adaped ;) --- Well, it turned out to become a
 + * merger between parts of the EMKstax Flash routines and the
 + * BMW funtion frames...
 + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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> +#include <mpc8xx.h> + +#define	FLASH_WORD_SIZE		unsigned short +#define FLASH_WORD_WIDTH	(sizeof (FLASH_WORD_SIZE))
 +
 +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips    */ +
 +/*----------------------------------------------------------------------- + * Functions + */ +static int write_word (flash_info_t *info, ulong dest, ulong data); + + +/*****************************************************************************
 + * software product ID entry/exit
 + *****************************************************************************/
 +static void FlashProductIdMode (
 +	volatile FLASH_WORD_SIZE *b,
 +	int on_off)
 +{
 +	b[0x5555] = 0xaa;
 +	b[0x2aaa] = 0x55;
 +	b[0x5555] = on_off ? 0x90 : 0xf0;
 +}
 +
 +/*****************************************************************************
 + * sector erase start
 + *****************************************************************************/
 +static void FlashSectorErase (
 +	volatile FLASH_WORD_SIZE *b,
 +	volatile FLASH_WORD_SIZE *a)
 +{
 +	b[0x5555] = 0xaa;
 +	b[0x2aaa] = 0x55;
 +	b[0x5555] = 0x80;
 +	b[0x5555] = 0xaa;
 +	b[0x2aaa] = 0x55;
 +	a[0] = 0x30;
 +}
 +
 +/*****************************************************************************
 + * program a word
 + *****************************************************************************/
 +static void FlashProgWord (
 +	volatile FLASH_WORD_SIZE *b,
 +	volatile FLASH_WORD_SIZE *a,
 +	FLASH_WORD_SIZE v)
 +{
 +	b[0x5555] = 0xaa;
 +	b[0x2aaa] = 0x55;
 +	b[0x5555] = 0xa0;
 +	a[0] = v;
 +}
 +
 +/*****************************************************************************
 + * reset bank, back to read mode
 + *****************************************************************************/
 +static void FlashReset (volatile FLASH_WORD_SIZE *b)
 +{
 +	b[0] = 0xf0;
 +}
 +
 +/*****************************************************************************
 + * identify FLASH chip
 + * this code is a stripped version of the FlashGetType() function in EMKstax
 + *****************************************************************************/
 +unsigned long flash_init (void) +{
 +	volatile FLASH_WORD_SIZE * const flash = (volatile FLASH_WORD_SIZE *) CFG_FLASH_BASE;
 +	FLASH_WORD_SIZE	manu, dev;
 +	flash_info_t * const pflinfo = &flash_info[0];
 +	int j;
 +
 +	/* get Id Bytes */
 +	FlashProductIdMode (flash, 1);
 +	manu = flash[0];
 +	dev  = flash[1];
 +	FlashProductIdMode (flash, 0);
 +
 +	pflinfo->size = 0;
 +	pflinfo->sector_count = 0;
 +	pflinfo->flash_id = 0xffffffff;
 +	pflinfo->portwidth = FLASH_CFI_16BIT;
 +	pflinfo->chipwidth = FLASH_CFI_BY16;
 +
 +	switch (manu&0xff)
 +	{
 +	case 0x01:	/* AMD */
 +		pflinfo->flash_id = FLASH_MAN_AMD;
 +		switch (dev&0xff)
 +		{
 +		case 0x49:
 +			pflinfo->size = 0x00200000;
 +			pflinfo->sector_count = 35;
 +			pflinfo->flash_id |= FLASH_AM160B;
 +			pflinfo->start[0] = CFG_FLASH_BASE;
 +			pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
 +			pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
 +			pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
 +			for (j = 4; j < 35; j++)
 +			{
 +				pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-3);
 +			}
 +			break;
 +
 +		case 0xf9:
 +			pflinfo->size = 0x00400000;
 +			pflinfo->sector_count = 71;
 +			pflinfo->flash_id |= FLASH_AM320B;
 +			pflinfo->start[0] = CFG_FLASH_BASE;
 +			pflinfo->start[1] = CFG_FLASH_BASE + 0x4000;
 +			pflinfo->start[2] = CFG_FLASH_BASE + 0x6000;
 +			pflinfo->start[3] = CFG_FLASH_BASE + 0x8000;
 +			for (j = 0; j < 8; j++)
 +			{
 +				pflinfo->start[j] = CFG_FLASH_BASE + 0x00002000 * (j);
 +			}
 +			for (j = 8; j < 71; j++)
 +			{
 +				pflinfo->start[j] = CFG_FLASH_BASE + 0x00010000 * (j-7);
 +			}
 +			break;
 +
 +		default:
 +			printf ("unknown AMD dev=%x ", dev);
 +			pflinfo->flash_id |= FLASH_UNKNOWN;
 +		}
 +		break;
 +
 +	default:
 +		printf ("unknown manu=%x ", manu);
 +	}
 +	return pflinfo->size;
 +} + +/*****************************************************************************
 + * print info about a FLASH
 + *****************************************************************************/
 +void flash_print_info (flash_info_t *info) +{
 +	static const char	unk[] = "Unknown";
 +	unsigned int		i;
 +	const char			*mfct=unk,
 +						*type=unk;
 +
 +	if(info->flash_id != FLASH_UNKNOWN)
 +	{
 +		switch (info->flash_id & FLASH_VENDMASK)
 +		{
 +		case FLASH_MAN_AMD:
 +			mfct = "AMD";
 +			break;
 +		}
 +
 +		switch (info->flash_id & FLASH_TYPEMASK)
 +		{
 +		case FLASH_AM160B:
 +			type = "AM29LV160B (16 Mbit, bottom boot sect)";
 +			break;
 +		case FLASH_AM320B:
 +			type = "AM29LV320B (32 Mbit, bottom boot sect)";
 +			break;
 +		}
 +	}
 +
 +	printf (
 +		"\n  Brand: %s Type: %s\n"
 +		"  Size: %lu KB in %d Sectors\n",
 +		mfct,
 +		type,
 +		info->size >> 10,
 +		info->sector_count
 +		);
 +
 +	printf ("  Sector Start Addresses:");
 +
 +	for (i = 0; i < info->sector_count; i++)
 +	{
 +		unsigned long	size;
 +		unsigned int	erased;
 +		unsigned long	*flash = (unsigned long *) info->start[i];
 +
 +		/*
 +		 * Check if whole sector is erased
 +		 */
 +		size =
 +			(i != (info->sector_count - 1)) ?
 +			(info->start[i + 1] - info->start[i]) >> 2 :
 +		(info->start[0] + info->size - info->start[i]) >> 2;
 +
 +		for (
 +			flash = (unsigned long *) info->start[i], erased = 1;
 +				(flash != (unsigned long *) info->start[i] + size) && erased;
 +					flash++
 +			)
 +			erased = *flash == ~0x0UL;
 +
 +		printf (
 +			"%s %08lX %s %s",
 +			(i % 5) ? "" : "\n   ",
 +			info->start[i],
 +			erased ? "E" : " ",
 +			info->protect[i] ? "RO" : "  "
 +			);
 +	}
 +
 +	puts ("\n");
 +	return;
 +} + +/*****************************************************************************
 + * erase one or more sectors
 + *****************************************************************************/
 +int	flash_erase (flash_info_t *info, int s_first, int s_last) +{
 +	volatile FLASH_WORD_SIZE	*addr = (FLASH_WORD_SIZE *)(info->start[0]);
 +	int							flag,
 +								prot,
 +								sect,
 +								l_sect;
 +	ulong						start,
 +								now,
 +								last;
 +
 +	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_UNKNOWN) ||
 +		(info->flash_id > (FLASH_MAN_STM | FLASH_AMD_COMP)))
 +	{
 +		printf ("Can't erase unknown flash type - aborted\n");
 +		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");
 +	}
 +
 +	l_sect = -1;
 +
 +	/* Disable interrupts which might cause a timeout here */
 +	flag = disable_interrupts();
 +
 +	/* Start erase on unprotected sectors */
 +	for (sect = s_first; sect<=s_last; sect++)
 +	{
 +		if (info->protect[sect] == 0)
 +		{ /* not protected */
 +			FlashSectorErase ((FLASH_WORD_SIZE *)info->start[0], (FLASH_WORD_SIZE *)info->start[sect]);
 +			l_sect = sect;
 +		}
 +	}
 +
 +	/* re-enable interrupts if necessary */
 +	if (flag)
 +		enable_interrupts();
 +
 +	/* wait at least 80us - let's wait 1 ms */
 +	udelay (1000);
 +
 +	/*
 +	* We wait for the last triggered sector
 +	*/
 +	if (l_sect < 0)
 +		goto DONE;
 +
 +	start = get_timer (0);
 +	last  = start;
 +	addr = (FLASH_WORD_SIZE *)info->start[l_sect];
 +	while ((addr[0] & 0x0080) != 0x0080)
 +	{
 +		if ((now = get_timer (start)) > CFG_FLASH_ERASE_TOUT)
 +		{
 +			printf ("Timeout\n");
 +			return 1;
 +		}
 +		/* show that we're waiting */
 +		if ((now - last) > 1000)
 +		{  /* every second */
 +			serial_putc ('.');
 +			last = now;
 +		}
 +	}
 +
 +	DONE:
 +	/* reset to read mode */
 +	FlashReset ((FLASH_WORD_SIZE *)info->start[0]);
 +
 +	printf (" done\n");
 +	return 0;
 +} + +/*****************************************************************************
 + * 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) +{
 +	ulong		cp,
 +				wp,
 +				data;
 +	int			i,
 +				l,
 +				rc;
 +
 +	wp = (addr & ~(FLASH_WORD_WIDTH-1));   /* get lower word aligned address */
 +
 +	/*
 +	 * handle unaligned start bytes, if there are...
 +	 */
 +	if ((l = addr - wp) != 0)
 +	{
 +		data = 0;
 +		
 +		/* get the current before the new data into our data word */
 +		for (i=0, cp=wp; i<l; ++i, ++cp)
 +		{
 +			data = (data << 8) | (*(uchar *)cp);
 +		}
 +		
 +		/* now merge the to be programmed values */
 +		for (; i<4 && cnt>0; ++i, ++cp, --cnt)
 +		{
 +			data = (data << 8) | *src++;
 +		}
 +
 +		/* get the current after the new data into our data word */
 +		for (; cnt==0 && i<FLASH_WORD_WIDTH; ++i, ++cp)
 +		{
 +			data = (data << 8) | (*(uchar *)cp);
 +		}
 +
 +		/* now write the combined word */
 +		if ((rc = write_word (info, wp, data)) != 0)
 +		{
 +			return (rc);
 +		}
 +		wp += FLASH_WORD_WIDTH;
 +	}
 +
 +	/*
 +	 * handle word aligned part
 +	 */
 +	while (cnt >= FLASH_WORD_WIDTH)
 +	{
 +		data = 0;
 +		for (i=0; i<FLASH_WORD_WIDTH; ++i)
 +		{
 +			data = (data << 8) | *src++;
 +		}
 +		if ((rc = write_word (info, wp, data)) != 0)
 +		{
 +			return (rc);
 +		}
 +		wp  += FLASH_WORD_WIDTH;
 +		cnt -= FLASH_WORD_WIDTH;
 +	}
 +
 +	if (cnt == 0)
 +	{
 +		return (0);
 +	}
 +
 +	/*
 +	 * handle unaligned tail bytes, if there are...
 +	 */
 +	data = 0;
 +
 +	/* now merge the to be programmed values */
 +	for (i=0, cp=wp; i<FLASH_WORD_WIDTH && cnt>0; ++i, ++cp)
 +	{
 +		data = (data << 8) | *src++;
 +		--cnt;
 +	}
 +
 +	/* get the current after the new data into our data word */
 +	for (; i<FLASH_WORD_WIDTH; ++i, ++cp)
 +	{
 +		data = (data << 8) | (*(uchar *)cp);
 +	}
 +
 +	/* now write the combined word */
 +	return (write_word (info, wp, data));
 +} + +/*****************************************************************************
 + * 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) +{
 +	volatile FLASH_WORD_SIZE	*addr2 = (FLASH_WORD_SIZE *)info->start[0];
 +	volatile FLASH_WORD_SIZE	*dest2 = (FLASH_WORD_SIZE *)dest;
 +	FLASH_WORD_SIZE				data2 = data;
 +	ulong						start;
 +	int							flag;
 +
 +	/* Check if Flash is (sufficiently) erased */
 +	if ((*dest2 & data2) != data2)
 +	{
 +		return (2);
 +	}
 +	
 +	/* Disable interrupts which might cause a timeout here */
 +	flag = disable_interrupts ();
 +
 +	FlashProgWord (addr2, dest2, data2);
 +
 +	/* re-enable interrupts if necessary */
 +	if (flag)
 +		enable_interrupts ();
 +
 +	/* data polling for D7 */
 +	start = get_timer (0);
 +	while ((*dest2 & 0x0080) != (data2 & 0x0080))
 +	{
 +		if (get_timer (start) > CFG_FLASH_WRITE_TOUT)
 +		{
 +			return (1);
 +		}
 +	}
 +
 +	return (0);
 +} + +/*----------------------------------------------------------------------- + */ +
 |