From 5653fc335a450fa46d89989e1afe5e8bb9a0a52e Mon Sep 17 00:00:00 2001 From: wdenk Date: Sun, 8 Feb 2004 22:55:38 +0000 Subject: [PATCH] * Patch by Yuli Barcohen, 26 Jan 2004: Allow bzip2 compression for small memory footprint boards * Patch by Brad Kemp, 21 Jan 2004: Add support for CFI flash driver for both the Intel and the AMD command sets. * Patch by Travis Sawyer, 20 Jan 2004: Fix pci bridge auto enumeration of sibling p2p bridges. * Patch by Tolunay Orkun, 12 Jan 2004: Add some delays as needed for Intel LXT971A PHY support * Patches by Stephan Linz, 09 Jan 2004: - avoid warning: unused variable `piop' in board/altera/common/sevenseg.c - make DK1C20 board configuration related to ASMI conform to documentation --- CHANGELOG | 18 + README | 6 +- board/altera/common/sevenseg.c | 6 +- common/cmd_bootm.c | 8 +- common/miiphyutil.c | 4 +- cpu/ppc4xx/miiphy.c | 6 + drivers/Makefile | 2 +- drivers/cfi_flash.c | 1018 ++++++++++++++++++++++++++++++++ drivers/pci_auto.c | 20 +- include/configs/DK1C20.h | 4 +- include/flash.h | 7 +- 11 files changed, 1084 insertions(+), 15 deletions(-) create mode 100644 drivers/cfi_flash.c diff --git a/CHANGELOG b/CHANGELOG index 202dd47ee8..2359b48208 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,24 @@ Changes since U-Boot 1.0.1: ====================================================================== +* Patch by Yuli Barcohen, 26 Jan 2004: + Allow bzip2 compression for small memory footprint boards + +* Patch by Brad Kemp, 21 Jan 2004: + Add support for CFI flash driver for both the Intel and the AMD + command sets. + +* Patch by Travis Sawyer, 20 Jan 2004: + Fix pci bridge auto enumeration of sibling p2p bridges. + +* Patch by Tolunay Orkun, 12 Jan 2004: + Add some delays as needed for Intel LXT971A PHY support + +* Patches by Stephan Linz, 09 Jan 2004: + - avoid warning: unused variable `piop' in board/altera/common/sevenseg.c + - make DK1C20 board configuration related to ASMI conform to + documentation + * Patch by Anders Larsen, 09 Jan 2004: ARM memory layout fixes: the abort-stack is now set up in the diff --git a/README b/README index 46171bf11c..ac5b921b4d 100644 --- a/README +++ b/README @@ -1643,7 +1643,11 @@ Configuration Settings: - CFG_FLASH_CFI: Define if the flash driver uses extra elements in the - common flash structure for storing flash geometry + common flash structure for storing flash geometry. + +- CFG_FLASH_CFI_DRIVER + This option also enables the building of the cfi_flash driver + in the drivers directory - CFG_RX_ETH_BUFFER: Defines the number of ethernet receive buffers. On some diff --git a/board/altera/common/sevenseg.c b/board/altera/common/sevenseg.c index fecfbd388e..c53cec16e6 100644 --- a/board/altera/common/sevenseg.c +++ b/board/altera/common/sevenseg.c @@ -44,7 +44,7 @@ static int sevenseg_init_done = 0; static inline void __sevenseg_set_masked (unsigned int mask, int value) { - nios_pio_t *piop = (nios_pio_t*)SEVENSEG_BASE; + nios_pio_t *piop __attribute__((unused)) = (nios_pio_t*)SEVENSEG_BASE; #ifdef SEVENSEG_WRONLY /* emulate read access */ @@ -97,7 +97,7 @@ static inline void __sevenseg_toggle_masked (unsigned int mask) static inline void __sevenseg_set (unsigned int value) { - nios_pio_t *piop = (nios_pio_t*)SEVENSEG_BASE; + nios_pio_t *piop __attribute__((unused)) = (nios_pio_t*)SEVENSEG_BASE; #ifdef SEVENSEG_WRONLY /* emulate read access */ @@ -126,7 +126,7 @@ static inline void __sevenseg_set (unsigned int value) static inline void __sevenseg_init (void) { - nios_pio_t *piop = (nios_pio_t*)SEVENSEG_BASE; + nios_pio_t *piop __attribute__((unused)) = (nios_pio_t*)SEVENSEG_BASE; __sevenseg_set(0); diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 34a74ce2c5..ac9c32e7b8 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -333,8 +333,14 @@ int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: printf (" Uncompressing %s ... ", name); + /* + * If we've got less than 4 MB of malloc() space, + * use slower decompression algorithm which requires + * at most 2300 KB of memory. + */ i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load), - &unc_len, (char *)data, len, 0, 0); + &unc_len, (char *)data, len, + CFG_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf ("BUNZIP2 ERROR %d - must RESET board to recover\n", i); SHOW_BOOT_PROGRESS (-6); diff --git a/common/miiphyutil.c b/common/miiphyutil.c index af8c7c7a31..03964da81f 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -99,7 +99,9 @@ int miiphy_reset (unsigned char addr) #endif return (-1); } - +#ifdef CONFIG_PHY_RESET_DELAY + udelay (CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ +#endif /* * Poll the control register for the reset bit to go to 0 (it is * auto-clearing). This should happen within 0.5 seconds per the diff --git a/cpu/ppc4xx/miiphy.c b/cpu/ppc4xx/miiphy.c index 5ca66815c5..3d343ee881 100644 --- a/cpu/ppc4xx/miiphy.c +++ b/cpu/ppc4xx/miiphy.c @@ -113,6 +113,9 @@ int miiphy_read (unsigned char addr, unsigned char reg, printf ("a2: write: EMAC_STACR=0x%0x\n", sta_reg); /* test-only */ #endif +#ifdef CONFIG_PHY_CMD_DELAY + udelay (CONFIG_PHY_CMD_DELAY); /* Intel LXT971A needs this */ +#endif sta_reg = in32 (EMAC_STACR); i = 0; while ((sta_reg & EMAC_STACR_OC) == 0) { @@ -173,6 +176,9 @@ int miiphy_write (unsigned char addr, unsigned char reg, out32 (EMAC_STACR, sta_reg); +#ifdef CONFIG_PHY_CMD_DELAY + udelay (CONFIG_PHY_CMD_DELAY); /* Intel LXT971A needs this */ +#endif /* wait for completion */ i = 0; sta_reg = in32 (EMAC_STACR); diff --git a/drivers/Makefile b/drivers/Makefile index 2bdabae8ec..2999eb465a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -28,7 +28,7 @@ include $(TOPDIR)/config.mk LIB = libdrivers.a OBJS = 3c589.o 5701rls.o ali512x.o \ - bcm570x.o bcm570x_autoneg.o cfb_console.o \ + bcm570x.o bcm570x_autoneg.o cfb_console.o cfi_flash.o \ cs8900.o ct69000.o dataflash.o dc2114x.o \ e1000.o eepro100.o \ i8042.o i82365.o inca-ip_sw.o \ diff --git a/drivers/cfi_flash.c b/drivers/cfi_flash.c new file mode 100644 index 0000000000..fb769253dd --- /dev/null +++ b/drivers/cfi_flash.c @@ -0,0 +1,1018 @@ +/* + * (C) Copyright 2002 + * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com + * + * Copyright (C) 2003 Arabella Software Ltd. + * Yuli Barcohen + * Modified to work with AMD flashes + * + * 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 + * + * History + * 01/20/2004 - combined variants of original driver. + * + * Tested Architectures + * Port Width Chip Width # of banks Flash Chip Board + * 32 16 1 23F128J3 seranoa/eagle + * + */ + +/* The DEBUG define must be before common to enable debugging */ +#undef DEBUG +#include +#include +#ifdef CFG_FLASH_CFI_DRIVER +/* + * This file implements a Common Flash Interface (CFI) driver for U-Boot. + * The width of the port and the width of the chips are determined at initialization. + * These widths are used to calculate the address for access CFI data structures. + * It has been tested on an Intel Strataflash implementation and AMD 29F016D. + * + * References + * JEDEC Standard JESD68 - Common Flash Interface (CFI) + * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes + * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets + * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet + * + * TODO + * + * Use Primary Extended Query table (PRI) and Alternate Algorithm Query + * Table (ALT) to determine if protection is available + * + * Add support for other command sets Use the PRI and ALT to determine command set + * Verify erase and program timeouts. + */ + +#define FLASH_CMD_CFI 0x98 +#define FLASH_CMD_READ_ID 0x90 +#define FLASH_CMD_RESET 0xff +#define FLASH_CMD_BLOCK_ERASE 0x20 +#define FLASH_CMD_ERASE_CONFIRM 0xD0 +#define FLASH_CMD_WRITE 0x40 +#define FLASH_CMD_PROTECT 0x60 +#define FLASH_CMD_PROTECT_SET 0x01 +#define FLASH_CMD_PROTECT_CLEAR 0xD0 +#define FLASH_CMD_CLEAR_STATUS 0x50 +#define FLASH_CMD_WRITE_TO_BUFFER 0xE8 +#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 + +#define FLASH_STATUS_DONE 0x80 +#define FLASH_STATUS_ESS 0x40 +#define FLASH_STATUS_ECLBS 0x20 +#define FLASH_STATUS_PSLBS 0x10 +#define FLASH_STATUS_VPENS 0x08 +#define FLASH_STATUS_PSS 0x04 +#define FLASH_STATUS_DPS 0x02 +#define FLASH_STATUS_R 0x01 +#define FLASH_STATUS_PROTECT 0x01 + +#define AMD_CMD_RESET 0xF0 +#define AMD_CMD_WRITE 0xA0 +#define AMD_CMD_ERASE_START 0x80 +#define AMD_CMD_ERASE_SECTOR 0x30 + +#define AMD_STATUS_TOGGLE 0x40 +#define AMD_STATUS_ERROR 0x20 + +#define FLASH_OFFSET_CFI 0x55 +#define FLASH_OFFSET_CFI_RESP 0x10 +#define FLASH_OFFSET_PRIMARY_VENDOR 0x13 +#define FLASH_OFFSET_WTOUT 0x1F +#define FLASH_OFFSET_WBTOUT 0x20 +#define FLASH_OFFSET_ETOUT 0x21 +#define FLASH_OFFSET_CETOUT 0x22 +#define FLASH_OFFSET_WMAX_TOUT 0x23 +#define FLASH_OFFSET_WBMAX_TOUT 0x24 +#define FLASH_OFFSET_EMAX_TOUT 0x25 +#define FLASH_OFFSET_CEMAX_TOUT 0x26 +#define FLASH_OFFSET_SIZE 0x27 +#define FLASH_OFFSET_INTERFACE 0x28 +#define FLASH_OFFSET_BUFFER_SIZE 0x2A +#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C +#define FLASH_OFFSET_ERASE_REGIONS 0x2D +#define FLASH_OFFSET_PROTECT 0x02 +#define FLASH_OFFSET_USER_PROTECTION 0x85 +#define FLASH_OFFSET_INTEL_PROTECTION 0x81 + + +#define FLASH_MAN_CFI 0x01000000 + +#define CFI_CMDSET_NONE 0 +#define CFI_CMDSET_INTEL_EXTENDED 1 +#define CFI_CMDSET_AMD_STANDARD 2 +#define CFI_CMDSET_INTEL_STANDARD 3 +#define CFI_CMDSET_AMD_EXTENDED 4 +#define CFI_CMDSET_MITSU_STANDARD 256 +#define CFI_CMDSET_MITSU_EXTENDED 257 +#define CFI_CMDSET_SST 258 + + +typedef union { + unsigned char c; + unsigned short w; + unsigned long l; + unsigned long long ll; +} cfiword_t; + +typedef union { + volatile unsigned char *cp; + volatile unsigned short *wp; + volatile unsigned long *lp; + volatile unsigned long long *llp; +} cfiptr_t; + +#define NUM_ERASE_REGIONS 4 + +static ulong bank_base[CFG_MAX_FLASH_BANKS] = CFG_FLASH_BANKS_LIST; + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +/*----------------------------------------------------------------------- + * Functions + */ + +typedef unsigned long flash_sect_t; + +static void flash_add_byte(flash_info_t *info, cfiword_t * cword, uchar c); +static void flash_make_cmd(flash_info_t * info, uchar cmd, void * cmdbuf); +static void flash_write_cmd(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); +static void flash_unlock_seq(flash_info_t *info); +static int flash_isequal(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); +static int flash_isset(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); +static int flash_toggle(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); +static int flash_detect_cfi(flash_info_t * info); +static ulong flash_get_size (ulong base, int banknum); +static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword); +static int flash_full_status_check(flash_info_t * info, flash_sect_t sector, ulong tout, char * prompt); +#ifdef CFG_FLASH_USE_BUFFER_WRITE +static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len); +#endif + +#ifdef DEBUG +void print_longlong(char * str, unsigned long long data) +{ + int i; + char *cp; + cp = (unsigned char *)&data; + for(i=0;i<8; i++) + sprintf(&str[i*2], "%2.2x", *cp++); +} +#endif + + +/*----------------------------------------------------------------------- + * create an address based on the offset and the port width + */ +inline uchar * flash_make_addr(flash_info_t * info, flash_sect_t sect, uint offset) +{ + return ((uchar *)(info->start[sect] + (offset * info->portwidth))); +} +/*----------------------------------------------------------------------- + * read a character at a port width address + */ +inline uchar flash_read_uchar(flash_info_t * info, uint offset) +{ + uchar *cp; + cp = flash_make_addr(info, 0, offset); + return (cp[info->portwidth - 1]); +} + +/*----------------------------------------------------------------------- + * read a short word by swapping for ppc format. + */ +ushort flash_read_ushort(flash_info_t * info, flash_sect_t sect, uint offset) +{ + uchar * addr; + + addr = flash_make_addr(info, sect, offset); + return ((addr[(2*info->portwidth) - 1] << 8) | addr[info->portwidth - 1]); + +} + +/*----------------------------------------------------------------------- + * read a long word by picking the least significant byte of each maiximum + * port size word. Swap for ppc format. + */ +ulong flash_read_long(flash_info_t * info, flash_sect_t sect, uint offset) +{ + uchar * addr; + + addr = flash_make_addr(info, sect, offset); + return ( (addr[(2*info->portwidth) - 1] << 24 ) | (addr[(info->portwidth) -1] << 16) | + (addr[(4*info->portwidth) - 1] << 8) | addr[(3*info->portwidth) - 1]); + +} + +/*----------------------------------------------------------------------- + */ +unsigned long flash_init (void) +{ + unsigned long size = 0; + int i; + + /* Init: no FLASHes known */ + for (i=0; i= CFG_FLASH_BASE) + flash_protect(FLAG_PROTECT_SET, + CFG_MONITOR_BASE, + CFG_MONITOR_BASE + monitor_flash_len - 1, + &flash_info[0]); +#endif + + return (size); +} + +/*----------------------------------------------------------------------- + */ +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + int rcode = 0; + int prot; + flash_sect_t sect; + + if( info->flash_id != FLASH_MAN_CFI) { + printf ("Can't erase unknown flash type - aborted\n"); + return 1; + } + if ((s_first < 0) || (s_first > s_last)) { + printf ("- no sectors to erase\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"); + } + + + for (sect = s_first; sect<=s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + switch(info->vendor) { + case CFI_CMDSET_INTEL_STANDARD: + case CFI_CMDSET_INTEL_EXTENDED: + flash_write_cmd(info, sect, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sect, 0, FLASH_CMD_BLOCK_ERASE); + flash_write_cmd(info, sect, 0, FLASH_CMD_ERASE_CONFIRM); + break; + case CFI_CMDSET_AMD_STANDARD: + case CFI_CMDSET_AMD_EXTENDED: + flash_unlock_seq(info); + flash_write_cmd(info, sect, 0x555, AMD_CMD_ERASE_START); + flash_unlock_seq(info); + flash_write_cmd(info, sect, 0, AMD_CMD_ERASE_SECTOR); + break; + default: + debug("Unkown flash vendor %d\n", info->vendor); + break; + } + + if(flash_full_status_check(info, sect, info->erase_blk_tout, "erase")) { + rcode = 1; + } else + printf("."); + } + } + printf (" done\n"); + return rcode; +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info (flash_info_t *info) +{ + int i; + + if (info->flash_id != FLASH_MAN_CFI) { + printf ("missing or unknown FLASH type\n"); + return; + } + + printf("CFI conformant FLASH (%d x %d)", + (info->portwidth << 3 ), (info->chipwidth << 3 )); + printf (" Size: %ld MB in %d Sectors\n", + info->size >> 20, info->sector_count); + printf(" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n", + info->erase_blk_tout, info->write_tout, info->buffer_write_tout, info->buffer_size); + + printf (" Sector Start Addresses:"); + for (i=0; isector_count; ++i) { +#ifdef CFG_FLASH_EMPTY_INFO + int k; + int size; + int erased; + volatile unsigned long *flash; + + /* + * Check if whole sector is erased + */ + if (i != (info->sector_count-1)) + size = info->start[i+1] - info->start[i]; + else + size = info->start[0] + info->size - info->start[i]; + erased = 1; + flash = (volatile unsigned long *)info->start[i]; + size = size >> 2; /* divide by 4 for longword access */ + for (k=0; kstart[i], + erased ? " E" : " ", + info->protect[i] ? "RO " : " "); +#else + if ((i % 5) == 0) + printf ("\n "); + printf (" %08lX%s", + info->start[i], + info->protect[i] ? " (RO)" : " "); +#endif + } + printf ("\n"); + return; +} + +/*----------------------------------------------------------------------- + * 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 wp; + ulong cp; + int aln; + cfiword_t cword; + int i, rc; + + /* get lower aligned address */ + wp = (addr & ~(info->portwidth - 1)); + + /* handle unaligned start */ + if((aln = addr - wp) != 0) { + cword.l = 0; + cp = wp; + for(i=0;iportwidth) && (cnt > 0) ; i++) { + flash_add_byte(info, &cword, *src++); + cnt--; + cp++; + } + for(; (cnt == 0) && (i < info->portwidth); ++i, ++cp) + flash_add_byte(info, &cword, (*(uchar *)cp)); + if((rc = flash_write_cfiword(info, wp, cword)) != 0) + return rc; + wp = cp; + } + +#ifdef CFG_FLASH_USE_BUFFER_WRITE + while(cnt >= info->portwidth) { + i = info->buffer_size > cnt? cnt: info->buffer_size; + if((rc = flash_write_cfibuffer(info, wp, src,i)) != ERR_OK) + return rc; + wp += i; + src += i; + cnt -=i; + } +#else + /* handle the aligned part */ + while(cnt >= info->portwidth) { + cword.l = 0; + for(i = 0; i < info->portwidth; i++) { + flash_add_byte(info, &cword, *src++); + } + if((rc = flash_write_cfiword(info, wp, cword)) != 0) + return rc; + wp += info->portwidth; + cnt -= info->portwidth; + } +#endif /* CFG_FLASH_USE_BUFFER_WRITE */ + if (cnt == 0) { + return (0); + } + + /* + * handle unaligned tail bytes + */ + cword.l = 0; + for (i=0, cp=wp; (iportwidth) && (cnt>0); ++i, ++cp) { + flash_add_byte(info, &cword, *src++); + --cnt; + } + for (; iportwidth; ++i, ++cp) { + flash_add_byte(info, & cword, (*(uchar *)cp)); + } + + return flash_write_cfiword(info, wp, cword); +} + +/*----------------------------------------------------------------------- + */ +#ifdef CFG_FLASH_PROTECTION + +int flash_real_protect(flash_info_t *info, long sector, int prot) +{ + int retcode = 0; + + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT); + if(prot) + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_SET); + else + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_CLEAR); + + if((retcode = flash_full_status_check(info, sector, info->erase_blk_tout, + prot?"protect":"unprotect")) == 0) { + + info->protect[sector] = prot; + /* Intel's unprotect unprotects all locking */ + if(prot == 0) { + flash_sect_t i; + for(i = 0 ; isector_count; i++) { + if(info->protect[i]) + flash_real_protect(info, i, 1); + } + } + } + + return retcode; + } +/*----------------------------------------------------------------------- + * flash_read_user_serial - read the OneTimeProgramming cells + */ +void flash_read_user_serial(flash_info_t * info, void * buffer, int offset, int len) +{ + uchar * src; + uchar * dst; + + dst = buffer; + src = flash_make_addr(info, 0, FLASH_OFFSET_USER_PROTECTION); + flash_write_cmd(info,0, 0, FLASH_CMD_READ_ID); + memcpy(dst,src + offset,len); + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); +} +/* + * flash_read_factory_serial - read the device Id from the protection area + */ +void flash_read_factory_serial(flash_info_t * info, void * buffer, int offset, int len) +{ + uchar * src; + + src = flash_make_addr(info, 0, FLASH_OFFSET_INTEL_PROTECTION); + flash_write_cmd(info,0, 0, FLASH_CMD_READ_ID); + memcpy(buffer,src + offset,len); + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); +} + +#endif /* CFG_FLASH_PROTECTION */ + +static int flash_poll_status(flash_info_t * info, flash_sect_t sect) +{ + int retval; + switch(info->vendor) { + case CFI_CMDSET_INTEL_STANDARD: + case CFI_CMDSET_INTEL_EXTENDED: + retval = !flash_isset(info, sect, 0, FLASH_STATUS_DONE); + break; + case CFI_CMDSET_AMD_STANDARD: + case CFI_CMDSET_AMD_EXTENDED: + retval = flash_toggle(info, sect, 0, AMD_STATUS_TOGGLE); + break; + default: + retval = 0; + } + return retval; +} +/*----------------------------------------------------------------------- + * wait for XSR.7 to be set. Time out with an error if it does not. + * This routine does not set the flash to read-array mode. + */ +static int flash_status_check(flash_info_t * info, flash_sect_t sector, ulong tout, char * prompt) +{ + ulong start; + + /* Wait for command completion */ + start = get_timer (0); + while (flash_poll_status(info, sector)) { + if (get_timer(start) > info->erase_blk_tout) { + printf("Flash %s timeout at address %lx\n", prompt, info->start[sector]); + flash_write_cmd(info, sector, 0, info->cmd_reset); + return ERR_TIMOUT; + } + } + return ERR_OK; +} +/*----------------------------------------------------------------------- + * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check. + * This routine sets the flash to read-array mode. + */ +static int flash_full_status_check(flash_info_t * info, flash_sect_t sector, ulong tout, char * prompt) +{ + int retcode; + retcode = flash_status_check(info, sector, tout, prompt); + switch(info->vendor) { + case CFI_CMDSET_INTEL_EXTENDED: + case CFI_CMDSET_INTEL_STANDARD: + if((retcode == ERR_OK) && !flash_isequal(info,sector, 0, FLASH_STATUS_DONE)) { + retcode = ERR_INVAL; + printf("Flash %s error at address %lx\n", prompt,info->start[sector]); + if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)){ + printf("Command Sequence Error.\n"); + } else if(flash_isset(info, sector, 0, FLASH_STATUS_ECLBS)){ + printf("Block Erase Error.\n"); + retcode = ERR_NOT_ERASED; + } else if (flash_isset(info, sector, 0, FLASH_STATUS_PSLBS)) { + printf("Locking Error\n"); + } + if(flash_isset(info, sector, 0, FLASH_STATUS_DPS)){ + printf("Block locked.\n"); + retcode = ERR_PROTECTED; + } + if(flash_isset(info, sector, 0, FLASH_STATUS_VPENS)) + printf("Vpp Low Error.\n"); + } + flash_write_cmd(info, sector, 0, FLASH_CMD_RESET); + break; + default: + break; + } + return retcode; +} +/*----------------------------------------------------------------------- + */ +static void flash_add_byte(flash_info_t *info, cfiword_t * cword, uchar c) +{ + switch(info->portwidth) { + case FLASH_CFI_8BIT: + cword->c = c; + break; + case FLASH_CFI_16BIT: + cword->w = (cword->w << 8) | c; + break; + case FLASH_CFI_32BIT: + cword->l = (cword->l << 8) | c; + break; + case FLASH_CFI_64BIT: + cword->ll = (cword->ll << 8) | c; + break; + } +} + + +/*----------------------------------------------------------------------- + * make a proper sized command based on the port and chip widths + */ +static void flash_make_cmd(flash_info_t * info, uchar cmd, void * cmdbuf) +{ + int i; + uchar *cp = (uchar *)cmdbuf; + for(i=0; i< info->portwidth; i++) + *cp++ = ((i+1) % info->chipwidth) ? '\0':cmd; +} + +/* + * Write a proper sized command to the correct address + */ +static void flash_write_cmd(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +{ + + volatile cfiptr_t addr; + cfiword_t cword; + addr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch(info->portwidth) { + case FLASH_CFI_8BIT: + debug("fwc addr %p cmd %x %x 8bit x %d bit\n",addr.cp, cmd, cword.c, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + *addr.cp = cword.c; + break; + case FLASH_CFI_16BIT: + debug("fwc addr %p cmd %x %4.4x 16bit x %d bit\n",addr.wp, cmd, cword.w, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + *addr.wp = cword.w; + break; + case FLASH_CFI_32BIT: + debug("fwc addr %p cmd %x %8.8lx 32bit x %d bit\n",addr.lp, cmd, cword.l, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + *addr.lp = cword.l; + break; + case FLASH_CFI_64BIT: +#ifdef DEBUG + { + char str[20]; + print_longlong(str, cword.ll); + + printf("fwc addr %p cmd %x %s 64 bit x %d bit\n",addr.llp, cmd, str, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + } +#endif + *addr.llp = cword.ll; + break; + } +} + +static void flash_unlock_seq(flash_info_t *info) +{ + flash_write_cmd(info, 0, 0x555, 0xAA); + flash_write_cmd(info, 0, 0x2AA, 0x55); +} +/*----------------------------------------------------------------------- + */ +static int flash_isequal(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + cptr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + + debug("is= cmd %x(%c) addr %p ", cmd,cmd, cptr.cp); + switch(info->portwidth) { + case FLASH_CFI_8BIT: + debug("is= %x %x\n", cptr.cp[0], cword.c); + retval = (cptr.cp[0] == cword.c); + break; + case FLASH_CFI_16BIT: + debug("is= %4.4x %4.4x\n", cptr.wp[0], cword.w); + retval = (cptr.wp[0] == cword.w); + break; + case FLASH_CFI_32BIT: + debug("is= %8.8lx %8.8lx\n", cptr.lp[0], cword.l); + retval = (cptr.lp[0] == cword.l); + break; + case FLASH_CFI_64BIT: +#ifdef DEBUG + { + char str1[20]; + char str2[20]; + print_longlong(str1, cptr.llp[0]); + print_longlong(str2, cword.ll); + printf("is= %s %s\n", str1, str2); + } +#endif + retval = (cptr.llp[0] == cword.ll); + break; + default: + retval = 0; + break; + } + return retval; +} +/*----------------------------------------------------------------------- + */ +static int flash_isset(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + cptr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch(info->portwidth) { + case FLASH_CFI_8BIT: + retval = ((cptr.cp[0] & cword.c) == cword.c); + break; + case FLASH_CFI_16BIT: + retval = ((cptr.wp[0] & cword.w) == cword.w); + break; + case FLASH_CFI_32BIT: + retval = ((cptr.lp[0] & cword.l) == cword.l); + break; + case FLASH_CFI_64BIT: + retval = ((cptr.llp[0] & cword.ll) == cword.ll); + default: + retval = 0; + break; + } + return retval; +} + +/*----------------------------------------------------------------------- + */ +static int flash_toggle(flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + cptr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch(info->portwidth) { + case FLASH_CFI_8BIT: + retval = ((cptr.cp[0] & cword.c) != (cptr.cp[0] & cword.c)); + break; + case FLASH_CFI_16BIT: + retval = ((cptr.wp[0] & cword.w) != (cptr.wp[0] & cword.w)); + break; + case FLASH_CFI_32BIT: + retval = ((cptr.lp[0] & cword.l) != (cptr.lp[0] & cword.l)); + break; + case FLASH_CFI_64BIT: + retval = ((cptr.llp[0] & cword.ll) != (cptr.llp[0] & cword.ll)); + break; + default: + retval = 0; + break; + } + return retval; +} + +/*----------------------------------------------------------------------- + * detect if flash is compatible with the Common Flash Interface (CFI) + * http://www.jedec.org/download/search/jesd68.pdf + * +*/ +static int flash_detect_cfi(flash_info_t * info) +{ + + puts("flash detect cfi\n"); + + for(info->portwidth=FLASH_CFI_8BIT; info->portwidth <= FLASH_CFI_64BIT; + info->portwidth <<= 1) { + /* for(info->chipwidth = info->portwidth; + info->chipwidth > 0; + info->chipwidth >>= 1) { */ + for(info->chipwidth =FLASH_CFI_BY8; + info->chipwidth <= info->portwidth; + info->chipwidth <<= 1) { + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); + flash_write_cmd(info, 0, FLASH_OFFSET_CFI, FLASH_CMD_CFI); + if(flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP,'Q') && + flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R') && + flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y')) { + debug("found port %d chip %d ", info->portwidth, info->chipwidth); + debug("port %d bits chip %d bits\n", info->portwidth << CFI_FLASH_SHIFT_WIDTH, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + return 1; + } + } + } + puts("not found\n"); + return 0; +} +/* + * The following code cannot be run from FLASH! + * + */ +static ulong flash_get_size (ulong base, int banknum) +{ + flash_info_t * info = &flash_info[banknum]; + int i, j; + flash_sect_t sect_cnt; + unsigned long sector; + unsigned long tmp; + int size_ratio; + uchar num_erase_regions; + int erase_region_size; + int erase_region_count; + + info->start[0] = base; + + if(flash_detect_cfi(info)){ + info->vendor = flash_read_ushort(info, 0, FLASH_OFFSET_PRIMARY_VENDOR); + switch(info->vendor) { + case CFI_CMDSET_INTEL_STANDARD: + case CFI_CMDSET_INTEL_EXTENDED: + default: + info->cmd_reset = FLASH_CMD_RESET; + break; + case CFI_CMDSET_AMD_STANDARD: + case CFI_CMDSET_AMD_EXTENDED: + info->cmd_reset = AMD_CMD_RESET; + break; + } + + debug("manufacturer is %d\n", info->vendor); + size_ratio = info->portwidth / info->chipwidth; + num_erase_regions = flash_read_uchar(info, FLASH_OFFSET_NUM_ERASE_REGIONS); + debug("size_ration %d port %d bits chip %d bits\n", size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, + info->chipwidth << CFI_FLASH_SHIFT_WIDTH); + debug("found %d erase regions\n", num_erase_regions); + sect_cnt = 0; + sector = base; + for(i = 0 ; i < num_erase_regions; i++) { + if(i > NUM_ERASE_REGIONS) { + printf("%d erase regions found, only %d used\n", + num_erase_regions, NUM_ERASE_REGIONS); + break; + } + tmp = flash_read_long(info, 0, FLASH_OFFSET_ERASE_REGIONS + i*4); + erase_region_size = (tmp & 0xffff)? ((tmp & 0xffff) * 256): 128; + tmp >>= 16; + erase_region_count = (tmp & 0xffff) +1; + for(j = 0; j< erase_region_count; j++) { + info->start[sect_cnt] = sector; + sector += (erase_region_size * size_ratio); + info->protect[sect_cnt] = flash_isset(info, sect_cnt, FLASH_OFFSET_PROTECT, FLASH_STATUS_PROTECT); + sect_cnt++; + } + } + + info->sector_count = sect_cnt; + /* multiply the size by the number of chips */ + info->size = (1 << flash_read_uchar(info, FLASH_OFFSET_SIZE)) * size_ratio; + info->buffer_size = (1 << flash_read_ushort(info, 0, FLASH_OFFSET_BUFFER_SIZE)); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_ETOUT); + info->erase_blk_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_EMAX_TOUT))); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WBTOUT); + info->buffer_write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WBMAX_TOUT))); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WTOUT); + info->write_tout = (tmp * (1 << flash_read_uchar(info, FLASH_OFFSET_WMAX_TOUT)))/ 1000; + info->flash_id = FLASH_MAN_CFI; + } + + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); + return(info->size); +} + + +/*----------------------------------------------------------------------- + */ +static int flash_write_cfiword (flash_info_t *info, ulong dest, cfiword_t cword) +{ + + cfiptr_t ctladdr; + cfiptr_t cptr; + int flag; + + ctladdr.cp = flash_make_addr(info, 0, 0); + cptr.cp = (uchar *)dest; + + + /* Check if Flash is (sufficiently) erased */ + switch(info->portwidth) { + case FLASH_CFI_8BIT: + flag = ((cptr.cp[0] & cword.c) == cword.c); + break; + case FLASH_CFI_16BIT: + flag = ((cptr.wp[0] & cword.w) == cword.w); + break; + case FLASH_CFI_32BIT: + flag = ((cptr.lp[0] & cword.l) == cword.l); + break; + case FLASH_CFI_64BIT: + flag = ((cptr.lp[0] & cword.ll) == cword.ll); + break; + default: + return 2; + } + if(!flag) + return 2; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + switch(info->vendor) { + case CFI_CMDSET_INTEL_EXTENDED: + case CFI_CMDSET_INTEL_STANDARD: + flash_write_cmd(info, 0, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, 0, 0, FLASH_CMD_WRITE); + break; + case CFI_CMDSET_AMD_EXTENDED: + case CFI_CMDSET_AMD_STANDARD: + flash_unlock_seq(info); + flash_write_cmd(info, 0, 0x555, AMD_CMD_WRITE); + break; + } + + switch(info->portwidth) { + case FLASH_CFI_8BIT: + cptr.cp[0] = cword.c; + break; + case FLASH_CFI_16BIT: + cptr.wp[0] = cword.w; + break; + case FLASH_CFI_32BIT: + cptr.lp[0] = cword.l; + break; + case FLASH_CFI_64BIT: + cptr.llp[0] = cword.ll; + break; + } + + /* re-enable interrupts if necessary */ + if(flag) + enable_interrupts(); + + return flash_full_status_check(info, 0, info->write_tout, "write"); +} + +#ifdef CFG_FLASH_USE_BUFFER_WRITE + +/* loop through the sectors from the highest address + * when the passed address is greater or equal to the sector address + * we have a match + */ +static flash_sect_t find_sector(flash_info_t *info, ulong addr) +{ + flash_sect_t sector; + for(sector = info->sector_count - 1; sector >= 0; sector--) { + if(addr >= info->start[sector]) + break; + } + return sector; +} + +static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, int len) +{ + flash_sect_t sector; + int cnt; + int retcode; + volatile cfiptr_t src; + volatile cfiptr_t dst; + + src.cp = cp; + dst.cp = (uchar *)dest; + sector = find_sector(info, dest); + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); + if((retcode = flash_status_check(info, sector, info->buffer_write_tout, + "write to buffer")) == ERR_OK) { + switch(info->portwidth) { + case FLASH_CFI_8BIT: + cnt = len; + break; + case FLASH_CFI_16BIT: + cnt = len >> 1; + break; + case FLASH_CFI_32BIT: + cnt = len >> 2; + break; + case FLASH_CFI_64BIT: + cnt = len >> 3; + break; + default: + return ERR_INVAL; + break; + } + flash_write_cmd(info, sector, 0, (uchar)cnt-1); + while(cnt-- > 0) { + switch(info->portwidth) { + case FLASH_CFI_8BIT: + *dst.cp++ = *src.cp++; + break; + case FLASH_CFI_16BIT: + *dst.wp++ = *src.wp++; + break; + case FLASH_CFI_32BIT: + *dst.lp++ = *src.lp++; + break; + case FLASH_CFI_64BIT: + *dst.llp++ = *src.llp++; + break; + default: + return ERR_INVAL; + break; + } + } + flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_BUFFER_CONFIRM); + retcode = flash_full_status_check(info, sector, info->buffer_write_tout, + "buffer write"); + } + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + return retcode; +} +#endif /* CFG_USE_FLASH_BUFFER_WRITE */ +#endif /* CFG_FLASH_CFI */ diff --git a/drivers/pci_auto.c b/drivers/pci_auto.c index 20acc0713e..39b7e8e33b 100644 --- a/drivers/pci_auto.c +++ b/drivers/pci_auto.c @@ -163,7 +163,8 @@ static void pciauto_prescan_setup_bridge(struct pci_controller *hose, /* Configure bus number registers */ pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS, PCI_BUS(dev)); - pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS, sub_bus + 1); + /* TBS: passed in sub_bus is correct, removed the +1 */ + pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS, sub_bus); pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff); if (pci_mem) @@ -284,6 +285,7 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) unsigned int sub_bus = PCI_BUS(dev); unsigned short class; unsigned char prg_iface; + int n; pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); @@ -294,11 +296,19 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_io); DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev)); - pciauto_prescan_setup_bridge(hose, dev, sub_bus); - - pci_hose_scan_bus(hose, hose->current_busno); - + + /* TBS: Passing in current_busno allows for sibling P2P bridges */ + pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); + /* + * TBS: need to figure out if this is a subordinate bridge on the bus + * to be able to properly set the pri/sec/sub bridge registers. + */ + n = pci_hose_scan_bus(hose, hose->current_busno); + + /* TBS: figure out the deepest we've gone for this leg */ + sub_bus = max(n, sub_bus); pciauto_postscan_setup_bridge(hose, dev, sub_bus); + sub_bus = hose->current_busno; break; diff --git a/include/configs/DK1C20.h b/include/configs/DK1C20.h index 92c8e517eb..f3570512e2 100644 --- a/include/configs/DK1C20.h +++ b/include/configs/DK1C20.h @@ -647,8 +647,8 @@ * ASMI is for Cyclone devices only and only works when the configuration * is loaded via JTAG or ASMI. Please see doc/README.dk1c20 for details. *----------------------------------------------------------------------*/ -#define CONFIG_NIOS_ASMI /* Enable ASMI */ -#define CFG_NIOS_ASMIBASE 0x00920b00 /* ASMI base address */ +#define CONFIG_NIOS_ASMI /* Enable ASMI */ +#define CFG_NIOS_ASMIBASE CFG_NIOS_CPU_ASMI0 /* ASMI base address */ /*------------------------------------------------------------------------ * COMMANDS diff --git a/include/flash.h b/include/flash.h index 8f20887e4b..0cfc76d32c 100644 --- a/include/flash.h +++ b/include/flash.h @@ -42,7 +42,8 @@ typedef struct { ulong erase_blk_tout; /* maximum block erase timeout */ ulong write_tout; /* maximum write timeout */ ulong buffer_write_tout; /* maximum buffer write timeout */ - + ushort vendor; /* the primary vendor id */ + ushort cmd_reset; /* Vendor specific reset command */ #endif } flash_info_t; @@ -61,6 +62,8 @@ typedef struct { #define FLASH_CFI_BY32 0x04 #define FLASH_CFI_BY64 0x08 +/* convert between bit value and numeric value */ +#define CFI_FLASH_SHIFT_WIDTH 3 /* Prototypes */ extern unsigned long flash_init (void); @@ -78,6 +81,8 @@ extern int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt); /* board/?/flash.c */ #if defined(CFG_FLASH_PROTECTION) extern int flash_real_protect(flash_info_t *info, long sector, int prot); +extern void flash_read_user_serial(flash_info_t * info, void * buffer, int offset, int len); +extern void flash_read_factory_serial(flash_info_t * info, void * buffer, int offset, int len); #endif /* CFG_FLASH_PROTECTION */ /*----------------------------------------------------------------------- -- 2.39.2