diff options
| author | wdenk <wdenk> | 2003-03-06 00:58:30 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2003-03-06 00:58:30 +0000 | 
| commit | db2f721ffcf9693086a7e5c6c7015f2019e7f52e (patch) | |
| tree | 1d755e28c035c1247f30b570ed239a097a7d13c8 /board/lubbock/flash.c | |
| parent | 43d9616cffb4a130e1620e3e33fc9bc1bcabe399 (diff) | |
| download | olio-uboot-2014.01-db2f721ffcf9693086a7e5c6c7015f2019e7f52e.tar.xz olio-uboot-2014.01-db2f721ffcf9693086a7e5c6c7015f2019e7f52e.zip | |
* Patch by Rune Torgersen, 13 Feb 2003:LABEL_2003_03_06_0200
  Add support for Motorola MPC8266ADS board
* Patch by Kyle Harris, 19 Feb 2003:
  patches for the Intel lubbock board:
  memsetup.S - general cleanup (based on Robert's csb226 code)
  flash.c - overhaul, actually works now
  lubbock.c - fix init funcs to return proper value
* Patch by Kenneth Johansson, 26 Feb 2003:
  - Fixed off by one in RFTA calculation.
  - No need to abort when LDF is lower than we can program it's only
    minimum timing so clamp it to what we can do.
  - Takes function pointer to function for reading the spd_nvram. Usefull
    for faking data or hardcode a module without the nvram.
  - fix other user for above change
  - fix some comments.
* Patches by Brian Waite, 26 Feb 2003:
  - fix port for evb64260 board
  - fix PCI for evb64260 board
  - fix PCI scan
* Patch by Reinhard Meyer, 1 Mar 2003:
  Add support for EMK TOP860 Module
* Patch by Yuli Barcohen, 02 Mar 2003:
  Add SPD EEPROM support for MPC8260ADS board
Diffstat (limited to 'board/lubbock/flash.c')
| -rw-r--r-- | board/lubbock/flash.c | 467 | 
1 files changed, 268 insertions, 199 deletions
| diff --git a/board/lubbock/flash.c b/board/lubbock/flash.c index 84c09a853..a93875083 100644 --- a/board/lubbock/flash.c +++ b/board/lubbock/flash.c @@ -1,10 +1,9 @@  /* - * (C) Copyright 2002 + * (C) Copyright 2001   * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net   * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de.   *   * See file CREDITS for list of people who contributed to this   * project. @@ -26,46 +25,62 @@   */  #include <common.h> +#include <linux/byteorder/swab.h> -#define FLASH_BANK_SIZE 0x2000000 -#define MAIN_SECT_SIZE  0x40000         /* 2x16 = 256k per sector */ -flash_info_t    flash_info[CFG_MAX_FLASH_BANKS]; +flash_info_t	flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips	*/ +/* Board support for 1 or 2 flash devices */ +#define FLASH_PORT_WIDTH32 +#undef FLASH_PORT_WIDTH16 + +#ifdef FLASH_PORT_WIDTH16 +#define FLASH_PORT_WIDTH		ushort +#define FLASH_PORT_WIDTHV		vu_short +#define SWAP(x)               __swab16(x) +#else +#define FLASH_PORT_WIDTH		ulong +#define FLASH_PORT_WIDTHV		vu_long +#define SWAP(x)               __swab32(x) +#endif + +#define FPW	   FLASH_PORT_WIDTH +#define FPWV   FLASH_PORT_WIDTHV + +#define mb() __asm__ __volatile__ ("" : : : "memory")  /*----------------------------------------------------------------------- + * Functions   */ +static ulong flash_get_size (FPW *addr, flash_info_t *info); +static int   write_data (flash_info_t *info, ulong dest, FPW data); +static void  flash_get_offsets (ulong base, flash_info_t *info); +void inline  spin_wheel(void); -ulong flash_init(void) +/*----------------------------------------------------------------------- + */ + +unsigned long flash_init (void)  { -    int i, j; +   int i;      ulong size = 0;      for (i = 0; i < CFG_MAX_FLASH_BANKS; i++)      { -	ulong flashbase = 0; -	flash_info[i].flash_id = -	  (INTEL_MANUFACT & FLASH_VENDMASK) | -	  (INTEL_ID_28F128J3 & FLASH_TYPEMASK); -	flash_info[i].size = FLASH_BANK_SIZE; -	flash_info[i].sector_count = CFG_MAX_FLASH_SECT; -	memset(flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);          switch (i)          {             case 0: -	        flashbase = PHYS_FLASH_1; +            flash_get_size((FPW *)PHYS_FLASH_1, &flash_info[i]); +	         flash_get_offsets(PHYS_FLASH_1, &flash_info[i]);                  break;             case 1: -	        flashbase = PHYS_FLASH_2; +            flash_get_size((FPW *)PHYS_FLASH_2, &flash_info[i]); +	         flash_get_offsets(PHYS_FLASH_2, &flash_info[i]);                  break;             default:  	        panic("configured to many flash banks!\n");                  break;          } -	for (j = 0; j < flash_info[i].sector_count; j++) -	{ -	    flash_info[i].start[j] = flashbase + j*MAIN_SECT_SIZE; -	}  	size += flash_info[i].size;      } @@ -86,71 +101,140 @@ ulong flash_init(void)  /*-----------------------------------------------------------------------   */ +static void flash_get_offsets (ulong base, flash_info_t *info) +{ +	int i; + +	if (info->flash_id == FLASH_UNKNOWN) { +		return; +	} + +	if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { +		for (i = 0; i < info->sector_count; i++) { +			info->start[i] = base + (i * PHYS_FLASH_SECT_SIZE); +			info->protect[i] = 0; +		} +	} +} + +/*----------------------------------------------------------------------- + */  void flash_print_info  (flash_info_t *info)  { -    int i, j; +	int i; -    for (j=0; j<CFG_MAX_FLASH_BANKS; j++) -    { -        switch (info->flash_id & FLASH_VENDMASK) -        { -        case (INTEL_MANUFACT & FLASH_VENDMASK): -	        printf("Intel: "); -	        break; -        default: -	        printf("Unknown Vendor "); -	        break; +	if (info->flash_id == FLASH_UNKNOWN) { +		printf ("missing or unknown FLASH type\n"); +		return;          } -        switch (info->flash_id & FLASH_TYPEMASK) -        { -        case (INTEL_ID_28F128J3 & FLASH_TYPEMASK): -	        printf("28F128J3 (128Mbit)\n"); -	        break; -        default: -	        printf("Unknown Chip Type\n"); -	        goto Done; -	        break; +	switch (info->flash_id & FLASH_VENDMASK) { +		case FLASH_MAN_INTEL:	printf ("INTEL ");		break; +		default:		printf ("Unknown Vendor ");	break; +	} + +	switch (info->flash_id & FLASH_TYPEMASK) { +   case FLASH_28F128J3A: +				printf ("28F128J3A\n"); break; +	default:		printf ("Unknown Chip Type\n"); break;          } -        printf("  Size: %ld MB in %d Sectors\n", +	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++) -        { +	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 (" %08lX%s", +			info->start[i], +			info->protect[i] ? " (RO)" : "     " +		);          }          printf ("\n"); -        info++; +	return; +} + +/* + * The following code cannot be run from FLASH! + */ +static ulong flash_get_size (FPW *addr, flash_info_t *info) +{ +	volatile FPW value; + +	/* Write auto select command: read Manufacturer ID */ +	addr[0x5555] = (FPW)0x00AA00AA; +	addr[0x2AAA] = (FPW)0x00550055; +	addr[0x5555] = (FPW)0x00900090; + +   mb(); +	value = addr[0]; + +   switch (value) { + +   case (FPW)INTEL_MANUFACT: +      info->flash_id = FLASH_MAN_INTEL; +      break; + +	default: +		info->flash_id = FLASH_UNKNOWN; +		info->sector_count = 0; +		info->size = 0; +		addr[0] = (FPW)0x00FF00FF;      /* restore read mode */ +		return (0);			/* no or unknown flash	*/ +	} + +   mb(); +	value = addr[1];			/* device ID		*/ + +   switch (value) { + +   case (FPW)INTEL_ID_28F128J3A: +      info->flash_id += FLASH_28F128J3A; +      info->sector_count = 128; +      info->size = 0x02000000; +      break;            /* => 16 MB     */ + +	default: +		info->flash_id = FLASH_UNKNOWN; +		break; +	} + +	if (info->sector_count > CFG_MAX_FLASH_SECT) { +		printf ("** ERROR: sector count %d > max (%d) **\n", +			info->sector_count, CFG_MAX_FLASH_SECT); +		info->sector_count = CFG_MAX_FLASH_SECT;      } -Done: +	addr[0] = (FPW)0x00FF00FF;      /* restore read mode */ + +	return (info->size);  } +  /*-----------------------------------------------------------------------   */  int	flash_erase (flash_info_t *info, int s_first, int s_last)  {      int flag, prot, sect; -    int rc = ERR_OK; - -    if (info->flash_id == FLASH_UNKNOWN) -	return ERR_UNKNOWN_FLASH_TYPE; +	ulong type, start, now, last; +	int rcode = 0;      if ((s_first < 0) || (s_first > s_last)) { -	return ERR_INVAL; +		if (info->flash_id == FLASH_UNKNOWN) { +			printf ("- missing\n"); +		} else { +			printf ("- no sectors to erase\n"); +		} +		return 1;      } -    if ((info->flash_id & FLASH_VENDMASK) != -	(INTEL_MANUFACT & FLASH_VENDMASK)) { -	return ERR_UNKNOWN_FLASH_VENDOR; +	type = (info->flash_id & FLASH_VENDMASK); +	if ((type != FLASH_MAN_INTEL)) { +		printf ("Can't erase unknown flash type %08lx - aborted\n", +			info->flash_id); +		return 1;      }      prot = 0; @@ -159,153 +243,79 @@ int	flash_erase (flash_info_t *info, int s_first, int s_last)  	    prot++;  	}      } -    if (prot) -	return ERR_PROTECTED; -    /* -     * Disable interrupts which might cause a timeout -     * here. Remember that our exception vectors are -     * at address 0 in the flash, and we don't want a -     * (ticker) exception to happen while the flash -     * chip is in programming mode. -     */ +	if (prot) { +		printf ("- Warning: %d protected sectors will not be erased!\n", +			prot); +	} else { +		printf ("\n"); +	} + +	start = get_timer (0); +	last  = start; + +   /* Disable interrupts which might cause a timeout here */      flag = disable_interrupts();      /* Start erase on unprotected sectors */ -    for (sect = s_first; sect<=s_last && !ctrlc(); sect++) { +	for (sect = s_first; sect<=s_last; sect++) { +		if (info->protect[sect] == 0) {	/* not protected */ +			FPWV *addr = (FPWV *)(info->start[sect]); +			FPW status;  	printf("Erasing sector %2d ... ", sect);  	/* arm simple, non interrupt dependent timer */  	reset_timer_masked(); -	if (info->protect[sect] == 0) {	/* not protected */ -	    vu_short *addr = (vu_short *)(info->start[sect]); +			*addr = (FPW)0x00500050;	/* clear status register */ +			*addr = (FPW)0x00200020;	/* erase setup */ +			*addr = (FPW)0x00D000D0;	/* erase confirm */ -	    *addr = 0x20;	/* erase setup */ -	    *addr = 0xD0;	/* erase confirm */ - -	    while ((*addr & 0x80) != 0x80) { +			while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) {  		if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) { -		    *addr = 0xB0; /* suspend erase */ -		    *addr = 0xFF;	/* reset to read mode */ -		    rc = ERR_TIMOUT; -		    goto outahere; -		} -	    } - -	    /* clear status register command */ -	    *addr = 0x50; -	    /* reset to read mode */ -	    *addr = 0xFF; +					printf ("Timeout\n"); +					*addr = (FPW)0x00B000B0; /* suspend erase	  */ +					*addr = (FPW)0x00FF00FF; /* reset to read mode */ +					rcode = 1; +					break;  	} -	printf("ok.\n");      } -    if (ctrlc()) -      printf("User Interrupt!\n"); -outahere: +			*addr = 0x00500050; /* clear status register cmd.   */ +			*addr = 0x00FF00FF; /* resest to read mode          */ -    /* allow flash to settle - wait 10 ms */ -    udelay_masked(10000); - -    if (flag) -      enable_interrupts(); - -    return rc; -} - -/*----------------------------------------------------------------------- - * Copy memory to flash - */ - -static int write_word (flash_info_t *info, ulong dest, ushort data) -{ -    vu_short *addr = (vu_short *)dest, val; -    int rc = ERR_OK; -    int flag; - -    /* Check if Flash is (sufficiently) erased -     */ -    if ((*addr & data) != data) -        return ERR_NOT_ERASED; - -    /* -     * Disable interrupts which might cause a timeout -     * here. Remember that our exception vectors are -     * at address 0 in the flash, and we don't want a -     * (ticker) exception to happen while the flash -     * chip is in programming mode. -     */ -    flag = disable_interrupts(); - -    /* clear status register command */ -    *addr = 0x50; - -    /* program set-up command */ -    *addr = 0x40; - -    /* latch address/data */ -    *addr = data; - -    /* arm simple, non interrupt dependent timer */ -    reset_timer_masked(); - -    /* wait while polling the status register */ -    while(((val = *addr) & 0x80) != 0x80) -    { -	if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) { -	    rc = ERR_TIMOUT; -	    /* suspend program command */ -	    *addr = 0xB0; -	    goto outahere; -	} -    } - -    if(val & 0x1A) {	/* check for error */ -        printf("\nFlash write error %02x at address %08lx\n", -    	   (int)val, (unsigned long)dest); -        if(val & (1<<3)) { -	    printf("Voltage range error.\n"); -	    rc = ERR_PROG_ERROR; -	    goto outahere; +			printf (" done\n");          } -        if(val & (1<<1)) { -	    printf("Device protect error.\n"); -	    rc = ERR_PROTECTED; -	    goto outahere;          } -        if(val & (1<<4)) { -	    printf("Programming error.\n"); -	    rc = ERR_PROG_ERROR; -	    goto outahere; -        } -        rc = ERR_PROG_ERROR; -        goto outahere; -    } - -outahere: -    /* read array command */ -    *addr = 0xFF; - -    if (flag) -      enable_interrupts(); - -    return rc; +	return rcode;  }  /*----------------------------------------------------------------------- - * Copy memory to flash. + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + * 4 - Flash not identified   */  int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)  {      ulong cp, wp; -    ushort data; -    int l; -    int i, rc; +	FPW data; +	int count, i, l, rc, port_width; -    wp = (addr & ~1);	/* get lower word aligned address */ +	if (info->flash_id == FLASH_UNKNOWN) { +		return 4; +	} +/* get lower word aligned address */ +#ifdef FLASH_PORT_WIDTH16 +	wp = (addr & ~1); +	port_width = 2; +#else +	wp = (addr & ~3); +	port_width = 4; +#endif      /*       * handle unaligned start bytes @@ -313,51 +323,110 @@ int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)      if ((l = addr - wp) != 0) {  	data = 0;  	for (i=0, cp=wp; i<l; ++i, ++cp) { -	    data = (data >> 8) | (*(uchar *)cp << 8); +			data = (data << 8) | (*(uchar *)cp);  	} -	for (; i<2 && cnt>0; ++i) { -	    data = (data >> 8) | (*src++ << 8); +		for (; i<port_width && cnt>0; ++i) { +			data = (data << 8) | *src++;  	    --cnt;  	    ++cp;  	} -	for (; cnt==0 && i<2; ++i, ++cp) { -	    data = (data >> 8) | (*(uchar *)cp << 8); +		for (; cnt==0 && i<port_width; ++i, ++cp) { +			data = (data << 8) | (*(uchar *)cp);  	} -	if ((rc = write_word(info, wp, data)) != 0) { +		if ((rc = write_data(info, wp, SWAP(data))) != 0) {  	    return (rc);  	} -	wp += 2; +		wp += port_width;      }      /*       * handle word aligned part       */ -    while (cnt >= 2) { -	data = *((vu_short*)src); -	if ((rc = write_word(info, wp, data)) != 0) { +	count = 0; +	while (cnt >= port_width) { +		data = 0; +		for (i=0; i<port_width; ++i) { +			data = (data << 8) | *src++; +		} +		if ((rc = write_data(info, wp, SWAP(data))) != 0) {  	    return (rc);  	} -	src += 2; -	wp  += 2; -	cnt -= 2; +		wp  += port_width; +		cnt -= port_width; +		if (count++ > 0x800) +		{ +         spin_wheel(); +			count = 0; +		}      }      if (cnt == 0) { -	return ERR_OK; +		return (0);      }      /*       * handle unaligned tail bytes       */      data = 0; -    for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) { -	data = (data >> 8) | (*src++ << 8); +	for (i=0, cp=wp; i<port_width && cnt>0; ++i, ++cp) { +		data = (data << 8) | *src++;  	--cnt;      } -    for (; i<2; ++i, ++cp) { -	data = (data >> 8) | (*(uchar *)cp << 8); +	for (; i<port_width; ++i, ++cp) { +		data = (data << 8) | (*(uchar *)cp); +	} + +	return (write_data(info, wp, SWAP(data))); +} + +/*----------------------------------------------------------------------- + * 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, ulong dest, FPW data) +{ +	FPWV *addr = (FPWV *)dest; +	ulong status; +	ulong start; +	int flag; + +	/* Check if Flash is (sufficiently) erased */ +	if ((*addr & data) != data) { +		printf("not erased at %08lx (%x)\n",(ulong)addr,*addr); +		return (2); +	} +	/* Disable interrupts which might cause a timeout here */ +	flag = disable_interrupts(); + +	*addr = (FPW)0x00400040;		/* write setup */ +	*addr = data; + +	/* arm simple, non interrupt dependent timer */ +	reset_timer_masked(); + +	/* wait while polling the status register */ +	while (((status = *addr) & (FPW)0x00800080) != (FPW)0x00800080) { +		if (get_timer_masked() > CFG_FLASH_WRITE_TOUT) { +			*addr = (FPW)0x00FF00FF;	/* restore read mode */ +			return (1); +		}      } -    return write_word(info, wp, data); +	*addr = (FPW)0x00FF00FF;	/* restore read mode */ + +	return (0); +} + +void inline +spin_wheel(void) +{ +   static int r=0,p=0; +   static char w[] = "\\/-"; + +   printf("\010%c", w[p]); +   (++p == 3) ? (p = 0) : 0;  } + |