X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=board%2Fpm520%2Fflash.c;h=89c9f02644c96f5111a9d1dc2baea14a57967b24;hb=1d07c1013c717bd79bb2bd7a94861fbeb2067176;hp=572cc9bbeb0b1acb1f3c8e1bad6f34e93a880b33;hpb=49822e23a09e2f529e6774ad61f23e43ab208cbc;p=u-boot diff --git a/board/pm520/flash.c b/board/pm520/flash.c index 572cc9bbeb..89c9f02644 100644 --- a/board/pm520/flash.c +++ b/board/pm520/flash.c @@ -5,66 +5,50 @@ * (C) Copyright 2001-2004 * 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 + * SPDX-License-Identifier: GPL-2.0+ */ #include #include -flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ +flash_info_t flash_info[CONFIG_SYS_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) (x) +#define FLASH_PORT_WIDTH ushort +#define FLASH_PORT_WIDTHV vu_short +#define SWAP(x) (x) #else -#define FLASH_PORT_WIDTH ulong -#define FLASH_PORT_WIDTHV vu_long -#define SWAP(x) (x) +#define FLASH_PORT_WIDTH ulong +#define FLASH_PORT_WIDTHV vu_long +#define SWAP(x) (x) #endif /* Intel-compatible flash ID */ -#define INTEL_COMPAT 0x00890089 -#define INTEL_ALT 0x00B000B0 +#define INTEL_COMPAT 0x00890089 +#define INTEL_ALT 0x00B000B0 /* Intel-compatible flash commands */ -#define INTEL_PROGRAM 0x00100010 -#define INTEL_ERASE 0x00200020 -#define INTEL_CLEAR 0x00500050 -#define INTEL_LOCKBIT 0x00600060 -#define INTEL_PROTECT 0x00010001 -#define INTEL_STATUS 0x00700070 -#define INTEL_READID 0x00900090 -#define INTEL_CONFIRM 0x00D000D0 -#define INTEL_RESET 0xFFFFFFFF +#define INTEL_PROGRAM 0x00100010 +#define INTEL_ERASE 0x00200020 +#define INTEL_CLEAR 0x00500050 +#define INTEL_LOCKBIT 0x00600060 +#define INTEL_PROTECT 0x00010001 +#define INTEL_STATUS 0x00700070 +#define INTEL_READID 0x00900090 +#define INTEL_CONFIRM 0x00D000D0 +#define INTEL_RESET 0xFFFFFFFF /* Intel-compatible flash status bits */ -#define INTEL_FINISHED 0x00800080 -#define INTEL_OK 0x00800080 +#define INTEL_FINISHED 0x00800080 +#define INTEL_OK 0x00800080 -#define FPW FLASH_PORT_WIDTH -#define FPWV FLASH_PORT_WIDTHV +#define FPW FLASH_PORT_WIDTH +#define FPWV FLASH_PORT_WIDTHV #define mb() __asm__ __volatile__ ("" : : : "memory") @@ -75,6 +59,8 @@ 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); +static void flash_sync_real_protect (flash_info_t * info); +static unsigned char intel_sector_protected (flash_info_t *info, ushort sector); /*----------------------------------------------------------------------- */ @@ -85,11 +71,11 @@ unsigned long flash_init (void) ulong size = 0; extern void flash_preinit(void); extern void flash_afterinit(ulong, ulong); - ulong flashbase = CFG_FLASH_BASE; + ulong flashbase = CONFIG_SYS_FLASH_BASE; flash_preinit(); - for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { + for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { switch (i) { case 0: memset(&flash_info[i], 0, sizeof(flash_info_t)); @@ -101,23 +87,26 @@ unsigned long flash_init (void) break; } size += flash_info[i].size; + + /* get the h/w and s/w protection status in sync */ + flash_sync_real_protect(&flash_info[i]); } /* Protect monitor and environment sectors */ -#if CFG_MONITOR_BASE >= CFG_FLASH_BASE +#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE #ifndef CONFIG_BOOT_ROM flash_protect ( FLAG_PROTECT_SET, - CFG_MONITOR_BASE, - CFG_MONITOR_BASE + monitor_flash_len - 1, + CONFIG_SYS_MONITOR_BASE, + CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0] ); #endif #endif -#ifdef CFG_ENV_IS_IN_FLASH +#ifdef CONFIG_ENV_IS_IN_FLASH flash_protect ( FLAG_PROTECT_SET, - CFG_ENV_ADDR, - CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0] ); + CONFIG_ENV_ADDR, + CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0] ); #endif flash_afterinit(flash_info[0].start[0], flash_info[0].size); @@ -138,7 +127,6 @@ static void flash_get_offsets (ulong base, flash_info_t *info) 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; } } } @@ -164,6 +152,10 @@ void flash_print_info (flash_info_t *info) } switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_28F256J3A: + printf ("28F256J3A\n"); + break; + case FLASH_28F128J3A: printf ("28F128J3A\n"); break; @@ -232,25 +224,33 @@ static ulong flash_get_size (FPW *addr, flash_info_t *info) switch (value) { + case (FPW) INTEL_ID_28F256J3A: + info->flash_id += FLASH_28F256J3A; + /* In U-Boot we support only 32 MB (no bank-switching) */ + info->sector_count = 256 / 2; + info->size = 0x04000000 / 2; + info->start[0] = CONFIG_SYS_FLASH_BASE + 0x02000000; + break; /* => 32 MB */ + case (FPW) INTEL_ID_28F128J3A: info->flash_id += FLASH_28F128J3A; info->sector_count = 128; info->size = 0x02000000; - info->start[0] = CFG_FLASH_BASE; + info->start[0] = CONFIG_SYS_FLASH_BASE + 0x02000000; break; /* => 32 MB */ case (FPW) INTEL_ID_28F640J3A: info->flash_id += FLASH_28F640J3A; info->sector_count = 64; info->size = 0x01000000; - info->start[0] = CFG_FLASH_BASE + 0x01000000; + info->start[0] = CONFIG_SYS_FLASH_BASE + 0x03000000; break; /* => 16 MB */ case (FPW) INTEL_ID_28F320J3A: info->flash_id += FLASH_28F320J3A; info->sector_count = 32; info->size = 0x800000; - info->start[0] = CFG_FLASH_BASE + 0x01800000; + info->start[0] = CONFIG_SYS_FLASH_BASE + 0x03800000; break; /* => 8 MB */ default: @@ -258,10 +258,10 @@ static ulong flash_get_size (FPW *addr, flash_info_t *info) break; } - if (info->sector_count > CFG_MAX_FLASH_SECT) { + if (info->sector_count > CONFIG_SYS_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; + info->sector_count, CONFIG_SYS_MAX_FLASH_SECT); + info->sector_count = CONFIG_SYS_MAX_FLASH_SECT; } addr[0] = (FPW) 0x00FF00FF; /* restore read mode */ @@ -270,13 +270,91 @@ static ulong flash_get_size (FPW *addr, flash_info_t *info) } +/* + * This function gets the u-boot flash sector protection status + * (flash_info_t.protect[]) in sync with the sector protection + * status stored in hardware. + */ +static void flash_sync_real_protect (flash_info_t * info) +{ + int i; + + switch (info->flash_id & FLASH_TYPEMASK) { + + case FLASH_28F256J3A: + case FLASH_28F128J3A: + case FLASH_28F640J3A: + case FLASH_28F320J3A: + for (i = 0; i < info->sector_count; ++i) { + info->protect[i] = intel_sector_protected(info, i); + } + break; + default: + /* no h/w protect support */ + break; + } +} + + +/* + * checks if "sector" in bank "info" is protected. Should work on intel + * strata flash chips 28FxxxJ3x in 8-bit mode. + * Returns 1 if sector is protected (or timed-out while trying to read + * protection status), 0 if it is not. + */ +static unsigned char intel_sector_protected (flash_info_t *info, ushort sector) +{ + FPWV *addr; + FPWV *lock_conf_addr; + ulong start; + unsigned char ret; + + /* + * first, wait for the WSM to be finished. The rationale for + * waiting for the WSM to become idle for at most + * CONFIG_SYS_FLASH_ERASE_TOUT is as follows. The WSM can be busy + * because of: (1) erase, (2) program or (3) lock bit + * configuration. So we just wait for the longest timeout of + * the (1)-(3), i.e. the erase timeout. + */ + + /* wait at least 35ns (W12) before issuing Read Status Register */ + udelay(1); + addr = (FPWV *) info->start[sector]; + *addr = (FPW) INTEL_STATUS; + + start = get_timer (0); + while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) { + if (get_timer (start) > CONFIG_SYS_FLASH_ERASE_TOUT) { + *addr = (FPW) INTEL_RESET; /* restore read mode */ + printf("WSM busy too long, can't get prot status\n"); + return 1; + } + } + + /* issue the Read Identifier Codes command */ + *addr = (FPW) INTEL_READID; + + /* wait at least 35ns (W12) before reading */ + udelay(1); + + /* Intel example code uses offset of 2 for 16 bit flash */ + lock_conf_addr = (FPWV *) info->start[sector] + 2; + ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0; + + /* put flash back in read mode */ + *addr = (FPW) INTEL_RESET; + + return ret; +} + /*----------------------------------------------------------------------- */ int flash_erase (flash_info_t *info, int s_first, int s_last) { int flag, prot, sect; - ulong type, start, last; + ulong type, start; int rcode = 0; if ((s_first < 0) || (s_first > s_last)) { @@ -310,7 +388,6 @@ int flash_erase (flash_info_t *info, int s_first, int s_last) } start = get_timer (0); - last = start; /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts (); @@ -331,7 +408,7 @@ int flash_erase (flash_info_t *info, int s_first, int s_last) *addr = (FPW) 0x00D000D0; /* erase confirm */ while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) { - if (get_timer(start) > CFG_FLASH_ERASE_TOUT) { + if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) { printf ("Timeout\n"); *addr = (FPW) 0x00B000B0; /* suspend erase */ *addr = (FPW) 0x00FF00FF; /* reset to read mode */ @@ -346,6 +423,10 @@ int flash_erase (flash_info_t *info, int s_first, int s_last) printf (" done\n"); } } + + if (flag) + enable_interrupts(); + return rcode; } @@ -449,6 +530,7 @@ static int write_data (flash_info_t *info, ulong dest, FPW data) ulong status; ulong start; int flag; + int rcode = 0; /* Check if Flash is (sufficiently) erased */ if ((*addr & data) != data) { @@ -466,15 +548,18 @@ static int write_data (flash_info_t *info, ulong dest, FPW data) /* wait while polling the status register */ while (((status = *addr) & (FPW) 0x00800080) != (FPW) 0x00800080) { - if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { - *addr = (FPW) 0x00FF00FF; /* restore read mode */ - return (1); + if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { + rcode = 1; + break; } } *addr = (FPW) 0x00FF00FF; /* restore read mode */ - return (0); + if (flag) + enable_interrupts(); + + return rcode; } void inline spin_wheel (void) @@ -491,7 +576,7 @@ void inline spin_wheel (void) * 0 - OK * 1 - Error (timeout, voltage problems, etc.) */ -int flash_real_protect(flash_info_t *info, long sector, int prot) +int flash_real_protect (flash_info_t *info, long sector, int prot) { ulong start; int i; @@ -512,7 +597,7 @@ int flash_real_protect(flash_info_t *info, long sector, int prot) start = get_timer(0); while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) { - if (get_timer(start) > CFG_FLASH_UNLOCK_TOUT) { + if (get_timer(start) > CONFIG_SYS_FLASH_UNLOCK_TOUT) { printf("Flash lock bit operation timed out\n"); rc = 1; break; @@ -531,6 +616,11 @@ int flash_real_protect(flash_info_t *info, long sector, int prot) /* * Clear lock bit command clears all sectors lock bits, so * we have to restore lock bits of protected sectors. + * WARNING: code below re-locks sectors only for one bank (info). + * This causes problems on boards where several banks share + * the same chip, as sectors in othere banks will be unlocked + * but not re-locked. It works fine on pm520 though, as there + * is only one chip and one bank. */ if (!prot) { @@ -544,7 +634,7 @@ int flash_real_protect(flash_info_t *info, long sector, int prot) *addr = INTEL_PROTECT; /* set */ while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) { - if (get_timer(start) > CFG_FLASH_UNLOCK_TOUT) + if (get_timer(start) > CONFIG_SYS_FLASH_UNLOCK_TOUT) { printf("Flash lock bit operation timed out\n"); rc = 1; @@ -553,6 +643,11 @@ int flash_real_protect(flash_info_t *info, long sector, int prot) } } } + /* + * get the s/w sector protection status in sync with the h/w, + * in case something went wrong during the re-locking. + */ + flash_sync_real_protect(info); /* resets flash to read mode */ } if (flag)