diff options
32 files changed, 4635 insertions, 880 deletions
@@ -118,6 +118,7 @@ LIBS += disk/libdisk.a LIBS += rtc/librtc.a LIBS += dtt/libdtt.a LIBS += drivers/libdrivers.a +LIBS += drivers/nand/libnand.a LIBS += drivers/sk98lin/libsk98lin.a LIBS += post/libpost.a post/cpu/libcpu.a LIBS += common/libcommon.a @@ -1391,6 +1392,17 @@ mx1ads_config : unconfig mx1fs2_config : unconfig @./mkconfig $(@:_config=) arm arm920t mx1fs2 NULL imx +netstar_32_config \ +netstar_config: unconfig + @if [ "$(findstring _32_,$@)" ] ; then \ + echo "... 32MB SDRAM" ; \ + echo "#define PHYS_SDRAM_1_SIZE SZ_32M" >>include/config.h ; \ + else \ + echo "... 64MB SDRAM" ; \ + echo "#define PHYS_SDRAM_1_SIZE SZ_64M" >>include/config.h ; \ + fi + @./mkconfig -a netstar arm arm925t netstar + omap1510inn_config : unconfig @./mkconfig $(@:_config=) arm arm925t omap1510inn diff --git a/board/netstar/Makefile b/board/netstar/Makefile new file mode 100644 index 0000000000..8ef21893ee --- /dev/null +++ b/board/netstar/Makefile @@ -0,0 +1,85 @@ +# +# (C) Copyright 2005 +# Ladislav Michl, 2N Telekomunikace, michl@2n.cz +# +# 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 $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +OBJS := netstar.o flash.o nand.o +SOBJS := setup.o crcek.o + +gcclibdir := $(shell dirname `$(CC) -print-libgcc-file-name`) + +LOAD_ADDR = 0x10400000 +LDSCRIPT = $(TOPDIR)/board/$(BOARDDIR)/eeprom.lds + +HOST_CFLAGS = -Wall -pedantic -I$(TOPDIR)/include + +all: $(LIB) eeprom.srec eeprom.bin crcek.srec crcek.bin crcit + +$(LIB): $(OBJS) $(SOBJS) + $(AR) crv $@ $^ + +eeprom.srec: eeprom.o eeprom_start.o + $(LD) -T $(LDSCRIPT) -g -Ttext $(LOAD_ADDR) \ + -o $(<:.o=) -e $(<:.o=) $^ \ + -L../../examples -lstubs \ + -L../../lib_generic -lgeneric \ + -L$(gcclibdir) -lgcc + $(OBJCOPY) -O srec $(<:.o=) $@ + +eeprom.bin: eeprom.srec + $(OBJCOPY) -I srec -O binary $< $@ 2>/dev/null + +crcek.srec: crcek.o + $(LD) -g -Ttext 0x00000000 \ + -o $(<:.o=) -e $(<:.o=) $^ + $(OBJCOPY) -O srec $(<:.o=) $@ + +crcek.bin: crcek.srec + $(OBJCOPY) -I srec -O binary $< $@ 2>/dev/null + +crcit: crcit.o crc32.o + $(HOSTCC) $(HOST_CFLAGS) -o $@ $^ + +crcit.o: crcit.c + $(HOSTCC) $(HOST_CFLAGS) -c $< + +crc32.o: $(TOPDIR)/tools/crc32.c + $(HOSTCC) $(HOST_CFLAGS) -DUSE_HOSTCC -c $< + +clean: + rm -f $(SOBJS) $(OBJS) eeprom eeprom.srec eeprom.bin \ + crcek crcek.srec crcek.bin + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +-include .depend + +######################################################################### diff --git a/board/netstar/config.mk b/board/netstar/config.mk new file mode 100644 index 0000000000..8b73e97598 --- /dev/null +++ b/board/netstar/config.mk @@ -0,0 +1,11 @@ +# +# Linux-Kernel is expected to be at 1000'8000, +# entry 1000'8000 (mem base + reserved) +# +# We load ourself to internal RAM at 2001'2000 +# Check map file when changing TEXT_BASE. +# Everything has fit into 192kB internal SRAM! +# + +# XXX TEXT_BASE = 0x20012000 +TEXT_BASE = 0x13FC0000 diff --git a/board/netstar/crcek.S b/board/netstar/crcek.S new file mode 100644 index 0000000000..6ca4d11df8 --- /dev/null +++ b/board/netstar/crcek.S @@ -0,0 +1,177 @@ +/** + * (C) Copyright 2005 + * 2N Telekomunikace, Ladislav Michl <michl@2n.cz> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2. + * + * Image layout looks like following: + * u32 - size + * u32 - version + * ... - data + * u32 - crc32 + */ + +#include "crcek.h" + +/** + * do_crc32 - calculate CRC32 of given buffer + * r0 - crc + * r1 - pointer to buffer + * r2 - buffer len + */ + .macro do_crc32 + ldr r5, FFFFFFFF + eor r0, r0, r5 + adr r3, CRC32_TABLE +1: + ldrb r4, [r1], #1 + eor r4, r4, r0 + and r4, r4, #0xff + ldr r4, [r3, r4, lsl#2] + eor r0, r4, r0, lsr#8 + subs r2, r2, #0x1 + bne 1b + eor r0, r0, r5 + .endm + + .macro crcuj, offset, size + mov r0, #0 + ldr r1, \offset + ldr r2, [r1] + cmp r2, r0 @ no data, no problem + beq 2f + tst r2, #3 @ unaligned size + bne 2f + ldr r3, \size + cmp r2, r3 @ bogus size + bhi 2f + add r1, r1, #4 + do_crc32 + ldr r1, [r1] +2: + cmp r0, r1 + .endm + + .macro wait, reg + mov \reg, #0x1000 +3: + subs \reg, \reg, #0x1 + bne 3b + + .endm +.text +.globl crcek +crcek: + b crc2_bad + mov r6, #0 + crcuj _LOADER1_OFFSET, _LOADER_SIZE + bne crc1_bad + orr r6, r6, #1 +crc1_bad: + crcuj _LOADER2_OFFSET, _LOADER_SIZE + bne crc2_bad + orr r6, r6, #2 +crc2_bad: + ldr r3, _LOADER1_OFFSET + ldr r4, _LOADER2_OFFSET + b boot_2nd + tst r6, #3 + beq one_is_bad @ one of them (or both) has bad crc + ldr r1, [r3, #4] + ldr r2, [r4, #4] + cmp r1, r2 @ boot 2nd loader if versions differ + beq boot_1st + b boot_2nd +one_is_bad: + tst r6, #1 + bne boot_1st + tst r6, #2 + bne boot_2nd +@ We are doomed, so let user know. + ldr r0, GPIO_BASE @ configure GPIO pins + ldr r1, GPIO_DIRECTION + strh r1, [r0, #0x08] +blink_loop: + mov r1, #0x08 + strh r1, [r0, #0x04] + wait r3 + mov r1, #0x10 + strh r1, [r0, #0x04] + wait r3 + b blink_loop +boot_1st: + add pc, r3, #8 +boot_2nd: + add pc, r4, #8 + +_LOADER_SIZE: + .word LOADER_SIZE - 8 @ minus size and crc32 +_LOADER1_OFFSET: + .word LOADER1_OFFSET +_LOADER2_OFFSET: + .word LOADER2_OFFSET + +FFFFFFFF: + .word 0xffffffff +CRC32_TABLE: + .word 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419 + .word 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4 + .word 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07 + .word 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de + .word 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856 + .word 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9 + .word 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4 + .word 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b + .word 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3 + .word 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a + .word 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599 + .word 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924 + .word 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190 + .word 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f + .word 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e + .word 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01 + .word 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed + .word 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950 + .word 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3 + .word 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2 + .word 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a + .word 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5 + .word 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010 + .word 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f + .word 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17 + .word 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6 + .word 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615 + .word 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8 + .word 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344 + .word 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb + .word 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a + .word 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5 + .word 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1 + .word 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c + .word 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef + .word 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236 + .word 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe + .word 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31 + .word 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c + .word 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713 + .word 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b + .word 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242 + .word 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1 + .word 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c + .word 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278 + .word 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7 + .word 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66 + .word 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9 + .word 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605 + .word 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8 + .word 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b + .word 0x2d02ef8d + +GPIO_BASE: + .word 0xfffce000 +GPIO_DIRECTION: + .word 0x0000ffe7 + +.end diff --git a/board/netstar/crcek.h b/board/netstar/crcek.h new file mode 100644 index 0000000000..30c08602f5 --- /dev/null +++ b/board/netstar/crcek.h @@ -0,0 +1,3 @@ +#define LOADER_SIZE (448 * 1024) +#define LOADER1_OFFSET (128 * 1024) +#define LOADER2_OFFSET (LOADER1_OFFSET + LOADER_SIZE) diff --git a/board/netstar/crcit.c b/board/netstar/crcit.c new file mode 100644 index 0000000000..f6d3066c15 --- /dev/null +++ b/board/netstar/crcit.c @@ -0,0 +1,86 @@ +/* + * (C) Copyright 2005 + * 2N Telekomunikace, Ladislav Michl <michl@2n.cz> + * + * 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 <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "crcek.h" + +extern unsigned long crc32(unsigned long, const unsigned char *, unsigned int); + +uint32_t data[LOADER_SIZE/4 + 3]; + +int doit(char *path, unsigned version) +{ + uint32_t *p; + ssize_t size; + int fd; + + fd = open(path, O_RDONLY); + if (fd == -1) { + perror("Error opening file"); + return EXIT_FAILURE; + } + p = data + 2; + size = read(fd, p, LOADER_SIZE + 4); + if (size == -1) { + perror("Error reading file"); + return EXIT_FAILURE; + } + if (size > LOADER_SIZE) { + fprintf(stderr, "File too large\n"); + return EXIT_FAILURE; + } + size = (((size - 1) >> 2) + 1) << 2; + data[0] = size + 4; /* add size of version field */ + data[1] = version; + data[(size >> 2) + 2] = crc32(0, (unsigned char *)(data + 1), data[0]); + close(fd); + + if (write(STDOUT_FILENO, data, size + 3*4) == -1) { + perror("Error writing file"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + if (argc == 2) { + return doit(argv[1], 0); + } else if ((argc == 4) && (strcmp(argv[1], "-v") == 0)) { + char *endptr, *nptr = argv[2]; + unsigned ver = strtoul(nptr, &endptr, 0); + if (nptr != '\0' && endptr == '\0') + return doit(argv[3], ver); + } + fprintf(stderr, "Usage: crcit [-v version] <image>\n"); + + return EXIT_FAILURE; +} diff --git a/board/netstar/eeprom.c b/board/netstar/eeprom.c new file mode 100644 index 0000000000..fef3822aae --- /dev/null +++ b/board/netstar/eeprom.c @@ -0,0 +1,215 @@ +/* + * (C) Copyright 2005 + * Ladislav Michl, 2N Telekomunikace, michl@2n.cz + * + * 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 version 2 as + * published by the Free Software Foundation. + * + * 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 + * + * Some code shamelessly stolen back from Robin Getz. + */ + +#define DEBUG + +#include <common.h> +#include <exports.h> +#include "../drivers/smc91111.h" + +#define SMC_BASE_ADDRESS CONFIG_SMC91111_BASE + +static u16 read_eeprom_reg(u16 reg) +{ + int timeout; + + SMC_SELECT_BANK(2); + SMC_outw(reg, PTR_REG); + + SMC_SELECT_BANK(1); + SMC_outw(SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_RELOAD, + CTL_REG); + timeout = 100; + while((SMC_inw (CTL_REG) & CTL_RELOAD) && --timeout) + udelay(100); + if (timeout == 0) { + printf("Timeout Reading EEPROM register %02x\n", reg); + return 0; + } + + return SMC_inw (GP_REG); +} + +static int write_eeprom_reg(u16 value, u16 reg) +{ + int timeout; + + SMC_SELECT_BANK(2); + SMC_outw(reg, PTR_REG); + + SMC_SELECT_BANK(1); + SMC_outw(value, GP_REG); + SMC_outw(SMC_inw (CTL_REG) | CTL_EEPROM_SELECT | CTL_STORE, CTL_REG); + timeout = 100; + while ((SMC_inw(CTL_REG) & CTL_STORE) && --timeout) + udelay (100); + if (timeout == 0) { + printf("Timeout Writing EEPROM register %02x\n", reg); + return 0; + } + + return 1; +} + +static int write_data(u16 *buf, int len) +{ + u16 reg = 0x23; + + while (len--) + write_eeprom_reg(*buf++, reg++); + + return 0; +} + +static int verify_macaddr(char *s) +{ + u16 reg; + int i, err = 0; + + printf("MAC Address: "); + err = i = 0; + for (i = 0; i < 3; i++) { + reg = read_eeprom_reg(0x20 + i); + printf("%02x:%02x%c", reg & 0xff, reg >> 8, i != 2 ? ':' : '\n'); + if (s) + err |= reg != ((u16 *)s)[i]; + } + + return err ? 0 : 1; +} + +static int set_mac(char *s) +{ + int i; + char *e, eaddr[6]; + + /* turn string into mac value */ + for (i = 0; i < 6; i++) { + eaddr[i] = simple_strtoul(s, &e, 16); + s = (*e) ? e+1 : e; + } + + for (i = 0; i < 3; i++) + write_eeprom_reg(*(((u16 *)eaddr) + i), 0x20 + i); + + return 0; +} + +static int parse_element(char *s, unsigned char *buf, int len) +{ + int cnt; + char *p, num[3]; + unsigned char id; + + id = simple_strtoul(s, &p, 16); + if (*p++ != ':') + return -1; + cnt = 2; + num[2] = 0; + for (; *p; p += 2) { + if (p[1] == 0) + return -2; + if (cnt + 3 > len) + return -3; + num[0] = p[0]; + num[1] = p[1]; + buf[cnt++] = simple_strtoul(num, NULL, 16); + } + buf[0] = id; + buf[1] = cnt - 2; + + return cnt; +} + +extern int crcek(void); + +int eeprom(int argc, char *argv[]) +{ + int i, len, ret; + unsigned char buf[58], *p; + + app_startup(argv); + if (get_version() != XF_VERSION) { + printf("Wrong XF_VERSION.\n"); + printf("Application expects ABI version %d\n", XF_VERSION); + printf("Actual U-Boot ABI version %d\n", (int)get_version()); + return 1; + } + + return crcek(); + + if ((SMC_inw (BANK_SELECT) & 0xFF00) != 0x3300) { + printf("SMSC91111 not found.\n"); + return 2; + } + + /* Called without parameters - print MAC address */ + if (argc < 2) { + verify_macaddr(NULL); + return 0; + } + + /* Print help message */ + if (argv[1][1] == 'h') { + printf("VoiceBlue EEPROM writer\n"); + printf("Built: %s at %s\n", __DATE__ , __TIME__ ); + printf("Usage:\n\t<mac_address> [<element_1>] [<...>]\n"); + return 0; + } + + /* Try to parse information elements */ + len = sizeof(buf); + p = buf; + for (i = 2; i < argc; i++) { + ret = parse_element(argv[i], p, len); + switch (ret) { + case -1: + printf("Element %d: malformed\n", i - 1); + return 3; + case -2: + printf("Element %d: odd character count\n", i - 1); + return 3; + case -3: + printf("Out of EEPROM memory\n"); + return 3; + default: + p += ret; + len -= ret; + } + } + + /* First argument (MAC) is mandatory */ + set_mac(argv[1]); + if (verify_macaddr(argv[1])) { + printf("*** MAC address does not match! ***\n"); + return 4; + } + + while (len--) + *p++ = 0; + + write_data((u16 *)buf, sizeof(buf) >> 1); + + return 0; +} diff --git a/board/netstar/eeprom.lds b/board/netstar/eeprom.lds new file mode 100644 index 0000000000..317550dbad --- /dev/null +++ b/board/netstar/eeprom.lds @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * (C) Copyright 2005 + * Ladislav Michl, 2N Telekomunikace, <michl@2n.cz> + * + * 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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = ALIGN(4); + .text : + { + eeprom_start.o (.text) + *(.text) + } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + .got : { *(.got) } + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/board/netstar/eeprom_start.S b/board/netstar/eeprom_start.S new file mode 100644 index 0000000000..75d9f0558f --- /dev/null +++ b/board/netstar/eeprom_start.S @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2005 2N Telekomunikace + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + */ + +.globl _start +_start: b eeprom + +#include "crcek.h" + +/** + * do_crc32 - calculate CRC32 of given buffer + * r0 - crc + * r1 - pointer to buffer + * r2 - buffer len + */ + .macro do_crc32 + ldr r5, FFFFFFFF + eor r0, r0, r5 + adr r3, CRC32_TABLE +1: + ldrb r4, [r1], #1 + eor r4, r4, r0 + and r4, r4, #0xff + ldr r4, [r3, r4, lsl#2] + eor r0, r4, r0, lsr#8 + subs r2, r2, #0x1 + bne 1b + eor r0, r0, r5 + .endm + + .macro crcuj, offset, size + ldr r1, \offset + ldr r2, [r1] + cmp r2, #0 @ no data, no problem + beq 2f + mov r7, #1 + tst r2, #3 @ unaligned size + bne 2f + mov r7, #2 + ldr r0, \size + cmp r2, r0 @ bogus size + bhi 2f + mov r7, #3 + add r1, r1, #4 + mov r0, #0 + do_crc32 + ldr r1, [r1] +2: + cmp r0, r1 + .endm + + .macro wait, reg + mov \reg, #0x1000 +3: + subs \reg, \reg, #0x1 + bne 3b + + .endm +.text +.globl crcek +crcek: + mov r6, #0 +@ crcuj _LOADER1_OFFSET, _LOADER_SIZE +@ bne crc1_bad +@ orr r6, r6, #1 +crc1_bad: + crcuj _LOADER2_OFFSET, _LOADER_SIZE + bne crc2_bad + orr r6, r6, #2 +crc2_bad: +@ mov r0, r6 + mov pc, lr + ldr r3, _LOADER1_OFFSET + ldr r4, _LOADER2_OFFSET + tst r6, #3 + beq one_is_bad @ one of them (or both) has bad crc + ldr r1, [r3, #4] + ldr r2, [r4, #4] + cmp r1, r2 @ boot 2nd loader if versions differ + beq boot_1st + b boot_2nd +one_is_bad: + tst r6, #1 + bne boot_1st + tst r6, #2 + bne boot_2nd +@ We are doomed, so let user know. + ldr r0, GPIO_BASE @ configure GPIO pins + ldr r1, GPIO_DIRECTION + strh r1, [r0, #0x08] +blink_loop: + mov r1, #0x08 + strh r1, [r0, #0x04] + wait r3 + mov r1, #0x10 + strh r1, [r0, #0x04] + wait r3 + b blink_loop +boot_1st: + add pc, r3, #8 +boot_2nd: + add pc, r4, #8 + +_LOADER_SIZE: + .word LOADER_SIZE - 8 @ minus size and crc32 +_LOADER1_OFFSET: + .word LOADER1_OFFSET +_LOADER2_OFFSET: + .word LOADER2_OFFSET + +FFFFFFFF: + .word 0xffffffff +CRC32_TABLE: + .word 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419 + .word 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4 + .word 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07 + .word 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de + .word 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856 + .word 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9 + .word 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4 + .word 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b + .word 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3 + .word 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a + .word 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599 + .word 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924 + .word 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190 + .word 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f + .word 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e + .word 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01 + .word 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed + .word 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950 + .word 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3 + .word 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2 + .word 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a + .word 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5 + .word 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010 + .word 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f + .word 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17 + .word 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6 + .word 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615 + .word 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8 + .word 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344 + .word 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb + .word 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a + .word 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5 + .word 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1 + .word 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c + .word 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef + .word 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236 + .word 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe + .word 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31 + .word 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c + .word 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713 + .word 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b + .word 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242 + .word 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1 + .word 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c + .word 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278 + .word 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7 + .word 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66 + .word 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9 + .word 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605 + .word 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8 + .word 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b + .word 0x2d02ef8d + +GPIO_BASE: + .word 0xfffce000 +GPIO_DIRECTION: + .word 0x0000ffe7 + +.end diff --git a/board/netstar/flash.c b/board/netstar/flash.c new file mode 100644 index 0000000000..f555c0c006 --- /dev/null +++ b/board/netstar/flash.c @@ -0,0 +1,343 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2005 + * 2N Telekomunikace, a.s. <www.2n.cz> + * Ladislav Michl <michl@2n.cz> + * + * 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 0 */ +#if (PHYS_SDRAM_1_SIZE != SZ_32M) + +#include "crcek.h" + +#if (CFG_MAX_FLASH_BANKS > 1) +#error There is always only _one_ flash chip +#endif + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + +#define CMD_READ_ARRAY 0x000000f0 +#define CMD_UNLOCK1 0x000000aa +#define CMD_UNLOCK2 0x00000055 +#define CMD_ERASE_SETUP 0x00000080 +#define CMD_ERASE_CONFIRM 0x00000030 +#define CMD_PROGRAM 0x000000a0 +#define CMD_UNLOCK_BYPASS 0x00000020 + +#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CFG_FLASH_BASE + (0x00000555 << 1))) +#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002aa << 1))) + +#define BIT_ERASE_DONE 0x00000080 +#define BIT_RDY_MASK 0x00000080 +#define BIT_PROGRAM_ERROR 0x00000020 +#define BIT_TIMEOUT 0x80000000 /* our flag */ + +/*----------------------------------------------------------------------- + */ + +ulong flash_init(void) +{ + int i; + + flash_info[0].flash_id = (AMD_MANUFACT & FLASH_VENDMASK) | + (AMD_ID_LV800B & FLASH_TYPEMASK); + flash_info[0].size = PHYS_FLASH_1_SIZE; + flash_info[0].sector_count = CFG_MAX_FLASH_SECT; + memset(flash_info[0].protect, 0, CFG_MAX_FLASH_SECT); + + for (i = 0; i < flash_info[0].sector_count; i++) { + switch (i) { + case 0: /* 16kB */ + flash_info[0].start[0] = CFG_FLASH_BASE; + break; + case 1: /* 8kB */ + flash_info[0].start[1] = CFG_FLASH_BASE + 0x4000; + break; + case 2: /* 8kB */ + flash_info[0].start[2] = CFG_FLASH_BASE + 0x4000 + + 0x2000; + break; + case 3: /* 32 KB */ + flash_info[0].start[3] = CFG_FLASH_BASE + 0x4000 + + 2 * 0x2000; + break; + case 4: + flash_info[0].start[4] = CFG_FLASH_BASE + 0x4000 + + 2 * 0x2000 + 0x8000; + break; + default: /* 64kB */ + flash_info[0].start[i] = flash_info[0].start[i-1] + + 0x10000; + break; + } + } + + /* U-Boot */ + flash_protect(FLAG_PROTECT_SET, + LOADER1_OFFSET, + LOADER1_OFFSET + LOADER_SIZE - 1, flash_info); + /* Protect crcek, env and r_env as well */ + flash_protect(FLAG_PROTECT_SET, 0, 0x8000 - 1, flash_info); + + return flash_info[0].size; +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info(flash_info_t *info) +{ + int i; + + switch (info->flash_id & FLASH_VENDMASK) { + case (AMD_MANUFACT & FLASH_VENDMASK): + puts("AMD: "); + break; + default: + puts("Unknown vendor "); + break; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case (AMD_ID_LV800B & FLASH_TYPEMASK): + puts("AM29LV800BB (8Mb)\n"); + break; + default: + puts("Unknown chip type\n"); + return; + } + + printf(" Size: %ld MB in %d sectors\n", + info->size >> 20, info->sector_count); + + puts(" Sector start addresses:"); + for (i = 0; i < info->sector_count; i++) { + if ((i % 5) == 0) + puts("\n "); + + printf(" %08lX%s", info->start[i], + info->protect[i] ? " (RO)" : " "); + } + puts("\n"); +} + +/*----------------------------------------------------------------------- + */ + +int flash_erase(flash_info_t *info, int s_first, int s_last) +{ + ushort result; + int prot, sect; + int rc = ERR_OK; + + /* first look for protection bits */ + + if (info->flash_id == FLASH_UNKNOWN) + return ERR_UNKNOWN_FLASH_TYPE; + + if ((s_first < 0) || (s_first > s_last)) + return ERR_INVAL; + + if ((info->flash_id & FLASH_VENDMASK) != + (AMD_MANUFACT & FLASH_VENDMASK)) + return ERR_UNKNOWN_FLASH_VENDOR; + + 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 + putc('\n'); + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { + if (info->protect[sect] == 0) { /* not protected */ + vu_short *addr = (vu_short *) (info->start[sect]); + + /* arm simple, non interrupt dependent timer */ + reset_timer_masked(); + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + *addr = CMD_ERASE_CONFIRM; + + /* wait until flash is ready */ + while (1) { + result = *addr; + + /* check timeout */ + if (get_timer_masked() > CFG_FLASH_ERASE_TOUT) { + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; + rc = ERR_TIMOUT; + break; + } + + if ((result & 0xfff) & BIT_ERASE_DONE) + break; + + if ((result & 0xffff) & BIT_PROGRAM_ERROR) { + rc = ERR_PROG_ERROR; + break; + } + } + + MEM_FLASH_ADDR1 = CMD_READ_ARRAY; + + if (rc != ERR_OK) + goto out; + + putc('.'); + } + } +out: + /* allow flash to settle - wait 10 ms */ + udelay_masked(10000); + + return rc; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash + */ + +volatile static int write_hword(flash_info_t *info, ulong dest, ushort data) +{ + vu_short *addr = (vu_short *) dest; + ushort result; + int rc = ERR_OK; + + /* check if flash is (sufficiently) erased */ + result = *addr; + if ((result & data) != data) + return ERR_NOT_ERASED; + + MEM_FLASH_ADDR1 = CMD_UNLOCK1; + MEM_FLASH_ADDR2 = CMD_UNLOCK2; + MEM_FLASH_ADDR1 = CMD_PROGRAM; + *addr = data; + + /* arm simple, non interrupt dependent timer */ + reset_timer_masked(); + + /* wait until flash is ready */ + while (1) { + result = *addr; + + /* check timeout */ + if (get_timer_masked () > CFG_FLASH_ERASE_TOUT) { + rc = ERR_TIMOUT; + break; + } + + if ((result & 0x80) == (data & 0x80)) + break; + + if ((result & 0xffff) & BIT_PROGRAM_ERROR) { + result = *addr; + + if ((result & 0x80) != (data & 0x80)) + rc = ERR_PROG_ERROR; + } + } + + *addr = CMD_READ_ARRAY; + + if (*addr != data) + rc = ERR_PROG_ERROR; + + return rc; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash. + */ + +int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + ulong cp, wp; + int l; + int i, rc; + ushort data; + + wp = (addr & ~1); /* 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 << 8); + for (; i < 2 && cnt > 0; ++i) { + data = (data >> 8) | (*src++ << 8); + --cnt; + ++cp; + } + for (; cnt == 0 && i < 2; ++i, ++cp) + data = (data >> 8) | (*(uchar *) cp << 8); + + if ((rc = write_hword(info, wp, data)) != 0) + return (rc); + wp += 2; + } + + /* + * handle word aligned part + */ + while (cnt >= 2) { + data = *((vu_short *) src); + if ((rc = write_hword(info, wp, data)) != 0) + return (rc); + src += 2; + wp += 2; + cnt -= 2; + } + + if (cnt == 0) + return ERR_OK; + + /* + * handle unaligned tail bytes + */ + data = 0; + for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) { + data = (data >> 8) | (*src++ << 8); + --cnt; + } + for (; i < 2; ++i, ++cp) + data = (data >> 8) | (*(uchar *) cp << 8); + + return write_hword(info, wp, data); +} + +#endif diff --git a/board/netstar/nand.c b/board/netstar/nand.c new file mode 100644 index 0000000000..e5b7f3346e --- /dev/null +++ b/board/netstar/nand.c @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2005 2N TELEKOMUNIKACE, Ladislav Michl + * + * 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 (CONFIG_COMMANDS & CFG_CMD_NAND) + +#include <nand.h> + +/* + * hardware specific access to control-lines + */ +#define MASK_CLE 0x02 +#define MASK_ALE 0x04 + +static void netstar_nand_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *this = mtd->priv; + ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; + + IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); + switch (cmd) { + case NAND_CTL_SETCLE: IO_ADDR_W |= MASK_CLE; break; + case NAND_CTL_SETALE: IO_ADDR_W |= MASK_ALE; break; + } + this->IO_ADDR_W = (void *) IO_ADDR_W; +} + +/* + * chip R/B detection + */ +static int netstar_nand_ready(struct mtd_info *mtd) +{ + return (*(volatile ushort *)GPIO_DATA_INPUT_REG) & 0x02; +} + +void board_nand_init(struct nand_chip *nand) +{ + nand->options = NAND_SAMSUNG_LP_OPTIONS; + nand->eccmode = NAND_ECC_SOFT; + nand->hwcontrol = netstar_nand_hwcontrol; +/* nand->dev_ready = netstar_nand_ready; */ + nand->chip_delay = 18; +} +#endif diff --git a/board/netstar/netstar.c b/board/netstar/netstar.c new file mode 100644 index 0000000000..62615e5c56 --- /dev/null +++ b/board/netstar/netstar.c @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2005 2N TELEKOMUNIKACE, Ladislav Michl + * + * 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> + +int board_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + /* arch number of NetStar board */ + /* TODO: use define from asm/mach-types.h */ + gd->bd->bi_arch_number = 692; + + /* adress of boot parameters */ + gd->bd->bi_boot_params = 0x10000100; + + return 0; +} + +int dram_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + + /* Take the Ethernet controller out of reset and wait + * for the EEPROM load to complete. */ + *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) |= 0x80; + udelay(10); /* doesn't work before interrupt_init call */ + *((volatile unsigned short *) GPIO_DATA_OUTPUT_REG) &= ~0x80; + udelay(500); + + return 0; +} + +extern void partition_flash(void); + +int misc_init_r(void) +{ + return 0; +} + +extern void nand_init(void); + +int board_late_init(void) +{ + return 0; +} diff --git a/board/netstar/setup.S b/board/netstar/setup.S new file mode 100644 index 0000000000..82c0342357 --- /dev/null +++ b/board/netstar/setup.S @@ -0,0 +1,287 @@ +/* + * Board specific setup info + * + * (C) Copyright 2004 Ales Jindra <jindra@2n.cz> + * (C) Copyright 2005 Ladislav Michl <michl@2n.cz> + * + * 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 <config.h> +#include <version.h> + +_TEXT_BASE: + .word TEXT_BASE /* SDRAM load addr from config.mk */ + +OMAP5910_LPG1_BASE: .word 0xfffbd000 +OMAP5910_TIPB_SWITCHES_BASE: .word 0xfffbc800 +OMAP5910_MPU_TC_BASE: .word 0xfffecc00 +OMAP5910_MPU_CLKM_BASE: .word 0xfffece00 +OMAP5910_ULPD_PWR_MNG_BASE: .word 0xfffe0800 +OMAP5910_DPLL1_BASE: .word 0xfffecf00 +OMAP5910_GPIO_BASE: .word 0xfffce000 +OMAP5910_MPU_WD_TIMER_BASE: .word 0xfffec800 +OMAP5910_MPUI_BASE: .word 0xfffec900 + +_OMAP5910_ARM_CKCTL: .word OMAP5910_ARM_CKCTL +_OMAP5910_ARM_EN_CLK: .word OMAP5910_ARM_EN_CLK + +OMAP5910_MPUI_CTRL: .word 0x0000ff1b + +VAL_EMIFS_CS0_CONFIG: .word 0x00009090 +VAL_EMIFS_CS1_CONFIG: .word 0x00003031 +VAL_EMIFS_CS2_CONFIG: .word 0x0000a0a1 +VAL_EMIFS_CS3_CONFIG: .word 0x0000c0c0 +VAL_EMIFS_DYN_WAIT: .word 0x00000000 +/* autorefresh counter 0x246 ((64000000/13.4)-400)/8192) */ + /* SLRF SD_RET ARE SDRAM_TYPE ARCV SDRAM_FREQUENCY PWD CLK */ + +#if (PHYS_SDRAM_1_SIZE == SZ_32M) +VAL_EMIFF_SDRAM_CONFIG: .word ((0 << 0) | (0 << 1) | (3 << 2) | (0xf << 4) | (0x246 << 8) | (0 << 24) | (0 << 26) | (0 << 27)) +#else +VAL_EMIFF_SDRAM_CONFIG: .word ((0 << 0) | (0 << 1) | (3 << 2) | (0xd << 4) | (0x246 << 8) | (0 << 24) | (0 << 26) | (0 << 27)) +#endif + +VAL_EMIFF_SDRAM_CONFIG2: .word 0x00000003 +VAL_EMIFF_MRS: .word 0x00000037 + +/* + * GPIO04 - Green LED (Red LED is connected to LED Pulse Generator) + * GPIO07 - LAN91C111 reset + */ +GPIO_DIRECTION: + .word 0x0000ff6f +/* + * Disable everything (green LED is connected via invertor) + */ +GPIO_OUTPUT: + .word 0x00000010 + +MUX_CONFIG_BASE: + .word 0xfffe1000 + +MUX_CONFIG_VALUES: + .align 4 + .word 0x00000000 @ FUNC_MUX_CTRL_0 + .word 0x00000000 @ FUNC_MUX_CTRL_1 + .word 0x00000000 @ FUNC_MUX_CTRL_2 + .word 0x00000000 @ FUNC_MUX_CTRL_3 + .word 0x00000000 @ FUNC_MUX_CTRL_4 + .word 0x02080480 @ FUNC_MUX_CTRL_5 + .word 0x0100001c @ FUNC_MUX_CTRL_6 + .word 0x0004800b @ FUNC_MUX_CTRL_7 + .word 0x10001200 @ FUNC_MUX_CTRL_8 + .word 0x01201012 @ FUNC_MUX_CTRL_9 + .word 0x02082248 @ FUNC_MUX_CTRL_A + .word 0x00000248 @ FUNC_MUX_CTRL_B + .word 0x12240000 @ FUNC_MUX_CTRL_C + .word 0x00002000 @ FUNC_MUX_CTRL_D + .word 0x00000000 @ PULL_DWN_CTRL_0 + .word 0x00000800 @ PULL_DWN_CTRL_1 + .word 0x01801000 @ PULL_DWN_CTRL_2 + .word 0x00000000 @ PULL_DWN_CTRL_3 + .word 0x00000000 @ GATE_INH_CTRL_0 + .word 0x00000000 @ VOLTAGE_CTRL_0 + .word 0x00000000 @ TEST_DBG_CTRL_0 + .word 0x00000006 @ MOD_CONF_CTRL_0 + .word 0x0000eaef @ COMP_MODE_CTRL_0 + +MUX_CONFIG_OFFSETS: + .align 1 + .byte 0x00 @ FUNC_MUX_CTRL_0 + .byte 0x04 @ FUNC_MUX_CTRL_1 + .byte 0x08 @ FUNC_MUX_CTRL_2 + .byte 0x10 @ FUNC_MUX_CTRL_3 + .byte 0x14 @ FUNC_MUX_CTRL_4 + .byte 0x18 @ FUNC_MUX_CTRL_5 + .byte 0x1c @ FUNC_MUX_CTRL_6 + .byte 0x20 @ FUNC_MUX_CTRL_7 + .byte 0x24 @ FUNC_MUX_CTRL_8 + .byte 0x28 @ FUNC_MUX_CTRL_9 + .byte 0x2c @ FUNC_MUX_CTRL_A + .byte 0x30 @ FUNC_MUX_CTRL_B + .byte 0x34 @ FUNC_MUX_CTRL_C + .byte 0x38 @ FUNC_MUX_CTRL_D + .byte 0x40 @ PULL_DWN_CTRL_0 + .byte 0x44 @ PULL_DWN_CTRL_1 + .byte 0x48 @ PULL_DWN_CTRL_2 + .byte 0x4c @ PULL_DWN_CTRL_3 + .byte 0x50 @ GATE_INH_CTRL_0 + .byte 0x60 @ VOLTAGE_CTRL_0 + .byte 0x70 @ TEST_DBG_CTRL_0 + .byte 0x80 @ MOD_CONF_CTRL_0 + .byte 0x0c @ COMP_MODE_CTRL_0 + .byte 0xff + +.globl platformsetup +platformsetup: + /* Improve performance a bit... */ + mrc p15, 0, r1, c0, c0, 0 @ read C15 ID register + mrc p15, 0, r1, c0, c0, 1 @ read C15 Cache information register + mrc p15, 0, r1, c1, c0, 0 @ read C15 Control register + orr r1, r1, #0x1000 @ enable I-cache, map interrupt vector 0xffff0000 + mcr p15, 0, r1, c1, c0, 0 @ write C15 Control register + mov r1, #0x00 + mcr p15, 0, r1, c7, c5, 0 @ Flush I-cache + nop + nop + nop + nop + + /* Setup clocking mode */ + ldr r0, OMAP5910_MPU_CLKM_BASE @ prepare base of CLOCK unit + ldrh r1, [r0, #0x18] @ get reset status + bic r1, r1, #(7 << 11) @ clear clock select + orr r1, r1, #(2 << 11) @ set synchronous scalable + mov r2, #0 @ set wait counter to 100 clock cycles + +icache_loop: + cmp r2, #0x01 + streqh r1, [r0, #0x18] + add r2, r2, #0x01 + cmp r2, #0x10 + bne icache_loop + nop + + /* Setup clock divisors */ + ldr r0, OMAP5910_MPU_CLKM_BASE @ base of CLOCK unit + ldr r1, _OMAP5910_ARM_CKCTL + orr r1, r1, #0x2000 @ enable DSP clock + strh r1, [r0, #0x00] @ setup clock divisors + + /* Setup DPLL to generate requested freq */ + ldr r0, OMAP5910_DPLL1_BASE @ base of DPLL1 register + mov r1, #0x0010 @ set PLL_ENABLE + orr r1, r1, #0x2000 @ set IOB to new locking + orr r1, r1, #(OMAP5910_DPLL_MUL << 7) @ setup multiplier CLKREF + orr r1, r1, #(OMAP5910_DPLL_DIV << 5) @ setup divider CLKREF + strh r1, [r0] @ write + +locking: + ldrh r1, [r0] @ get DPLL value + tst r1, #0x01 + beq locking @ while LOCK not set + + /* Enable clock */ + ldr r0, OMAP5910_MPU_CLKM_BASE @ base of CLOCK unit + mov r1, #(1 << 10) @ disable idle mode do not check + @ nWAKEUP pin, other remain active + strh r1, [r0, #0x04] + ldr r1, _OMAP5910_ARM_EN_CLK + strh r1, [r0, #0x08] + mov r1, #0x003f @ FLASH.RP not enabled in idle and + @ max delayed ( 32 x CLKIN ) + strh r1, [r0, #0x0c] + + /* Configure 5910 pins functions to match our board. */ + ldr r0, MUX_CONFIG_BASE + adr r1, MUX_CONFIG_VALUES + adr r2, MUX_CONFIG_OFFSETS +next_mux_cfg: + ldrb r3, [r2], #1 + ldr r4, [r1], #4 + cmp r3, #0xff + strne r4, [r0, r3] + bne next_mux_cfg + + /* Configure GPIO pins (also disables Green LED) */ + ldr r0, OMAP5910_GPIO_BASE + ldr r1, GPIO_OUTPUT + strh r1, [r0, #0x04] + ldr r1, GPIO_DIRECTION + strh r1, [r0, #0x08] + + /* EnablePeripherals */ + ldr r0, OMAP5910_MPU_CLKM_BASE @ CLOCK unit + mov r1, #0x0001 @ Peripheral enable + strh r1, [r0, #0x14] + + /* Program LED Pulse Generator */ + ldr r0, OMAP5910_LPG1_BASE @ 1st LED Pulse Generator + mov r1, #0x7F @ Set obscure frequency in + strb r1, [r0, #0x00] @ LCR + mov r1, #0x01 @ Enable clock (CLK_EN) in + strb r1, [r0, #0x04] @ PMR + + /* TIPB Lock UART1 */ + ldr r0, OMAP5910_TIPB_SWITCHES_BASE @ prepare base of TIPB switches + mov r1, #1 @ ARM allocated + strh r1, [r0,#0x04] @ clear IRQ line and status bits + strh r1, [r0,#0x00] + ldrh r1, [r0,#0x04] + + /* Disable watchdog */ + ldr r0, OMAP5910_MPU_WD_TIMER_BASE + mov r1, #0xf5 + strh r1, [r0, #0x8] + mov r1, #0xa0 + strh r1, [r0, #0x8] + + /* Enable MCLK */ + ldr r0, OMAP5910_ULPD_PWR_MNG_BASE + mov r1, #0x6 + strh r1, [r0, #0x34] + strh r1, [r0, #0x34] + + /* Setup clock divisors */ + ldr r0, OMAP5910_ULPD_PWR_MNG_BASE @ base of ULDPL DPLL1 register + + mov r1, #0x0010 @ set PLL_ENABLE + orr r1, r1, #0x2000 @ set IOB to new locking + strh r1, [r0] @ write + +ulocking: + ldrh r1, [r0] @ get DPLL value + tst r1, #1 + beq ulocking @ while LOCK not set + + /* EMIF init */ + ldr r0, OMAP5910_MPU_TC_BASE + ldrh r1, [r0, #0x0c] @ EMIFS_CONFIG_REG + bic r1, r1, #0x0c @ pwr down disabled, flash WP + orr r1, r1, #0x01 + str r1, [r0, #0x0c] + + ldr r1, VAL_EMIFS_CS0_CONFIG + str r1, [r0, #0x10] @ EMIFS_CS0_CONFIG + ldr r1, VAL_EMIFS_CS1_CONFIG + str r1, [r0, #0x14] @ EMIFS_CS1_CONFIG + ldr r1, VAL_EMIFS_CS2_CONFIG + str r1, [r0, #0x18] @ EMIFS_CS2_CONFIG + ldr r1, VAL_EMIFS_CS3_CONFIG + str r1, [r0, #0x1c] @ EMIFS_CS3_CONFIG + ldr r1, VAL_EMIFS_DYN_WAIT + str r1, [r0, #0x40] @ EMIFS_CFG_DYN_WAIT + + /* Setup SDRAM */ + ldr r1, VAL_EMIFF_SDRAM_CONFIG + str r1, [r0, #0x20] @ EMIFF_SDRAM_CONFIG + ldr r1, VAL_EMIFF_SDRAM_CONFIG2 + str r1, [r0, #0x3c] @ EMIFF_SDRAM_CONFIG2 + ldr r1, VAL_EMIFF_MRS + str r1, [r0, #0x24] @ EMIFF_MRS + /* SDRAM needs 100us to stabilize */ + mov r0, #0x4000 +sdelay: + subs r0, r0, #0x1 + bne sdelay + + /* back to arch calling code */ + mov pc, lr +.end diff --git a/board/netstar/u-boot.lds b/board/netstar/u-boot.lds new file mode 100644 index 0000000000..8317f72d06 --- /dev/null +++ b/board/netstar/u-boot.lds @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + cpu/arm925t/start.o (.text) + *(.text) + } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + .got : { *(.got) } + + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c index 7ab6e9ca7a..bc63f0c492 100644 --- a/common/cmd_jffs2.c +++ b/common/cmd_jffs2.c @@ -99,6 +99,10 @@ #include <cramfs/cramfs_fs.h> +#ifdef CONFIG_NEW_NAND_CODE +#include <nand.h> +#endif + /* enable/disable debugging messages */ #define DEBUG #undef DEBUG @@ -324,10 +328,9 @@ static int part_validate_nand(struct mtdids *id, struct part_info *part) { #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) /* info for NAND chips */ - extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; - struct nand_chip *nand; + nand_info_t *nand; - nand = &nand_dev_desc[id->num]; + nand = &nand_info[id->num]; if ((unsigned long)(part->offset) % nand->erasesize) { printf("%s%d: partition (%s) start offset alignment incorrect\n", @@ -422,8 +425,9 @@ static int part_del(struct mtd_device *dev, struct part_info *part) } } - +#ifndef CONFIG_NEW_NAND_CODE jffs2_free_cache(part); +#endif list_del(&part->link); free(part); dev->num_parts--; @@ -445,7 +449,9 @@ static void part_delall(struct list_head *head) list_for_each_safe(entry, n, head) { part_tmp = list_entry(entry, struct part_info, link); +#ifndef CONFIG_NEW_NAND_CODE jffs2_free_cache(part_tmp); +#endif list_del(entry); free(part_tmp); } @@ -661,6 +667,7 @@ static int device_validate(u8 type, u8 num, u32 *size) if (num < CFG_MAX_FLASH_BANKS) { extern flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; *size = flash_info[num].size; + return 0; } @@ -672,8 +679,12 @@ static int device_validate(u8 type, u8 num, u32 *size) } else if (type == MTD_DEV_TYPE_NAND) { #if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) if (num < CFG_MAX_NAND_DEVICE) { +#ifdef CONFIG_NEW_NAND_CODE + *size = nand_info[num].size; +#else extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; *size = nand_dev_desc[num].totlen; +#endif return 0; } diff --git a/common/cmd_nand.c b/common/cmd_nand.c index ae4c68ac1f..0c05255855 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -1,15 +1,18 @@ /* - * Rick Bronson and Pantelis Antoniou + * Driver for NAND support, Rick Bronson + * borrowed heavily from: + * (c) 1999 Machine Vision Holdings, Inc. + * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> + * + * Added 16-bit nand support + * (C) 2004 Texas Instruments */ #include <common.h> - -#if (CONFIG_COMMANDS & CFG_CMD_NAND) - #include <command.h> -#include <watchdog.h> #include <malloc.h> -#include <asm/byteorder.h> +#include <asm/io.h> +#include <watchdog.h> #ifdef CONFIG_SHOW_BOOT_PROGRESS # include <status_led.h> @@ -18,311 +21,290 @@ # define SHOW_BOOT_PROGRESS(arg) #endif -#include <jffs2/jffs2.h> -#include <nand.h> - -extern nand_info_t nand_info[]; /* info for NAND chips */ +#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined CONFIG_NEW_NAND_CODE -static int nand_dump_oob(nand_info_t *nand, ulong off) -{ - return 0; -} - -static int nand_dump(nand_info_t *nand, ulong off) -{ - int i; - u_char *buf, *p; - - buf = malloc(nand->oobblock + nand->oobsize); - if (!buf) { - puts("No memory for page buffer\n"); - return 1; - } - off &= ~(nand->oobblock - 1); - i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize); - if (i < 0) { - printf("Error (%d) reading page %08x\n", i, off); - free(buf); - return 1; - } - printf("Page %08x dump:\n", off); - i = nand->oobblock >> 4; p = buf; - while (i--) { - printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x" - " %02x %02x %02x %02x %02x %02x %02x %02x\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], - p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); - p += 16; - } - puts("OOB:\n"); - i = nand->oobsize >> 3; - while (i--) { - printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n", - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); - p += 8; - } - free(buf); +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ids.h> +#include <jffs2/jffs2.h> - return 0; -} +#ifdef CONFIG_OMAP1510 +void archflashwp(void *archdata, int wp); +#endif -/* ------------------------------------------------------------------------- */ +#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) -static void -arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize) -{ - *off = 0; - *size = 0; +/* + * Definition of the out of band configuration structure + */ +struct nand_oob_config { + int ecc_pos[6]; /* position of ECC bytes inside oob */ + int badblock_pos; /* position of bad block flag inside oob -1 = inactive */ + int eccvalid_pos; /* position of ECC valid flag inside oob -1 = inactive */ +} oob_config = { {0}, 0, 0}; + +#undef NAND_DEBUG +#undef PSYCHO_DEBUG + +/* ****************** WARNING ********************* + * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will + * erase (or at least attempt to erase) blocks that are marked + * bad. This can be very handy if you are _sure_ that the block + * is OK, say because you marked a good block bad to test bad + * block handling and you are done testing, or if you have + * accidentally marked blocks bad. + * + * Erasing factory marked bad blocks is a _bad_ idea. If the + * erase succeeds there is no reliable way to find them again, + * and attempting to program or erase bad blocks can affect + * the data in _other_ (good) blocks. + */ +#define ALLOW_ERASE_BAD_DEBUG 0 -#if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART) - if (argc >= 1 && strcmp(argv[0], "partition") == 0) { - int part_num; - struct part_info *part; - const char *partstr; +#define CONFIG_MTD_NAND_ECC /* enable ECC */ +#define CONFIG_MTD_NAND_ECC_JFFS2 - if (argc >= 2) - partstr = argv[1]; - else - partstr = getenv("partition"); +/* bits for nand_rw() `cmd'; or together as needed */ +#define NANDRW_READ 0x01 +#define NANDRW_WRITE 0x00 +#define NANDRW_JFFS2 0x02 +#define NANDRW_JFFS2_SKIP 0x04 - if (partstr) - part_num = (int)simple_strtoul(partstr, NULL, 10); - else - part_num = 0; - - part = jffs2_part_info(part_num); - if (part == NULL) { - printf("\nInvalid partition %d\n", part_num); - return; - } - *size = part->size; - *off = (ulong)part->offset; - } else +/* + * Function Prototypes + */ +static void nand_print(struct nand_chip *nand); +int nand_rw (struct nand_chip* nand, int cmd, + size_t start, size_t len, + size_t * retlen, u_char * buf); +int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean); +static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, + size_t * retlen, u_char *buf, u_char *ecc_code); +static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, + size_t * retlen, const u_char * buf, u_char * ecc_code); +static void nand_print_bad(struct nand_chip *nand); +static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, + size_t * retlen, u_char * buf); +static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, + size_t * retlen, const u_char * buf); +static int NanD_WaitReady(struct nand_chip *nand, int ale_wait); +#ifdef CONFIG_MTD_NAND_ECC +static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc); +static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code); #endif - { - if (argc >= 1) - *off = (ulong)simple_strtoul(argv[0], NULL, 16); - else - *off = 0; - if (argc >= 2) - *size = (ulong)simple_strtoul(argv[1], NULL, 16); - else - *size = totsize - *off; +struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE] = {{0}}; - } +/* Current NAND Device */ +static int curr_device = -1; -} +/* ------------------------------------------------------------------------- */ -int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { - int i, dev, ret; - ulong addr, off, size; - char *cmd, *s; - nand_info_t *nand; + int rcode = 0; - /* at least two arguments please */ - if (argc < 2) - goto usage; - - cmd = argv[1]; + switch (argc) { + case 0: + case 1: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 2: + if (strcmp(argv[1],"info") == 0) { + int i; - if (strcmp(cmd, "info") == 0) { + putc ('\n'); - putc('\n'); - for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { - if (nand_info[i].name) - printf("Device %d: %s\n", i, nand_info[i].name); + for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) { + if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) + continue; /* list only known devices */ + printf ("Device %d: ", i); + nand_print(&nand_dev_desc[i]); } return 0; - } - if (strcmp(cmd, "device") == 0) { - - if (argc < 3) { - if ((nand_curr_device < 0) || - (nand_curr_device >= CFG_MAX_NAND_DEVICE)) - puts("\nno devices available\n"); - else - printf("\nDevice %d: %s\n", nand_curr_device, - nand_info[nand_curr_device].name); - return 0; - } - dev = (int)simple_strtoul(argv[2], NULL, 10); - if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { - puts("No such device\n"); + } else if (strcmp(argv[1],"device") == 0) { + if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) { + puts ("\nno devices available\n"); return 1; } - printf("Device %d: %s", dev, nand_info[dev].name); - puts("... is now current device\n"); - nand_curr_device = dev; + printf ("\nDevice %d: ", curr_device); + nand_print(&nand_dev_desc[curr_device]); return 0; - } - - if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && - strncmp(cmd, "dump", 4) != 0 && - strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 -#ifdef CONFIG_MTD_NAND_UNSAFE - && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "biterr") != 0 - && strcmp(cmd, "markbad") != 0 -#endif - ) - goto usage; - - /* the following commands operate on the current device */ - if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE || - !nand_info[nand_curr_device].name) { - puts("\nno devices available\n"); - return 1; - } - nand = &nand_info[nand_curr_device]; - if (strcmp(cmd, "bad") == 0) { - printf("\nDevice %d bad blocks:\n", nand_curr_device); - for (off = 0; off < nand->size; off += nand->erasesize) - if (nand_block_isbad(nand, off)) - printf(" %08x\n", off); + } else if (strcmp(argv[1],"bad") == 0) { + if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) { + puts ("\nno devices available\n"); + return 1; + } + printf ("\nDevice %d bad blocks:\n", curr_device); + nand_print_bad(&nand_dev_desc[curr_device]); return 0; - } - - if (strcmp(cmd, "erase") == 0 -#ifdef CONFIG_MTD_NAND_UNSAFE - || strcmp(cmd, "scrub") == 0 -#endif - ) { -#ifdef CONFIG_MTD_NAND_UNSAFE - i = strcmp(cmd, "scrub") == 0; /* 1 scrub, 0 = erase */ -#endif + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 3: + if (strcmp(argv[1],"device") == 0) { + int dev = (int)simple_strtoul(argv[2], NULL, 10); - arg_off_size(argc - 2, argv + 2, &off, &size, nand->size); - if (off == 0 && size == 0) + printf ("\nDevice %d: ", dev); + if (dev >= CFG_MAX_NAND_DEVICE) { + puts ("unknown device\n"); return 1; + } + nand_print(&nand_dev_desc[dev]); + /*nand_print (dev);*/ - printf("\nNAND %s: device %d offset 0x%x, size 0x%x ", -#ifdef CONFIG_MTD_NAND_UNSAFE - i ? "scrub" : -#endif - "erase", - nand_curr_device, off, size); + if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) { + return 1; + } -#ifdef CONFIG_MTD_NAND_UNSAFE - if (i) - ret = nand_scrub(nand, off, size); - else -#endif - ret = nand_erase(nand, off, size); + curr_device = dev; - printf("%s\n", ret ? "ERROR" : "OK"); + puts ("... is now current device\n"); - return ret == 0 ? 0 : 1; + return 0; } + else if (strcmp(argv[1],"erase") == 0 && strcmp(argv[2], "clean") == 0) { + struct nand_chip* nand = &nand_dev_desc[curr_device]; + ulong off = 0; + ulong size = nand->totlen; + int ret; - if (strncmp(cmd, "dump", 4) == 0) { - if (argc < 3) - goto usage; + printf ("\nNAND erase: device %d offset %ld, size %ld ... ", + curr_device, off, size); - s = strchr(cmd, '.'); - off = (int)simple_strtoul(argv[2], NULL, 16); + ret = nand_erase (nand, off, size, 1); - if (s != NULL && strcmp(s, ".oob") == 0) - ret = nand_dump_oob(nand, off); - else - ret = nand_dump(nand, off); - - return ret == 0 ? 1 : 0; + printf("%s\n", ret ? "ERROR" : "OK"); + return ret; } - /* read write */ - if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { - if (argc < 4) - goto usage; -/* - s = strchr(cmd, '.'); - clean = CLEAN_NONE; - if (s != NULL) { - if (strcmp(s, ".jffs2") == 0 || strcmp(s, ".e") == 0 - || strcmp(s, ".i")) - clean = CLEAN_JFFS2; - } -*/ - addr = (ulong)simple_strtoul(argv[2], NULL, 16); - - arg_off_size(argc - 3, argv + 3, &off, &size, nand->size); - if (off == 0 && size == 0) + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + default: + /* at least 4 args */ + + if (strncmp(argv[1], "read", 4) == 0 || + strncmp(argv[1], "write", 5) == 0) { + ulong addr = simple_strtoul(argv[2], NULL, 16); + ulong off = simple_strtoul(argv[3], NULL, 16); + ulong size = simple_strtoul(argv[4], NULL, 16); + int cmd = (strncmp(argv[1], "read", 4) == 0) ? + NANDRW_READ : NANDRW_WRITE; + int ret, total; + char* cmdtail = strchr(argv[1], '.'); + + if (cmdtail && !strncmp(cmdtail, ".oob", 2)) { + /* read out-of-band data */ + if (cmd & NANDRW_READ) { + ret = nand_read_oob(nand_dev_desc + curr_device, + off, size, &total, + (u_char*)addr); + } + else { + ret = nand_write_oob(nand_dev_desc + curr_device, + off, size, &total, + (u_char*)addr); + } + return ret; + } + else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2)) + cmd |= NANDRW_JFFS2; /* skip bad blocks */ + else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 2)) { + cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ + if (cmd & NANDRW_READ) + cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ + } +#ifdef SXNI855T + /* need ".e" same as ".j" for compatibility with older units */ + else if (cmdtail && !strcmp(cmdtail, ".e")) + cmd |= NANDRW_JFFS2; /* skip bad blocks */ +#endif +#ifdef CFG_NAND_SKIP_BAD_DOT_I + /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */ + /* ".i" for image -> read skips bad block (no 0xff) */ + else if (cmdtail && !strcmp(cmdtail, ".i")) { + cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */ + if (cmd & NANDRW_READ) + cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */ + } +#endif /* CFG_NAND_SKIP_BAD_DOT_I */ + else if (cmdtail) { + printf ("Usage:\n%s\n", cmdtp->usage); return 1; + } - i = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ - printf("\nNAND %s: device %d offset %u, size %u ... ", - i ? "read" : "write", nand_curr_device, off, size); + printf ("\nNAND %s: device %d offset %ld, size %ld ... ", + (cmd & NANDRW_READ) ? "read" : "write", + curr_device, off, size); - if (i) - ret = nand_read(nand, off, &size, (u_char *)addr); - else - ret = nand_write(nand, off, &size, (u_char *)addr); + ret = nand_rw(nand_dev_desc + curr_device, cmd, off, size, + &total, (u_char*)addr); - printf(" %d bytes %s: %s\n", size, - i ? "read" : "written", ret ? "ERROR" : "OK"); + printf (" %d bytes %s: %s\n", total, + (cmd & NANDRW_READ) ? "read" : "written", + ret ? "ERROR" : "OK"); - return ret == 0 ? 0 : 1; - } -#ifdef CONFIG_MTD_NAND_UNSAFE - if (strcmp(cmd, "markbad") == 0 || strcmp(cmd, "biterr") == 0) { - if (argc < 3) - goto usage; + return ret; + } else if (strcmp(argv[1],"erase") == 0 && + (argc == 4 || strcmp("clean", argv[2]) == 0)) { + int clean = argc == 5; + ulong off = simple_strtoul(argv[2 + clean], NULL, 16); + ulong size = simple_strtoul(argv[3 + clean], NULL, 16); + int ret; - i = strcmp(cmd, "biterr") == 0; + printf ("\nNAND erase: device %d offset %ld, size %ld ... ", + curr_device, off, size); - off = (int)simple_strtoul(argv[2], NULL, 16); + ret = nand_erase (nand_dev_desc + curr_device, off, size, clean); - if (i) - ret = nand_make_bit_error(nand, off); - else - ret = nand_mark_bad(nand, off); + printf("%s\n", ret ? "ERROR" : "OK"); - return ret == 0 ? 0 : 1; + return ret; + } else { + printf ("Usage:\n%s\n", cmdtp->usage); + rcode = 1; } -#endif -usage: - printf("Usage:\n%s\n", cmdtp->usage); - return 1; + return rcode; + } } -U_BOOT_CMD(nand, 5, 1, do_nand, +U_BOOT_CMD( + nand, 5, 1, do_nand, "nand - NAND sub-system\n", - "info - show available NAND devices\n" - "nand device [dev] - show or set current device\n" - "nand read[.jffs2] - addr off size\n" - "nand write[.jffs2] - addr off size - read/write `size' bytes starting\n" + "info - show available NAND devices\n" + "nand device [dev] - show or set current device\n" + "nand read[.jffs2[s]] addr off size\n" + "nand write[.jffs2] addr off size - read/write `size' bytes starting\n" " at offset `off' to/from memory address `addr'\n" "nand erase [clean] [off size] - erase `size' bytes from\n" " offset `off' (entire device if not specified)\n" "nand bad - show bad blocks\n" - "nand dump[.oob] off - dump page\n" - "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" - "nand markbad off - mark bad block at offset (UNSAFE)\n" - "nand biterr off - make a bit error at offset (UNSAFE)\n"); + "nand read.oob addr off size - read out-of-band data\n" + "nand write.oob addr off size - read out-of-band data\n" +); -int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { char *boot_device = NULL; char *ep; int dev; - int r; - ulong addr, cnt, offset = 0; + ulong cnt; + ulong addr; + ulong offset = 0; image_header_t *hdr; - nand_info_t *nand; - + int rcode = 0; switch (argc) { case 1: addr = CFG_LOAD_ADDR; - boot_device = getenv("bootdevice"); + boot_device = getenv ("bootdevice"); break; case 2: addr = simple_strtoul(argv[1], NULL, 16); - boot_device = getenv("bootdevice"); + boot_device = getenv ("bootdevice"); break; case 3: addr = simple_strtoul(argv[1], NULL, 16); @@ -334,53 +316,55 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) offset = simple_strtoul(argv[3], NULL, 16); break; default: - printf("Usage:\n%s\n", cmdtp->usage); - SHOW_BOOT_PROGRESS(-1); + printf ("Usage:\n%s\n", cmdtp->usage); + SHOW_BOOT_PROGRESS (-1); return 1; } if (!boot_device) { - puts("\n** No boot device **\n"); - SHOW_BOOT_PROGRESS(-1); + puts ("\n** No boot device **\n"); + SHOW_BOOT_PROGRESS (-1); return 1; } dev = simple_strtoul(boot_device, &ep, 16); - if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { - printf("\n** Device %d not available\n", dev); - SHOW_BOOT_PROGRESS(-1); + if ((dev >= CFG_MAX_NAND_DEVICE) || + (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) { + printf ("\n** Device %d not available\n", dev); + SHOW_BOOT_PROGRESS (-1); return 1; } - nand = &nand_info[dev]; - printf("\nLoading from device %d: %s (offset 0x%lx)\n", - dev, nand->name, offset); + printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n", + dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR, + offset); - cnt = nand->oobblock; - r = nand_read(nand, offset, &cnt, (u_char *) addr); - if (r) { - printf("** Read error on %d\n", dev); - SHOW_BOOT_PROGRESS(-1); + if (nand_rw (nand_dev_desc + dev, NANDRW_READ, offset, + SECTORSIZE, NULL, (u_char *)addr)) { + printf ("** Read error on %d\n", dev); + SHOW_BOOT_PROGRESS (-1); return 1; } - hdr = (image_header_t *) addr; + hdr = (image_header_t *)addr; - if (ntohl(hdr->ih_magic) != IH_MAGIC) { - printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic); - SHOW_BOOT_PROGRESS(-1); - return 1; - } + if (ntohl(hdr->ih_magic) == IH_MAGIC) { - print_image_hdr(hdr); + print_image_hdr (hdr); - cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t)); + cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t)); + cnt -= SECTORSIZE; + } else { + printf ("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic); + SHOW_BOOT_PROGRESS (-1); + return 1; + } - r = nand_read(nand, offset, &cnt, (u_char *) addr); - if (r) { - printf("** Read error on %d\n", dev); - SHOW_BOOT_PROGRESS(-1); + if (nand_rw (nand_dev_desc + dev, NANDRW_READ, offset + SECTORSIZE, cnt, + NULL, (u_char *)(addr+SECTORSIZE))) { + printf ("** Read error on %d\n", dev); + SHOW_BOOT_PROGRESS (-1); return 1; } @@ -389,24 +373,1526 @@ int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) load_addr = addr; /* Check if we should attempt an auto-start */ - if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) { + if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) { char *local_args[2]; - extern int do_bootm(cmd_tbl_t *, int, int, char *[]); + extern int do_bootm (cmd_tbl_t *, int, int, char *[]); local_args[0] = argv[0]; local_args[1] = NULL; - printf("Automatic boot of image at addr 0x%08lx ...\n", addr); + printf ("Automatic boot of image at addr 0x%08lx ...\n", addr); + + do_bootm (cmdtp, 0, 1, local_args); + rcode = 1; + } + return rcode; +} + +U_BOOT_CMD( + nboot, 4, 1, do_nandboot, + "nboot - boot from NAND device\n", + "loadAddr dev\n" +); - do_bootm(cmdtp, 0, 1, local_args); +/* returns 0 if block containing pos is OK: + * valid erase block and + * not marked bad, or no bad mark position is specified + * returns 1 if marked bad or otherwise invalid + */ +int check_block (struct nand_chip *nand, unsigned long pos) +{ + int retlen; + uint8_t oob_data; + uint16_t oob_data16[6]; + int page0 = pos & (-nand->erasesize); + int page1 = page0 + nand->oobblock; + int badpos = oob_config.badblock_pos; + + if (pos >= nand->totlen) return 1; + + if (badpos < 0) + return 0; /* no way to check, assume OK */ + + if (nand->bus16) { + if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16) + || (oob_data16[2] & 0xff00) != 0xff00) + return 1; + if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16) + || (oob_data16[2] & 0xff00) != 0xff00) + return 1; + } else { + /* Note - bad block marker can be on first or second page */ + if (nand_read_oob(nand, page0 + badpos, 1, &retlen, &oob_data) + || oob_data != 0xff + || nand_read_oob (nand, page1 + badpos, 1, &retlen, &oob_data) + || oob_data != 0xff) + return 1; } + return 0; } -U_BOOT_CMD(nboot, 4, 1, do_nandboot, - "nboot - boot from NAND device\n", "loadAddr dev\n"); +/* print bad blocks in NAND flash */ +static void nand_print_bad(struct nand_chip* nand) +{ + unsigned long pos; + + for (pos = 0; pos < nand->totlen; pos += nand->erasesize) { + if (check_block(nand, pos)) + printf(" 0x%8.8lx\n", pos); + } + puts("\n"); +} + +/* cmd: 0: NANDRW_WRITE write, fail on bad block + * 1: NANDRW_READ read, fail on bad block + * 2: NANDRW_WRITE | NANDRW_JFFS2 write, skip bad blocks + * 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks + * 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks + */ +int nand_rw (struct nand_chip* nand, int cmd, + size_t start, size_t len, + size_t * retlen, u_char * buf) +{ + int ret = 0, n, total = 0; + char eccbuf[6]; + /* eblk (once set) is the start of the erase block containing the + * data being processed. + */ + unsigned long eblk = ~0; /* force mismatch on first pass */ + unsigned long erasesize = nand->erasesize; + + while (len) { + if ((start & (-erasesize)) != eblk) { + /* have crossed into new erase block, deal with + * it if it is sure marked bad. + */ + eblk = start & (-erasesize); /* start of block */ + if (check_block(nand, eblk)) { + if (cmd == (NANDRW_READ | NANDRW_JFFS2)) { + while (len > 0 && + start - eblk < erasesize) { + *(buf++) = 0xff; + ++start; + ++total; + --len; + } + continue; + } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) { + start += erasesize; + continue; + } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) { + /* skip bad block */ + start += erasesize; + continue; + } else { + ret = 1; + break; + } + } + } + /* The ECC will not be calculated correctly if + less than 512 is written or read */ + /* Is request at least 512 bytes AND it starts on a proper boundry */ + if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200)) + printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n"); + + if (cmd & NANDRW_READ) { + ret = nand_read_ecc(nand, start, + min(len, eblk + erasesize - start), + &n, (u_char*)buf, eccbuf); + } else { + ret = nand_write_ecc(nand, start, + min(len, eblk + erasesize - start), + &n, (u_char*)buf, eccbuf); + } + + if (ret) + break; + + start += n; + buf += n; + total += n; + len -= n; + } + if (retlen) + *retlen = total; + + return ret; +} + +static void nand_print(struct nand_chip *nand) +{ + if (nand->numchips > 1) { + printf("%s at 0x%lx,\n" + "\t %d chips %s, size %d MB, \n" + "\t total size %ld MB, sector size %ld kB\n", + nand->name, nand->IO_ADDR, nand->numchips, + nand->chips_name, 1 << (nand->chipshift - 20), + nand->totlen >> 20, nand->erasesize >> 10); + } + else { + printf("%s at 0x%lx (", nand->chips_name, nand->IO_ADDR); + print_size(nand->totlen, ", "); + print_size(nand->erasesize, " sector)\n"); + } +} + +/* ------------------------------------------------------------------------- */ + +static int NanD_WaitReady(struct nand_chip *nand, int ale_wait) +{ + /* This is inline, to optimise the common case, where it's ready instantly */ + int ret = 0; + +#ifdef NAND_NO_RB /* in config file, shorter delays currently wrap accesses */ + if(ale_wait) + NAND_WAIT_READY(nand); /* do the worst case 25us wait */ + else + udelay(10); +#else /* has functional r/b signal */ + NAND_WAIT_READY(nand); +#endif + return ret; +} + +/* NanD_Command: Send a flash command to the flash chip */ + +static inline int NanD_Command(struct nand_chip *nand, unsigned char command) +{ + unsigned long nandptr = nand->IO_ADDR; + + /* Assert the CLE (Command Latch Enable) line to the flash chip */ + NAND_CTL_SETCLE(nandptr); + + /* Send the command */ + WRITE_NAND_COMMAND(command, nandptr); + + /* Lower the CLE line */ + NAND_CTL_CLRCLE(nandptr); + +#ifdef NAND_NO_RB + if(command == NAND_CMD_RESET){ + u_char ret_val; + NanD_Command(nand, NAND_CMD_STATUS); + do { + ret_val = READ_NAND(nandptr);/* wait till ready */ + } while((ret_val & 0x40) != 0x40); + } +#endif + return NanD_WaitReady(nand, 0); +} + +/* NanD_Address: Set the current address for the flash chip */ + +static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs) +{ + unsigned long nandptr; + int i; + + nandptr = nand->IO_ADDR; + + /* Assert the ALE (Address Latch Enable) line to the flash chip */ + NAND_CTL_SETALE(nandptr); + + /* Send the address */ + /* Devices with 256-byte page are addressed as: + * Column (bits 0-7), Page (bits 8-15, 16-23, 24-31) + * there is no device on the market with page256 + * and more than 24 bits. + * Devices with 512-byte page are addressed as: + * Column (bits 0-7), Page (bits 9-16, 17-24, 25-31) + * 25-31 is sent only if the chip support it. + * bit 8 changes the read command to be sent + * (NAND_CMD_READ0 or NAND_CMD_READ1). + */ + + if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) + WRITE_NAND_ADDRESS(ofs, nandptr); + + ofs = ofs >> nand->page_shift; + + if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) { + for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) { + WRITE_NAND_ADDRESS(ofs, nandptr); + } + } + + /* Lower the ALE line */ + NAND_CTL_CLRALE(nandptr); + + /* Wait for the chip to respond */ + return NanD_WaitReady(nand, 1); +} + +/* NanD_SelectChip: Select a given flash chip within the current floor */ + +static inline int NanD_SelectChip(struct nand_chip *nand, int chip) +{ + /* Wait for it to be ready */ + return NanD_WaitReady(nand, 0); +} + +/* NanD_IdentChip: Identify a given NAND chip given {floor,chip} */ + +static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip) +{ + int mfr, id, i; + + NAND_ENABLE_CE(nand); /* set pin low */ + /* Reset the chip */ + if (NanD_Command(nand, NAND_CMD_RESET)) { +#ifdef NAND_DEBUG + printf("NanD_Command (reset) for %d,%d returned true\n", + floor, chip); +#endif + NAND_DISABLE_CE(nand); /* set pin high */ + return 0; + } + + /* Read the NAND chip ID: 1. Send ReadID command */ + if (NanD_Command(nand, NAND_CMD_READID)) { +#ifdef NAND_DEBUG + printf("NanD_Command (ReadID) for %d,%d returned true\n", + floor, chip); +#endif + NAND_DISABLE_CE(nand); /* set pin high */ + return 0; + } + + /* Read the NAND chip ID: 2. Send address byte zero */ + NanD_Address(nand, ADDR_COLUMN, 0); + + /* Read the manufacturer and device id codes from the device */ + + mfr = READ_NAND(nand->IO_ADDR); + + id = READ_NAND(nand->IO_ADDR); + + NAND_DISABLE_CE(nand); /* set pin high */ + +#ifdef NAND_DEBUG + printf("NanD_Command (ReadID) got %x %x\n", mfr, id); +#endif + if (mfr == 0xff || mfr == 0) { + /* No response - return failure */ + return 0; + } + + /* Check it's the same as the first chip we identified. + * M-Systems say that any given nand_chip device should only + * contain _one_ type of flash part, although that's not a + * hardware restriction. */ + if (nand->mfr) { + if (nand->mfr == mfr && nand->id == id) { + return 1; /* This is another the same the first */ + } else { + printf("Flash chip at floor %d, chip %d is different:\n", + floor, chip); + } + } + + /* Print and store the manufacturer and ID codes. */ + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (mfr == nand_flash_ids[i].manufacture_id && + id == nand_flash_ids[i].model_id) { +#ifdef NAND_DEBUG + printf("Flash chip found:\n\t Manufacturer ID: 0x%2.2X, " + "Chip ID: 0x%2.2X (%s)\n", mfr, id, + nand_flash_ids[i].name); +#endif + if (!nand->mfr) { + nand->mfr = mfr; + nand->id = id; + nand->chipshift = + nand_flash_ids[i].chipshift; + nand->page256 = nand_flash_ids[i].page256; + nand->eccsize = 256; + if (nand->page256) { + nand->oobblock = 256; + nand->oobsize = 8; + nand->page_shift = 8; + } else { + nand->oobblock = 512; + nand->oobsize = 16; + nand->page_shift = 9; + } + nand->pageadrlen = nand_flash_ids[i].pageadrlen; + nand->erasesize = nand_flash_ids[i].erasesize; + nand->chips_name = nand_flash_ids[i].name; + nand->bus16 = nand_flash_ids[i].bus16; + return 1; + } + return 0; + } + } + + +#ifdef NAND_DEBUG + /* We haven't fully identified the chip. Print as much as we know. */ + printf("Unknown flash chip found: %2.2X %2.2X\n", + id, mfr); +#endif + + return 0; +} + +/* NanD_ScanChips: Find all NAND chips present in a nand_chip, and identify them */ + +static void NanD_ScanChips(struct nand_chip *nand) +{ + int floor, chip; + int numchips[NAND_MAX_FLOORS]; + int maxchips = NAND_MAX_CHIPS; + int ret = 1; + + nand->numchips = 0; + nand->mfr = 0; + nand->id = 0; + + + /* For each floor, find the number of valid chips it contains */ + for (floor = 0; floor < NAND_MAX_FLOORS; floor++) { + ret = 1; + numchips[floor] = 0; + for (chip = 0; chip < maxchips && ret != 0; chip++) { + + ret = NanD_IdentChip(nand, floor, chip); + if (ret) { + numchips[floor]++; + nand->numchips++; + } + } + } + + /* If there are none at all that we recognise, bail */ + if (!nand->numchips) { +#ifdef NAND_DEBUG + puts ("No NAND flash chips recognised.\n"); +#endif + return; + } + + /* Allocate an array to hold the information for each chip */ + nand->chips = malloc(sizeof(struct Nand) * nand->numchips); + if (!nand->chips) { + puts ("No memory for allocating chip info structures\n"); + return; + } + + ret = 0; + + /* Fill out the chip array with {floor, chipno} for each + * detected chip in the device. */ + for (floor = 0; floor < NAND_MAX_FLOORS; floor++) { + for (chip = 0; chip < numchips[floor]; chip++) { + nand->chips[ret].floor = floor; + nand->chips[ret].chip = chip; + nand->chips[ret].curadr = 0; + nand->chips[ret].curmode = 0x50; + ret++; + } + } + + /* Calculate and print the total size of the device */ + nand->totlen = nand->numchips * (1 << nand->chipshift); + +#ifdef NAND_DEBUG + printf("%d flash chips found. Total nand_chip size: %ld MB\n", + nand->numchips, nand->totlen >> 20); +#endif +} + +/* we need to be fast here, 1 us per read translates to 1 second per meg */ +static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr) +{ + unsigned long nandptr = nand->IO_ADDR; + + NanD_Command (nand, NAND_CMD_READ0); + + if (nand->bus16) { + u16 val; + + while (cntr >= 16) { + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + cntr -= 16; + } + + while (cntr > 0) { + val = READ_NAND (nandptr); + *data_buf++ = val & 0xff; + *data_buf++ = val >> 8; + cntr -= 2; + } + } else { + while (cntr >= 16) { + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + *data_buf++ = READ_NAND (nandptr); + cntr -= 16; + } + + while (cntr > 0) { + *data_buf++ = READ_NAND (nandptr); + cntr--; + } + } +} + +/* + * NAND read with ECC + */ +static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, + size_t * retlen, u_char *buf, u_char *ecc_code) +{ + int col, page; + int ecc_status = 0; +#ifdef CONFIG_MTD_NAND_ECC + int j; + int ecc_failed = 0; + u_char *data_poi; + u_char ecc_calc[6]; +#endif + + /* Do not allow reads past end of device */ + if ((start + len) > nand->totlen) { + printf ("%s: Attempt read beyond end of device %x %x %x\n", + __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen); + *retlen = 0; + return -1; + } + + /* First we calculate the starting page */ + /*page = shr(start, nand->page_shift);*/ + page = start >> nand->page_shift; + + /* Get raw starting column */ + col = start & (nand->oobblock - 1); + + /* Initialize return value */ + *retlen = 0; + + /* Select the NAND device */ + NAND_ENABLE_CE(nand); /* set pin low */ + + /* Loop until all data read */ + while (*retlen < len) { + +#ifdef CONFIG_MTD_NAND_ECC + /* Do we have this page in cache ? */ + if (nand->cache_page == page) + goto readdata; + /* Send the read command */ + NanD_Command(nand, NAND_CMD_READ0); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + + /* Read in a page + oob data */ + NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize); + + /* copy data into cache, for read out of cache and if ecc fails */ + if (nand->data_cache) { + memcpy (nand->data_cache, nand->data_buf, + nand->oobblock + nand->oobsize); + } + + /* Pick the ECC bytes out of the oob data */ + for (j = 0; j < 6; j++) { + ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])]; + } + + /* Calculate the ECC and verify it */ + /* If block was not written with ECC, skip ECC */ + if (oob_config.eccvalid_pos != -1 && + (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) { + + nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]); + switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) { + case -1: + printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page); + ecc_failed++; + break; + case 1: + case 2: /* transfer ECC corrected data to cache */ + if (nand->data_cache) + memcpy (nand->data_cache, nand->data_buf, 256); + break; + } + } + + if (oob_config.eccvalid_pos != -1 && + nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) { + + nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]); + switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) { + case -1: + printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page); + ecc_failed++; + break; + case 1: + case 2: /* transfer ECC corrected data to cache */ + if (nand->data_cache) + memcpy (&nand->data_cache[256], &nand->data_buf[256], 256); + break; + } + } +readdata: + /* Read the data from ECC data buffer into return buffer */ + data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf; + data_poi += col; + if ((*retlen + (nand->oobblock - col)) >= len) { + memcpy (buf + *retlen, data_poi, len - *retlen); + *retlen = len; + } else { + memcpy (buf + *retlen, data_poi, nand->oobblock - col); + *retlen += nand->oobblock - col; + } + /* Set cache page address, invalidate, if ecc_failed */ + nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1; + + ecc_status += ecc_failed; + ecc_failed = 0; + +#else + /* Send the read command */ + NanD_Command(nand, NAND_CMD_READ0); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + + /* Read the data directly into the return buffer */ + if ((*retlen + (nand->oobblock - col)) >= len) { + NanD_ReadBuf(nand, buf + *retlen, len - *retlen); + *retlen = len; + /* We're done */ + continue; + } else { + NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col); + *retlen += nand->oobblock - col; + } +#endif + /* For subsequent reads align to page boundary. */ + col = 0; + /* Increment page address */ + page++; + } + + /* De-select the NAND device */ + NAND_DISABLE_CE(nand); /* set pin high */ + + /* + * Return success, if no ECC failures, else -EIO + * fs driver will take care of that, because + * retlen == desired len and result == -EIO + */ + return ecc_status ? -1 : 0; +} + +/* + * Nand_page_program function is used for write and writev ! + */ +static int nand_write_page (struct nand_chip *nand, + int page, int col, int last, u_char * ecc_code) +{ + + int i; + unsigned long nandptr = nand->IO_ADDR; + +#ifdef CONFIG_MTD_NAND_ECC +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE + int ecc_bytes = (nand->oobblock == 512) ? 6 : 3; +#endif +#endif + /* pad oob area */ + for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++) + nand->data_buf[i] = 0xff; + +#ifdef CONFIG_MTD_NAND_ECC + /* Zero out the ECC array */ + for (i = 0; i < 6; i++) + ecc_code[i] = 0x00; + + /* Read back previous written data, if col > 0 */ + if (col) { + NanD_Command (nand, NAND_CMD_READ0); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + + if (nand->bus16) { + u16 val; + + for (i = 0; i < col; i += 2) { + val = READ_NAND (nandptr); + nand->data_buf[i] = val & 0xff; + nand->data_buf[i + 1] = val >> 8; + } + } else { + for (i = 0; i < col; i++) + nand->data_buf[i] = READ_NAND (nandptr); + } + } + + /* Calculate and write the ECC if we have enough data */ + if ((col < nand->eccsize) && (last >= nand->eccsize)) { + nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0])); + for (i = 0; i < 3; i++) { + nand->data_buf[(nand->oobblock + + oob_config.ecc_pos[i])] = ecc_code[i]; + } + if (oob_config.eccvalid_pos != -1) { + nand->data_buf[nand->oobblock + + oob_config.eccvalid_pos] = 0xf0; + } + } + + /* Calculate and write the second ECC if we have enough data */ + if ((nand->oobblock == 512) && (last == nand->oobblock)) { + nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3])); + for (i = 3; i < 6; i++) { + nand->data_buf[(nand->oobblock + + oob_config.ecc_pos[i])] = ecc_code[i]; + } + if (oob_config.eccvalid_pos != -1) { + nand->data_buf[nand->oobblock + + oob_config.eccvalid_pos] &= 0x0f; + } + } +#endif + /* Prepad for partial page programming !!! */ + for (i = 0; i < col; i++) + nand->data_buf[i] = 0xff; + + /* Postpad for partial page programming !!! oob is already padded */ + for (i = last; i < nand->oobblock; i++) + nand->data_buf[i] = 0xff; + + /* Send command to begin auto page programming */ + NanD_Command (nand, NAND_CMD_READ0); + NanD_Command (nand, NAND_CMD_SEQIN); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + + /* Write out complete page of data */ + if (nand->bus16) { + for (i = 0; i < (nand->oobblock + nand->oobsize); i += 2) { + WRITE_NAND (nand->data_buf[i] + + (nand->data_buf[i + 1] << 8), + nand->IO_ADDR); + } + } else { + for (i = 0; i < (nand->oobblock + nand->oobsize); i++) + WRITE_NAND (nand->data_buf[i], nand->IO_ADDR); + } + + /* Send command to actually program the data */ + NanD_Command (nand, NAND_CMD_PAGEPROG); + NanD_Command (nand, NAND_CMD_STATUS); +#ifdef NAND_NO_RB + { + u_char ret_val; + + do { + ret_val = READ_NAND (nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); + } +#endif + /* See if device thinks it succeeded */ + if (READ_NAND (nand->IO_ADDR) & 0x01) { + printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, + page); + return -1; + } +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE + /* + * The NAND device assumes that it is always writing to + * a cleanly erased page. Hence, it performs its internal + * write verification only on bits that transitioned from + * 1 to 0. The device does NOT verify the whole page on a + * byte by byte basis. It is possible that the page was + * not completely erased or the page is becoming unusable + * due to wear. The read with ECC would catch the error + * later when the ECC page check fails, but we would rather + * catch it early in the page write stage. Better to write + * no data than invalid data. + */ + + /* Send command to read back the page */ + if (col < nand->eccsize) + NanD_Command (nand, NAND_CMD_READ0); + else + NanD_Command (nand, NAND_CMD_READ1); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + + /* Loop through and verify the data */ + if (nand->bus16) { + for (i = col; i < last; i = +2) { + if ((nand->data_buf[i] + + (nand->data_buf[i + 1] << 8)) != READ_NAND (nand->IO_ADDR)) { + printf ("%s: Failed write verify, page 0x%08x ", + __FUNCTION__, page); + return -1; + } + } + } else { + for (i = col; i < last; i++) { + if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) { + printf ("%s: Failed write verify, page 0x%08x ", + __FUNCTION__, page); + return -1; + } + } + } + +#ifdef CONFIG_MTD_NAND_ECC + /* + * We also want to check that the ECC bytes wrote + * correctly for the same reasons stated above. + */ + NanD_Command (nand, NAND_CMD_READOOB); + if (nand->bus16) { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + (col >> 1)); + } else { + NanD_Address (nand, ADDR_COLUMN_PAGE, + (page << nand->page_shift) + col); + } + if (nand->bus16) { + for (i = 0; i < nand->oobsize; i += 2) { + u16 val; + + val = READ_NAND (nand->IO_ADDR); + nand->data_buf[i] = val & 0xff; + nand->data_buf[i + 1] = val >> 8; + } + } else { + for (i = 0; i < nand->oobsize; i++) { + nand->data_buf[i] = READ_NAND (nand->IO_ADDR); + } + } + for (i = 0; i < ecc_bytes; i++) { + if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) { + printf ("%s: Failed ECC write " + "verify, page 0x%08x, " + "%6i bytes were succesful\n", + __FUNCTION__, page, i); + return -1; + } + } +#endif /* CONFIG_MTD_NAND_ECC */ +#endif /* CONFIG_MTD_NAND_VERIFY_WRITE */ + return 0; +} + +static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, + size_t * retlen, const u_char * buf, u_char * ecc_code) +{ + int i, page, col, cnt, ret = 0; + + /* Do not allow write past end of device */ + if ((to + len) > nand->totlen) { + printf ("%s: Attempt to write past end of page\n", __FUNCTION__); + return -1; + } + + /* Shift to get page */ + page = ((int) to) >> nand->page_shift; + + /* Get the starting column */ + col = to & (nand->oobblock - 1); + + /* Initialize return length value */ + *retlen = 0; + + /* Select the NAND device */ +#ifdef CONFIG_OMAP1510 + archflashwp(0,0); +#endif +#ifdef CFG_NAND_WP + NAND_WP_OFF(); +#endif + + NAND_ENABLE_CE(nand); /* set pin low */ + + /* Check the WP bit */ + NanD_Command(nand, NAND_CMD_STATUS); + if (!(READ_NAND(nand->IO_ADDR) & 0x80)) { + printf ("%s: Device is write protected!!!\n", __FUNCTION__); + ret = -1; + goto out; + } + + /* Loop until all data is written */ + while (*retlen < len) { + /* Invalidate cache, if we write to this page */ + if (nand->cache_page == page) + nand->cache_page = -1; + + /* Write data into buffer */ + if ((col + len) >= nand->oobblock) { + for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) { + nand->data_buf[i] = buf[(*retlen + cnt)]; + } + } else { + for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) { + nand->data_buf[i] = buf[(*retlen + cnt)]; + } + } + /* We use the same function for write and writev !) */ + ret = nand_write_page (nand, page, col, i, ecc_code); + if (ret) + goto out; + + /* Next data start at page boundary */ + col = 0; + + /* Update written bytes count */ + *retlen += cnt; + + /* Increment page address */ + page++; + } + + /* Return happy */ + *retlen = len; + +out: + /* De-select the NAND device */ + NAND_DISABLE_CE(nand); /* set pin high */ +#ifdef CONFIG_OMAP1510 + archflashwp(0,1); +#endif +#ifdef CFG_NAND_WP + NAND_WP_ON(); +#endif + + return ret; +} + +/* read from the 16 bytes of oob data that correspond to a 512 byte + * page or 2 256-byte pages. + */ +static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, + size_t * retlen, u_char * buf) +{ + int len256 = 0; + struct Nand *mychip; + int ret = 0; + + mychip = &nand->chips[ofs >> nand->chipshift]; + + /* update address for 2M x 8bit devices. OOB starts on the second */ + /* page to maintain compatibility with nand_read_ecc. */ + if (nand->page256) { + if (!(ofs & 0x8)) + ofs += 0x100; + else + ofs -= 0x8; + } + + NAND_ENABLE_CE(nand); /* set pin low */ + NanD_Command(nand, NAND_CMD_READOOB); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + ((ofs >> nand->page_shift) << nand->page_shift) + + ((ofs & (nand->oobblock - 1)) >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + } + + /* treat crossing 8-byte OOB data for 2M x 8bit devices */ + /* Note: datasheet says it should automaticaly wrap to the */ + /* next OOB block, but it didn't work here. mf. */ + if (nand->page256 && ofs + len > (ofs | 0x7) + 1) { + len256 = (ofs | 0x7) + 1 - ofs; + NanD_ReadBuf(nand, buf, len256); + + NanD_Command(nand, NAND_CMD_READOOB); + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff)); + } + + NanD_ReadBuf(nand, &buf[len256], len - len256); + + *retlen = len; + /* Reading the full OOB data drops us off of the end of the page, + * causing the flash device to go into busy mode, so we need + * to wait until ready 11.4.1 and Toshiba TC58256FT nands */ + + ret = NanD_WaitReady(nand, 1); + NAND_DISABLE_CE(nand); /* set pin high */ + + return ret; + +} + +/* write to the 16 bytes of oob data that correspond to a 512 byte + * page or 2 256-byte pages. + */ +static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, + size_t * retlen, const u_char * buf) +{ + int len256 = 0; + int i; + unsigned long nandptr = nand->IO_ADDR; + +#ifdef PSYCHO_DEBUG + printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n", + (long)ofs, len, buf[0], buf[1], buf[2], buf[3], + buf[8], buf[9], buf[14],buf[15]); +#endif + + NAND_ENABLE_CE(nand); /* set pin low to enable chip */ + + /* Reset the chip */ + NanD_Command(nand, NAND_CMD_RESET); + + /* issue the Read2 command to set the pointer to the Spare Data Area. */ + NanD_Command(nand, NAND_CMD_READOOB); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + ((ofs >> nand->page_shift) << nand->page_shift) + + ((ofs & (nand->oobblock - 1)) >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + } + + /* update address for 2M x 8bit devices. OOB starts on the second */ + /* page to maintain compatibility with nand_read_ecc. */ + if (nand->page256) { + if (!(ofs & 0x8)) + ofs += 0x100; + else + ofs -= 0x8; + } + + /* issue the Serial Data In command to initial the Page Program process */ + NanD_Command(nand, NAND_CMD_SEQIN); + if (nand->bus16) { + NanD_Address(nand, ADDR_COLUMN_PAGE, + ((ofs >> nand->page_shift) << nand->page_shift) + + ((ofs & (nand->oobblock - 1)) >> 1)); + } else { + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); + } + + /* treat crossing 8-byte OOB data for 2M x 8bit devices */ + /* Note: datasheet says it should automaticaly wrap to the */ + /* next OOB block, but it didn't work here. mf. */ + if (nand->page256 && ofs + len > (ofs | 0x7) + 1) { + len256 = (ofs | 0x7) + 1 - ofs; + for (i = 0; i < len256; i++) + WRITE_NAND(buf[i], nandptr); + + NanD_Command(nand, NAND_CMD_PAGEPROG); + NanD_Command(nand, NAND_CMD_STATUS); +#ifdef NAND_NO_RB + { u_char ret_val; + do { + ret_val = READ_NAND(nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); + } +#endif + if (READ_NAND(nandptr) & 1) { + puts ("Error programming oob data\n"); + /* There was an error */ + NAND_DISABLE_CE(nand); /* set pin high */ + *retlen = 0; + return -1; + } + NanD_Command(nand, NAND_CMD_SEQIN); + NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff)); + } + + if (nand->bus16) { + for (i = len256; i < len; i += 2) { + WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr); + } + } else { + for (i = len256; i < len; i++) + WRITE_NAND(buf[i], nandptr); + } + + NanD_Command(nand, NAND_CMD_PAGEPROG); + NanD_Command(nand, NAND_CMD_STATUS); +#ifdef NAND_NO_RB + { u_char ret_val; + do { + ret_val = READ_NAND(nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); + } +#endif + if (READ_NAND(nandptr) & 1) { + puts ("Error programming oob data\n"); + /* There was an error */ + NAND_DISABLE_CE(nand); /* set pin high */ + *retlen = 0; + return -1; + } + + NAND_DISABLE_CE(nand); /* set pin high */ + *retlen = len; + return 0; + +} + +int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean) +{ + /* This is defined as a structure so it will work on any system + * using native endian jffs2 (the default). + */ + static struct jffs2_unknown_node clean_marker = { + JFFS2_MAGIC_BITMASK, + JFFS2_NODETYPE_CLEANMARKER, + 8 /* 8 bytes in this node */ + }; + unsigned long nandptr; + struct Nand *mychip; + int ret = 0; + + if (ofs & (nand->erasesize-1) || len & (nand->erasesize-1)) { + printf ("Offset and size must be sector aligned, erasesize = %d\n", + (int) nand->erasesize); + return -1; + } + + nandptr = nand->IO_ADDR; + + /* Select the NAND device */ +#ifdef CONFIG_OMAP1510 + archflashwp(0,0); +#endif +#ifdef CFG_NAND_WP + NAND_WP_OFF(); +#endif + NAND_ENABLE_CE(nand); /* set pin low */ + + /* Check the WP bit */ + NanD_Command(nand, NAND_CMD_STATUS); + if (!(READ_NAND(nand->IO_ADDR) & 0x80)) { + printf ("nand_write_ecc: Device is write protected!!!\n"); + ret = -1; + goto out; + } + + /* Check the WP bit */ + NanD_Command(nand, NAND_CMD_STATUS); + if (!(READ_NAND(nand->IO_ADDR) & 0x80)) { + printf ("%s: Device is write protected!!!\n", __FUNCTION__); + ret = -1; + goto out; + } + + /* FIXME: Do nand in the background. Use timers or schedule_task() */ + while(len) { + /*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/ + mychip = &nand->chips[ofs >> nand->chipshift]; + + /* always check for bad block first, genuine bad blocks + * should _never_ be erased. + */ + if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) { + /* Select the NAND device */ + NAND_ENABLE_CE(nand); /* set pin low */ + + NanD_Command(nand, NAND_CMD_ERASE1); + NanD_Address(nand, ADDR_PAGE, ofs); + NanD_Command(nand, NAND_CMD_ERASE2); + + NanD_Command(nand, NAND_CMD_STATUS); + +#ifdef NAND_NO_RB + { u_char ret_val; + do { + ret_val = READ_NAND(nandptr); /* wait till ready */ + } while ((ret_val & 0x40) != 0x40); + } +#endif + if (READ_NAND(nandptr) & 1) { + printf ("%s: Error erasing at 0x%lx\n", + __FUNCTION__, (long)ofs); + /* There was an error */ + ret = -1; + goto out; + } + if (clean) { + int n; /* return value not used */ + int p, l; + + /* clean marker position and size depend + * on the page size, since 256 byte pages + * only have 8 bytes of oob data + */ + if (nand->page256) { + p = NAND_JFFS2_OOB8_FSDAPOS; + l = NAND_JFFS2_OOB8_FSDALEN; + } else { + p = NAND_JFFS2_OOB16_FSDAPOS; + l = NAND_JFFS2_OOB16_FSDALEN; + } + + ret = nand_write_oob(nand, ofs + p, l, &n, + (u_char *)&clean_marker); + /* quit here if write failed */ + if (ret) + goto out; + } + } + ofs += nand->erasesize; + len -= nand->erasesize; + } + +out: + /* De-select the NAND device */ + NAND_DISABLE_CE(nand); /* set pin high */ +#ifdef CONFIG_OMAP1510 + archflashwp(0,1); +#endif +#ifdef CFG_NAND_WP + NAND_WP_ON(); +#endif + + return ret; +} + +static inline int nandcheck(unsigned long potential, unsigned long physadr) +{ + return 0; +} + +unsigned long nand_probe(unsigned long physadr) +{ + struct nand_chip *nand = NULL; + int i = 0, ChipID = 1; + +#ifdef CONFIG_MTD_NAND_ECC_JFFS2 + oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0; + oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1; + oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2; + oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3; + oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4; + oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5; + oob_config.eccvalid_pos = 4; +#else + oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0; + oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1; + oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2; + oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3; + oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4; + oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5; + oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS; +#endif + oob_config.badblock_pos = 5; + + for (i=0; i<CFG_MAX_NAND_DEVICE; i++) { + if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) { + nand = &nand_dev_desc[i]; + break; + } + } + if (!nand) + return (0); + + memset((char *)nand, 0, sizeof(struct nand_chip)); + + nand->IO_ADDR = physadr; + nand->cache_page = -1; /* init the cache page */ + NanD_ScanChips(nand); + + if (nand->totlen == 0) { + /* no chips found, clean up and quit */ + memset((char *)nand, 0, sizeof(struct nand_chip)); + nand->ChipID = NAND_ChipID_UNKNOWN; + return (0); + } + + nand->ChipID = ChipID; + if (curr_device == -1) + curr_device = i; + + nand->data_buf = malloc (nand->oobblock + nand->oobsize); + if (!nand->data_buf) { + puts ("Cannot allocate memory for data structures.\n"); + return (0); + } + + return (nand->totlen); +} + +#ifdef CONFIG_MTD_NAND_ECC +/* + * Pre-calculated 256-way 1 byte column parity + */ +static const u_char nand_ecc_precalc_table[] = { + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, + 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, + 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, + 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, + 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, + 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, + 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, + 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, + 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, + 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, + 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, + 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, + 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 +}; + + +/* + * Creates non-inverted ECC code from line parity + */ +static void nand_trans_result(u_char reg2, u_char reg3, + u_char *ecc_code) +{ + u_char a, b, i, tmp1, tmp2; + + /* Initialize variables */ + a = b = 0x80; + tmp1 = tmp2 = 0; + + /* Calculate first ECC byte */ + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ + tmp1 |= b; + b >>= 1; + a >>= 1; + } + + /* Calculate second ECC byte */ + b = 0x80; + for (i = 0; i < 4; i++) { + if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ + tmp2 |= b; + b >>= 1; + a >>= 1; + } + + /* Store two of the ECC bytes */ + ecc_code[0] = tmp1; + ecc_code[1] = tmp2; +} + +/* + * Calculate 3 byte ECC code for 256 byte block + */ +static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code) +{ + u_char idx, reg1, reg3; + int j; + + /* Initialize variables */ + reg1 = reg3 = 0; + ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; + + /* Build up column parity */ + for(j = 0; j < 256; j++) { + + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[dat[j]]; + reg1 ^= idx; + + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (u_char) j; + } + } + + /* Create non-inverted ECC code from line parity */ + nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code); + + /* Calculate final ECC code */ + ecc_code[0] = ~ecc_code[0]; + ecc_code[1] = ~ecc_code[1]; + ecc_code[2] = ((~reg1) << 2) | 0x03; +} + +/* + * Detect and correct a 1 bit error for 256 byte block + */ +static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) +{ + u_char a, b, c, d1, d2, d3, add, bit, i; + + /* Do error detection */ + d1 = calc_ecc[0] ^ read_ecc[0]; + d2 = calc_ecc[1] ^ read_ecc[1]; + d3 = calc_ecc[2] ^ read_ecc[2]; + + if ((d1 | d2 | d3) == 0) { + /* No errors */ + return 0; + } else { + a = (d1 ^ (d1 >> 1)) & 0x55; + b = (d2 ^ (d2 >> 1)) & 0x55; + c = (d3 ^ (d3 >> 1)) & 0x54; + + /* Found and will correct single bit error in the data */ + if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { + c = 0x80; + add = 0; + a = 0x80; + for (i=0; i<4; i++) { + if (d1 & c) + add |= a; + c >>= 2; + a >>= 1; + } + c = 0x80; + for (i=0; i<4; i++) { + if (d2 & c) + add |= a; + c >>= 2; + a >>= 1; + } + bit = 0; + b = 0x04; + c = 0x80; + for (i=0; i<3; i++) { + if (d3 & c) + bit |= b; + c >>= 2; + b >>= 1; + } + b = 0x01; + a = dat[add]; + a ^= (b << bit); + dat[add] = a; + return 1; + } + else { + i = 0; + while (d1) { + if (d1 & 0x01) + ++i; + d1 >>= 1; + } + while (d2) { + if (d2 & 0x01) + ++i; + d2 >>= 1; + } + while (d3) { + if (d3 & 0x01) + ++i; + d3 >>= 1; + } + if (i == 1) { + /* ECC Code Error Correction */ + read_ecc[0] = calc_ecc[0]; + read_ecc[1] = calc_ecc[1]; + read_ecc[2] = calc_ecc[2]; + return 2; + } + else { + /* Uncorrectable Error */ + return -1; + } + } + } + + /* Should never happen */ + return -1; +} + +#endif + +#ifdef CONFIG_JFFS2_NAND + +int read_jffs2_nand(size_t start, size_t len, + size_t * retlen, u_char * buf, int nanddev) +{ + return nand_rw(nand_dev_desc + nanddev, NANDRW_READ | NANDRW_JFFS2, + start, len, retlen, buf); +} +#endif /* CONFIG_JFFS2_NAND */ -#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */ +#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */ diff --git a/common/cmd_nand_new.c b/common/cmd_nand_new.c new file mode 100644 index 0000000000..3ff2ebaf60 --- /dev/null +++ b/common/cmd_nand_new.c @@ -0,0 +1,364 @@ +#include <common.h> + +#if (CONFIG_COMMANDS & CFG_CMD_NAND) && defined CONFIG_NEW_NAND_CODE + +#include <command.h> +#include <watchdog.h> +#include <malloc.h> +#include <asm/byteorder.h> + +#ifdef CONFIG_SHOW_BOOT_PROGRESS +# include <status_led.h> +# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg) +#else +# define SHOW_BOOT_PROGRESS(arg) +#endif + +#include <jffs2/jffs2.h> +#include <nand.h> + +extern nand_info_t nand_info[]; /* info for NAND chips */ + +static int nand_dump_oob(nand_info_t *nand, ulong off) +{ + return 0; +} + +static int nand_dump(nand_info_t *nand, ulong off) +{ + int i; + u_char *buf, *p; + + buf = malloc(nand->oobblock + nand->oobsize); + if (!buf) { + puts("No memory for page buffer\n"); + return 1; + } + off &= ~(nand->oobblock - 1); + i = nand_read_raw(nand, buf, off, nand->oobblock, nand->oobsize); + if (i < 0) { + printf("Error (%d) reading page %08x\n", i, off); + free(buf); + return 1; + } + printf("Page %08x dump:\n", off); + i = nand->oobblock >> 4; p = buf; + while (i--) { + printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x" + " %02x %02x %02x %02x %02x %02x %02x %02x\n", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); + p += 16; + } + puts("OOB:\n"); + i = nand->oobsize >> 3; + while (i--) { + printf( "\t%02x %02x %02x %02x %02x %02x %02x %02x\n", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + p += 8; + } + free(buf); + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void +arg_off_size(int argc, char *argv[], ulong *off, ulong *size, ulong totsize) +{ + *off = 0; + *size = 0; + +#if defined(CONFIG_JFFS2_NAND) && defined(CFG_JFFS_CUSTOM_PART) + if (argc >= 1 && strcmp(argv[0], "partition") == 0) { + int part_num; + struct part_info *part; + const char *partstr; + + if (argc >= 2) + partstr = argv[1]; + else + partstr = getenv("partition"); + + if (partstr) + part_num = (int)simple_strtoul(partstr, NULL, 10); + else + part_num = 0; + + part = jffs2_part_info(part_num); + if (part == NULL) { + printf("\nInvalid partition %d\n", part_num); + return; + } + *size = part->size; + *off = (ulong)part->offset; + } else +#endif + { + if (argc >= 1) + *off = (ulong)simple_strtoul(argv[0], NULL, 16); + else + *off = 0; + + if (argc >= 2) + *size = (ulong)simple_strtoul(argv[1], NULL, 16); + else + *size = totsize - *off; + + } + +} + +int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int i, dev, ret; + ulong addr, off, size; + char *cmd, *s; + nand_info_t *nand; + + /* at least two arguments please */ + if (argc < 2) + goto usage; + + cmd = argv[1]; + + if (strcmp(cmd, "info") == 0) { + + putc('\n'); + for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { + if (nand_info[i].name) + printf("Device %d: %s\n", i, nand_info[i].name); + } + return 0; + } + + if (strcmp(cmd, "device") == 0) { + + if (argc < 3) { + if ((nand_curr_device < 0) || + (nand_curr_device >= CFG_MAX_NAND_DEVICE)) + puts("\nno devices available\n"); + else + printf("\nDevice %d: %s\n", nand_curr_device, + nand_info[nand_curr_device].name); + return 0; + } + dev = (int)simple_strtoul(argv[2], NULL, 10); + if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { + puts("No such device\n"); + return 1; + } + printf("Device %d: %s", dev, nand_info[dev].name); + puts("... is now current device\n"); + nand_curr_device = dev; + return 0; + } + + if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && + strncmp(cmd, "dump", 4) != 0 && + strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0) + goto usage; + + /* the following commands operate on the current device */ + if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE || + !nand_info[nand_curr_device].name) { + puts("\nno devices available\n"); + return 1; + } + nand = &nand_info[nand_curr_device]; + + if (strcmp(cmd, "bad") == 0) { + printf("\nDevice %d bad blocks:\n", nand_curr_device); + for (off = 0; off < nand->size; off += nand->erasesize) + if (nand_block_isbad(nand, off)) + printf(" %08x\n", off); + return 0; + } + + if (strcmp(cmd, "erase") == 0) { + arg_off_size(argc - 2, argv + 2, &off, &size, nand->size); + if (off == 0 && size == 0) + return 1; + + printf("\nNAND erase: device %d offset 0x%x, size 0x%x ", + nand_curr_device, off, size); + ret = nand_erase(nand, off, size); + printf("%s\n", ret ? "ERROR" : "OK"); + + return ret == 0 ? 0 : 1; + } + + if (strncmp(cmd, "dump", 4) == 0) { + if (argc < 3) + goto usage; + + s = strchr(cmd, '.'); + off = (int)simple_strtoul(argv[2], NULL, 16); + + if (s != NULL && strcmp(s, ".oob") == 0) + ret = nand_dump_oob(nand, off); + else + ret = nand_dump(nand, off); + + return ret == 0 ? 1 : 0; + + } + + /* read write */ + if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { + if (argc < 4) + goto usage; +/* + s = strchr(cmd, '.'); + clean = CLEAN_NONE; + if (s != NULL) { + if (strcmp(s, ".jffs2") == 0 || strcmp(s, ".e") == 0 + || strcmp(s, ".i")) + clean = CLEAN_JFFS2; + } +*/ + addr = (ulong)simple_strtoul(argv[2], NULL, 16); + + arg_off_size(argc - 3, argv + 3, &off, &size, nand->size); + if (off == 0 && size == 0) + return 1; + + i = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ + printf("\nNAND %s: device %d offset %u, size %u ... ", + i ? "read" : "write", nand_curr_device, off, size); + + if (i) + ret = nand_read(nand, off, &size, (u_char *)addr); + else + ret = nand_write(nand, off, &size, (u_char *)addr); + + printf(" %d bytes %s: %s\n", size, + i ? "read" : "written", ret ? "ERROR" : "OK"); + + return ret == 0 ? 0 : 1; + } +usage: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +U_BOOT_CMD(nand, 5, 1, do_nand, + "nand - NAND sub-system\n", + "info - show available NAND devices\n" + "nand device [dev] - show or set current device\n" + "nand read[.jffs2] - addr off size\n" + "nand write[.jffs2] - addr off size - read/write `size' bytes starting\n" + " at offset `off' to/from memory address `addr'\n" + "nand erase [clean] [off size] - erase `size' bytes from\n" + " offset `off' (entire device if not specified)\n" + "nand bad - show bad blocks\n" + "nand dump[.oob] off - dump page\n" + "nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n" + "nand markbad off - mark bad block at offset (UNSAFE)\n" + "nand biterr off - make a bit error at offset (UNSAFE)\n"); + +int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + char *boot_device = NULL; + char *ep; + int dev; + int r; + ulong addr, cnt, offset = 0; + image_header_t *hdr; + nand_info_t *nand; + + switch (argc) { + case 1: + addr = CFG_LOAD_ADDR; + boot_device = getenv("bootdevice"); + break; + case 2: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = getenv("bootdevice"); + break; + case 3: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = argv[2]; + break; + case 4: + addr = simple_strtoul(argv[1], NULL, 16); + boot_device = argv[2]; + offset = simple_strtoul(argv[3], NULL, 16); + break; + default: + printf("Usage:\n%s\n", cmdtp->usage); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + if (!boot_device) { + puts("\n** No boot device **\n"); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + dev = simple_strtoul(boot_device, &ep, 16); + + if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { + printf("\n** Device %d not available\n", dev); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + nand = &nand_info[dev]; + printf("\nLoading from device %d: %s (offset 0x%lx)\n", + dev, nand->name, offset); + + cnt = nand->oobblock; + r = nand_read(nand, offset, &cnt, (u_char *) addr); + if (r) { + printf("** Read error on %d\n", dev); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + hdr = (image_header_t *) addr; + + if (ntohl(hdr->ih_magic) != IH_MAGIC) { + printf("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + print_image_hdr(hdr); + + cnt = (ntohl(hdr->ih_size) + sizeof (image_header_t)); + + r = nand_read(nand, offset, &cnt, (u_char *) addr); + if (r) { + printf("** Read error on %d\n", dev); + SHOW_BOOT_PROGRESS(-1); + return 1; + } + + /* Loading ok, update default load address */ + + load_addr = addr; + + /* Check if we should attempt an auto-start */ + if (((ep = getenv("autostart")) != NULL) && (strcmp(ep, "yes") == 0)) { + char *local_args[2]; + extern int do_bootm(cmd_tbl_t *, int, int, char *[]); + + local_args[0] = argv[0]; + local_args[1] = NULL; + + printf("Automatic boot of image at addr 0x%08lx ...\n", addr); + + do_bootm(cmdtp, 0, 1, local_args); + return 1; + } + return 0; +} + +U_BOOT_CMD(nboot, 4, 1, do_nandboot, + "nboot - boot from NAND device\n", "loadAddr dev\n"); + + +#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */ diff --git a/cpu/arm925t/config.mk b/cpu/arm925t/config.mk index cef7d26f1c..960df4c989 100644 --- a/cpu/arm925t/config.mk +++ b/cpu/arm925t/config.mk @@ -22,6 +22,6 @@ # PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ - -mshort-load-bytes -msoft-float + -msoft-float PLATFORM_CPPFLAGS += -mapcs-32 -march=armv4 diff --git a/drivers/nand/Makefile b/drivers/nand/Makefile index 3906bf951d..96f67dfca8 100644 --- a/drivers/nand/Makefile +++ b/drivers/nand/Makefile @@ -14,4 +14,3 @@ $(LIB): $(OBJS) $(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@ sinclude .depend - diff --git a/drivers/nand/diskonchip.c b/drivers/nand/diskonchip.c index 02135c3ac2..b421d4c1c3 100644 --- a/drivers/nand/diskonchip.c +++ b/drivers/nand/diskonchip.c @@ -1,4 +1,4 @@ -/* +/* * drivers/mtd/nand/diskonchip.c * * (C) 2003 Red Hat, Inc. @@ -8,12 +8,12 @@ * Author: David Woodhouse <dwmw2@infradead.org> * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org> * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee> - * + * * Error correction code lifted from the old docecc code - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de> - * + * * Interface to generic NAND code for M-Systems DiskOnChip devices * * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $ @@ -42,25 +42,25 @@ static unsigned long __initdata doc_locations[] = { #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) #ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH - 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, + 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, - 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, - 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, + 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, + 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, #else /* CONFIG_MTD_DOCPROBE_HIGH */ - 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000, 0xd4000, 0xd6000, - 0xd8000, 0xda000, 0xdc000, 0xde000, - 0xe0000, 0xe2000, 0xe4000, 0xe6000, + 0xd8000, 0xda000, 0xdc000, 0xde000, + 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ #elif defined(__PPC__) 0xe4000000, #elif defined(CONFIG_MOMENCO_OCELOT) 0x2f000000, - 0xff000000, + 0xff000000, #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) - 0xff000000, + 0xff000000, ##else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif @@ -142,7 +142,7 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe /* the Reed Solomon control structure */ static struct rs_control *rs_decoder; -/* +/* * The HW decoder in the DoC ASIC's provides us a error syndrome, * which we must convert to a standard syndrom usable by the generic * Reed-Solomon library code. @@ -167,8 +167,8 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) /* Initialize the syndrom buffer */ for (i = 0; i < NROOTS; i++) s[i] = ds[0]; - /* - * Evaluate + /* + * Evaluate * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] * where x = alpha^(FCR + i) */ @@ -192,7 +192,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) if (nerr < 0) return nerr; - /* + /* * Correct the errors. The bitpositions are a bit of magic, * but they are given by the design of the de/encoder circuit * in the DoC ASIC's. @@ -209,7 +209,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) can be modified since pos is even */ index = (pos >> 3) ^ 1; bitpos = pos & 7; - if ((index >= 0 && index < SECTOR_SIZE) || + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { val = (uint8_t) (errval[i] >> (2 + bitpos)); parity ^= val; @@ -220,7 +220,7 @@ static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) bitpos = (bitpos + 10) & 7; if (bitpos == 0) bitpos = 8; - if ((index >= 0 && index < SECTOR_SIZE) || + if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) { val = (uint8_t)(errval[i] << (8 - bitpos)); parity ^= val; @@ -237,7 +237,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) { volatile char dummy; int i; - + for (i = 0; i < cycles; i++) { if (DoC_is_Millennium(doc)) dummy = ReadDOC(doc->virtadr, NOP); @@ -246,7 +246,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) else dummy = ReadDOC(doc->virtadr, DOCStatus); } - + } #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) @@ -254,7 +254,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ static int _DoC_WaitReady(struct doc_priv *doc) { - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; unsigned long timeo = jiffies + (HZ * 10); if(debug) printk("_DoC_WaitReady...\n"); @@ -284,7 +284,7 @@ static int _DoC_WaitReady(struct doc_priv *doc) static inline int DoC_WaitReady(struct doc_priv *doc) { - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int ret = 0; if (DoC_is_MillenniumPlus(doc)) { @@ -310,7 +310,7 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; if(debug)printk("write_byte %02x\n", datum); WriteDOC(datum, docptr, CDSNSlowIO); @@ -321,7 +321,7 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; u_char ret; ReadDOC(docptr, CDSNSlowIO); @@ -331,12 +331,12 @@ static u_char doc2000_read_byte(struct mtd_info *mtd) return ret; } -static void doc2000_writebuf(struct mtd_info *mtd, +static void doc2000_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("writebuf of %d bytes: ", len); for (i=0; i < len; i++) { @@ -347,12 +347,12 @@ static void doc2000_writebuf(struct mtd_info *mtd, if (debug) printk("\n"); } -static void doc2000_readbuf(struct mtd_info *mtd, +static void doc2000_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("readbuf of %d bytes: ", len); @@ -362,12 +362,12 @@ static void doc2000_readbuf(struct mtd_info *mtd, } } -static void doc2000_readbuf_dword(struct mtd_info *mtd, +static void doc2000_readbuf_dword(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug) printk("readbuf_dword of %d bytes: ", len); @@ -383,12 +383,12 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd, } } -static int doc2000_verifybuf(struct mtd_info *mtd, +static int doc2000_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; for (i=0; i < len; i++) @@ -435,7 +435,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) this->read_buf = &doc2000_readbuf_dword; } } - + return ret; } @@ -466,7 +466,7 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) struct doc_priv *doc = this->priv; int status; - + DoC_WaitReady(doc); this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); DoC_WaitReady(doc); @@ -479,7 +479,7 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; WriteDOC(datum, docptr, CDSNSlowIO); WriteDOC(datum, docptr, Mil_CDSN_IO); @@ -490,22 +490,22 @@ static u_char doc2001_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; - //ReadDOC(docptr, CDSNSlowIO); + /*ReadDOC(docptr, CDSNSlowIO); */ /* 11.4.5 -- delay twice to allow extended length cycle */ DoC_Delay(doc, 2); ReadDOC(docptr, ReadPipeInit); - //return ReadDOC(docptr, Mil_CDSN_IO); + /*return ReadDOC(docptr, Mil_CDSN_IO); */ return ReadDOC(docptr, LastDataRead); } -static void doc2001_writebuf(struct mtd_info *mtd, +static void doc2001_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; for (i=0; i < len; i++) @@ -514,12 +514,12 @@ static void doc2001_writebuf(struct mtd_info *mtd, WriteDOC(0x00, docptr, WritePipeTerm); } -static void doc2001_readbuf(struct mtd_info *mtd, +static void doc2001_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; /* Start read pipeline */ @@ -532,12 +532,12 @@ static void doc2001_readbuf(struct mtd_info *mtd, buf[i] = ReadDOC(docptr, LastDataRead); } -static int doc2001_verifybuf(struct mtd_info *mtd, +static int doc2001_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; /* Start read pipeline */ @@ -557,22 +557,22 @@ static u_char doc2001plus_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; u_char ret; - ReadDOC(docptr, Mplus_ReadPipeInit); - ReadDOC(docptr, Mplus_ReadPipeInit); - ret = ReadDOC(docptr, Mplus_LastDataRead); + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + ret = ReadDOC(docptr, Mplus_LastDataRead); if (debug) printk("read_byte returns %02x\n", ret); return ret; } -static void doc2001plus_writebuf(struct mtd_info *mtd, +static void doc2001plus_writebuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("writebuf of %d bytes: ", len); @@ -584,12 +584,12 @@ static void doc2001plus_writebuf(struct mtd_info *mtd, if (debug) printk("\n"); } -static void doc2001plus_readbuf(struct mtd_info *mtd, +static void doc2001plus_readbuf(struct mtd_info *mtd, u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("readbuf of %d bytes: ", len); @@ -614,12 +614,12 @@ static void doc2001plus_readbuf(struct mtd_info *mtd, if (debug) printk("\n"); } -static int doc2001plus_verifybuf(struct mtd_info *mtd, +static int doc2001plus_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; if (debug)printk("verifybuf of %d bytes: ", len); @@ -645,7 +645,7 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int floor = 0; if(debug)printk("select chip (%d)\n", chip); @@ -671,7 +671,7 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int floor = 0; if(debug)printk("select chip (%d)\n", chip); @@ -698,7 +698,7 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; switch(cmd) { case NAND_CTL_SETNCE: @@ -736,7 +736,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* * Must terminate write pipeline before sending any commands @@ -794,7 +794,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col WriteDOC(0, docptr, Mplus_FlashControl); } - /* + /* * program and erase have their own busy handlers * status and sequential in needs no delay */ @@ -819,7 +819,7 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ @@ -840,7 +840,7 @@ static int doc200x_dev_ready(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; if (DoC_is_MillenniumPlus(doc)) { /* 11.4.2 -- must NOP four times before checking FR/B# */ @@ -878,7 +878,7 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* Prime the ECC engine */ switch(mode) { @@ -897,7 +897,7 @@ static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; /* Prime the ECC engine */ switch(mode) { @@ -918,7 +918,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, { struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; int i; int emptymatch = 1; @@ -942,7 +942,7 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, for (i = 0; i < 6; i++) { if (DoC_is_MillenniumPlus(doc)) ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); - else + else ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); if (ecc_code[i] != empty_write_ecc[i]) emptymatch = 0; @@ -976,10 +976,10 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ int i, ret = 0; struct nand_chip *this = mtd->priv; struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; + void __iomem *docptr = doc->virtadr; volatile u_char dummy; int emptymatch = 1; - + /* flush the pipeline */ if (DoC_is_2000(doc)) { dummy = ReadDOC(docptr, 2k_ECCStatus); @@ -994,7 +994,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf); } - + /* Error occured ? */ if (dummy & 0x80) { for (i = 0; i < 6; i++) { @@ -1032,7 +1032,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); if (ret > 0) printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); - } + } if (DoC_is_MillenniumPlus(doc)) WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else @@ -1043,16 +1043,16 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ } return ret; } - -//u_char mydatabuf[528]; + +/*u_char mydatabuf[528]; */ static struct nand_oobinfo doc200x_oobinfo = { - .useecc = MTD_NANDECC_AUTOPLACE, - .eccbytes = 6, - .eccpos = {0, 1, 2, 3, 4, 5}, - .oobfree = { {8, 8} } + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 6, + .eccpos = {0, 1, 2, 3, 4, 5}, + .oobfree = { {8, 8} } }; - + /* Find the (I)NFTL Media Header, and optionally also the mirror media header. On sucessful return, buf will contain a copy of the media header for further processing. id is the string to scan for, and will presumably be @@ -1068,7 +1068,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, int ret; size_t retlen; - end = min(end, mtd->size); // paranoia + end = min(end, mtd->size); /* paranoia */ for (offs = 0; offs < end; offs += mtd->erasesize) { ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); if (retlen != mtd->oobblock) continue; @@ -1122,8 +1122,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; mh = (struct NFTLMediaHeader *) buf; -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) +/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ +/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ printk(KERN_INFO " DataOrgID = %s\n" " NumEraseUnits = %d\n" " FirstPhysicalEUN = %d\n" @@ -1132,7 +1132,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, mh->DataOrgID, mh->NumEraseUnits, mh->FirstPhysicalEUN, mh->FormattedSize, mh->UnitSizeFactor); -//#endif +/*#endif */ blocks = mtd->size >> this->phys_erase_shift; maxblocks = min(32768U, mtd->erasesize - psize); @@ -1175,9 +1175,9 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, offs <<= this->page_shift; offs += mtd->erasesize; - //parts[0].name = " DiskOnChip Boot / Media Header partition"; - //parts[0].offset = 0; - //parts[0].size = offs; + /*parts[0].name = " DiskOnChip Boot / Media Header partition"; */ + /*parts[0].offset = 0; */ + /*parts[0].size = offs; */ parts[0].name = " DiskOnChip BDTL partition"; parts[0].offset = offs; @@ -1232,9 +1232,9 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed); - -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) + +/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ +/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ printk(KERN_INFO " bootRecordID = %s\n" " NoOfBootImageBlocks = %d\n" " NoOfBinaryPartitions = %d\n" @@ -1252,7 +1252,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, ((unsigned char *) &mh->OsakVersion)[2] & 0xf, ((unsigned char *) &mh->OsakVersion)[3] & 0xf, mh->PercentUsed); -//#endif +/*#endif */ vshift = this->phys_erase_shift + mh->BlockMultiplierBits; @@ -1278,8 +1278,8 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, ip->spareUnits = le32_to_cpu(ip->spareUnits); ip->Reserved0 = le32_to_cpu(ip->Reserved0); -//#ifdef CONFIG_MTD_DEBUG_VERBOSE -// if (CONFIG_MTD_DEBUG_VERBOSE >= 2) +/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ +/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ printk(KERN_INFO " PARTITION[%d] ->\n" " virtualUnits = %d\n" " firstUnit = %d\n" @@ -1289,7 +1289,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, i, ip->virtualUnits, ip->firstUnit, ip->lastUnit, ip->flags, ip->spareUnits); -//#endif +/*#endif */ /* if ((i == 0) && (ip->firstUnit > 0)) { @@ -1456,7 +1456,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd) ReadDOC(doc->virtadr, ChipID); if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { /* It's not a Millennium; it's one of the newer - DiskOnChip 2000 units with a similar ASIC. + DiskOnChip 2000 units with a similar ASIC. Treat it like a Millennium, except that it can have multiple chips. */ doc2000_count_chips(mtd); @@ -1518,20 +1518,20 @@ static inline int __init doc_probe(unsigned long physadr) * to the DOCControl register. So we store the current contents * of the DOCControl register's location, in case we later decide * that it's not a DiskOnChip, and want to put it back how we - * found it. + * found it. */ save_control = ReadDOC(virtadr, DOCControl); /* Reset the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl); /* Enable the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl); ChipID = ReadDOC(virtadr, ChipID); @@ -1614,11 +1614,11 @@ static inline int __init doc_probe(unsigned long physadr) if (ChipID == DOC_ChipID_DocMilPlus16) { WriteDOC(~newval, virtadr, Mplus_AliasResolution); oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); - WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it + WriteDOC(newval, virtadr, Mplus_AliasResolution); /* restore it */ } else { WriteDOC(~newval, virtadr, AliasResolution); oldval = ReadDOC(doc->virtadr, AliasResolution); - WriteDOC(newval, virtadr, AliasResolution); // restore it + WriteDOC(newval, virtadr, AliasResolution); /* restore it */ } newval = ~newval; if (oldval == newval) { @@ -1726,7 +1726,7 @@ static int __init init_nanddoc(void) int i, ret = 0; /* We could create the decoder on demand, if memory is a concern. - * This way we have it handy, if an error happens + * This way we have it handy, if an error happens * * Symbolsize is 10 (bits) * Primitve polynomial is x^10+x^3+1 diff --git a/drivers/nand/nand_base.c b/drivers/nand/nand_base.c index c423512f18..a7ab8c27ad 100644 --- a/drivers/nand/nand_base.c +++ b/drivers/nand/nand_base.c @@ -5,14 +5,14 @@ * This is the generic MTD driver for NAND flash devices. It should be * capable of working with almost all NAND chips currently available. * Basic support for AG-AND chips is provided. - * + * * Additional technical information is available on * http://www.linux-mtd.infradead.org/tech/nand.html - * + * * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * 2002 Thomas Gleixner (tglx@linutronix.de) * - * 02-08-2004 tglx: support for strange chips, which cannot auto increment + * 02-08-2004 tglx: support for strange chips, which cannot auto increment * pages on read / read_oob * * 03-17-2004 tglx: Check ready before auto increment check. Simon Bayes @@ -21,7 +21,7 @@ * Make reads over block boundaries work too * * 04-14-2004 tglx: first working version for 2k page size chips - * + * * 05-19-2004 tglx: Basic support for Renesas AG-AND chips * * 09-24-2004 tglx: add support for hardware controllers (e.g. ECC) shared @@ -29,8 +29,8 @@ * from Ben Dooks <ben-mtd@fluff.org> * * Credits: - * David Woodhouse for adding multichip support - * + * David Woodhouse for adding multichip support + * * Aleph One Ltd. and Toby Churchill Ltd. for supporting the * rework for 2K page size chips * @@ -68,7 +68,7 @@ #include <linux/mtd/partitions.h> #endif -#else +#endif #include <common.h> @@ -88,8 +88,6 @@ #include <jffs2/jffs2.h> #endif -#endif - /* Define default oob placement schemes for large and small page devices */ static struct nand_oobinfo nand_oob_8 = { .useecc = MTD_NANDECC_AUTOPLACE, @@ -109,8 +107,8 @@ static struct nand_oobinfo nand_oob_64 = { .useecc = MTD_NANDECC_AUTOPLACE, .eccbytes = 24, .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, .oobfree = { {2, 38} } }; @@ -156,19 +154,19 @@ static void nand_sync (struct mtd_info *mtd); static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int mode); #ifdef CONFIG_MTD_NAND_VERIFY_WRITE -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode); #else #define nand_verify_pages(...) (0) #endif - + static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state); /** * nand_release_device - [GENERIC] release chip * @mtd: MTD device structure - * - * Deselect, release chip lock and wake up anyone waiting on the device + * + * Deselect, release chip lock and wake up anyone waiting on the device */ /* XXX U-BOOT XXX */ #if 0 @@ -223,7 +221,7 @@ static void nand_write_byte(struct mtd_info *mtd, u_char byte) * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith with + * Default read function for 16bit buswith with * endianess conversion */ static u_char nand_read_byte16(struct mtd_info *mtd) @@ -250,7 +248,7 @@ static void nand_write_byte16(struct mtd_info *mtd, u_char byte) * nand_read_word - [DEFAULT] read one word from the chip * @mtd: MTD device structure * - * Default read function for 16bit buswith without + * Default read function for 16bit buswith without * endianess conversion */ static u16 nand_read_word(struct mtd_info *mtd) @@ -264,7 +262,7 @@ static u16 nand_read_word(struct mtd_info *mtd) * @mtd: MTD device structure * @word: data word to write * - * Default write function for 16bit buswith without + * Default write function for 16bit buswith without * endianess conversion */ static void nand_write_word(struct mtd_info *mtd, u16 word) @@ -285,7 +283,7 @@ static void nand_select_chip(struct mtd_info *mtd, int chip) struct nand_chip *this = mtd->priv; switch(chip) { case -1: - this->hwcontrol(mtd, NAND_CTL_CLRNCE); + this->hwcontrol(mtd, NAND_CTL_CLRNCE); break; case 0: this->hwcontrol(mtd, NAND_CTL_SETNCE); @@ -314,7 +312,7 @@ static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) } /** - * nand_read_buf - [DEFAULT] read chip data into buffer + * nand_read_buf - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -331,7 +329,7 @@ static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf - [DEFAULT] Verify chip data against buffer + * nand_verify_buf - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -364,14 +362,14 @@ static void nand_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) struct nand_chip *this = mtd->priv; u16 *p = (u16 *) buf; len >>= 1; - + for (i=0; i<len; i++) writew(p[i], this->IO_ADDR_W); - + } /** - * nand_read_buf16 - [DEFAULT] read chip data into buffer + * nand_read_buf16 - [DEFAULT] read chip data into buffer * @mtd: MTD device structure * @buf: buffer to store date * @len: number of bytes to read @@ -390,7 +388,7 @@ static void nand_read_buf16(struct mtd_info *mtd, u_char *buf, int len) } /** - * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer + * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer * @mtd: MTD device structure * @buf: buffer containing the data to compare * @len: number of bytes to compare @@ -417,7 +415,7 @@ static int nand_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) * @ofs: offset from device start * @getchip: 0, if the chip is already selected * - * Check, if the block is bad. + * Check, if the block is bad. */ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) { @@ -434,8 +432,8 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /* Select the NAND device */ this->select_chip(mtd, chipnr); - } else - page = (int) ofs; + } else + page = (int) ofs; if (this->options & NAND_BUSWIDTH_16) { this->cmdfunc (mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE, page & this->pagemask); @@ -449,12 +447,12 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) if (this->read_byte(mtd) != 0xff) res = 1; } - + if (getchip) { /* Deselect and wake up anyone waiting on the device */ nand_release_device(mtd); - } - + } + return res; } @@ -472,7 +470,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) u_char buf[2] = {0, 0}; size_t retlen; int block; - + /* Get block number */ block = ((int) ofs) >> this->bbt_erase_shift; this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); @@ -480,25 +478,25 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /* Do we have a flash based bad block table ? */ if (this->options & NAND_USE_FLASH_BBT) return nand_update_bbt (mtd, ofs); - + /* We write two bytes, so we dont have to mess with 16 bit access */ ofs += mtd->oobsize + (this->badblockpos & ~0x01); return nand_write_oob (mtd, ofs , 2, &retlen, buf); } -/** +/** * nand_check_wp - [GENERIC] check if the chip is write protected * @mtd: MTD device structure - * Check, if the device is write protected + * Check, if the device is write protected * - * The function expects, that the device is already selected + * The function expects, that the device is already selected */ static int nand_check_wp (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; /* Check the WP bit */ this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - return (this->read_byte(mtd) & 0x80) ? 0 : 1; + return (this->read_byte(mtd) & 0x80) ? 0 : 1; } /** @@ -514,10 +512,10 @@ static int nand_check_wp (struct mtd_info *mtd) static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt) { struct nand_chip *this = mtd->priv; - + if (!this->bbt) return this->block_bad(mtd, ofs, getchip); - + /* Return info from the table */ return nand_isbad_bbt (mtd, ofs, allowbbt); } @@ -582,13 +580,13 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers + + /* + * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { - + case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: @@ -597,7 +595,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in return; case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); @@ -606,18 +604,18 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in while ( !(this->read_byte(mtd) & 0x40)); return; - /* This applies to read commands */ + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } - + /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); @@ -646,8 +644,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column += mtd->oobblock; command = NAND_CMD_READ0; } - - + + /* Begin command latch cycle */ this->hwcontrol(mtd, NAND_CTL_SETCLE); /* Write out the command to the device. */ @@ -665,7 +663,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, column >>= 1; this->write_byte(mtd, column & 0xff); this->write_byte(mtd, column >> 8); - } + } if (page_addr != -1) { this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); @@ -676,13 +674,13 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* Latch in address */ this->hwcontrol(mtd, NAND_CTL_CLRALE); } - - /* - * program and erase have their own busy handlers + + /* + * program and erase have their own busy handlers * status and sequential in needs no delay */ switch (command) { - + case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: @@ -693,7 +691,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, case NAND_CMD_RESET: - if (this->dev_ready) + if (this->dev_ready) break; udelay(this->chip_delay); this->hwcontrol(mtd, NAND_CTL_SETCLE); @@ -710,19 +708,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, /* End command latch cycle */ this->hwcontrol(mtd, NAND_CTL_CLRCLE); /* Fall through into ready check */ - - /* This applies to read commands */ + + /* This applies to read commands */ default: - /* + /* * If we don't have access to the busy pin, we apply the given * command delay */ if (!this->dev_ready) { udelay (this->chip_delay); return; - } + } } - + /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay (100); @@ -734,7 +732,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, * nand_get_device - [GENERIC] Get chip for selected access * @this: the nand chip descriptor * @mtd: MTD device structure - * @new_state: the state which is requested + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ @@ -746,8 +744,8 @@ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int n DECLARE_WAITQUEUE (wait, current); - /* - * Grab the lock and see if the device is available + /* + * Grab the lock and see if the device is available */ retry: /* Hardware controller shared among independend devices */ @@ -759,7 +757,7 @@ retry: this->controller->active = this; spin_unlock (&this->controller->lock); } - + if (active == this) { spin_lock (&this->chip_lock); if (this->state == FL_READY) { @@ -767,7 +765,7 @@ retry: spin_unlock (&this->chip_lock); return; } - } + } set_current_state (TASK_UNINTERRUPTIBLE); add_wait_queue (&active->wq, &wait); spin_unlock (&active->chip_lock); @@ -786,7 +784,7 @@ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int n * @state: state to select the max. timeout value * * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to + * Erase can take up to 400ms and program up to 20ms according to * general NAND and SmartMedia specs * */ @@ -796,7 +794,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) { unsigned long timeo = jiffies; int status; - + if (state == FL_ERASING) timeo += (HZ * 400) / 1000; else @@ -808,17 +806,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else + else this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); - while (time_before(jiffies, timeo)) { + while (time_before(jiffies, timeo)) { /* Check, if we were interrupted */ if (this->state != state) return 0; if (this->dev_ready) { if (this->dev_ready(mtd)) - break; + break; } else { if (this->read_byte(mtd) & NAND_STATUS_READY) break; @@ -853,7 +851,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) * * Cached programming is not supported yet. */ -static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel, int cached) { int i, status; @@ -862,10 +860,10 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa int *oob_config = oobsel->eccpos; int datidx = 0, eccidx = 0, eccsteps = this->eccsteps; int eccbytes = 0; - + /* FIXME: Enable cached programming */ cached = 0; - + /* Send command to begin auto page programming */ this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); @@ -876,7 +874,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); this->write_buf(mtd, this->data_poi, mtd->oobblock); break; - + /* Software ecc 3/256, write all */ case NAND_ECC_SOFT: for (; eccsteps; eccsteps--) { @@ -905,11 +903,11 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa } break; } - + /* Write out OOB data */ if (this->options & NAND_HWECC_SYNDROME) this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes); - else + else this->write_buf(mtd, oob_buf, mtd->oobsize); /* Send command to actually program the data */ @@ -926,9 +924,9 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa } else { /* FIXME: Implement cached programming ! */ /* wait until cache is ready*/ - // status = this->waitfunc (mtd, this, FL_CACHEDRPG); + /* status = this->waitfunc (mtd, this, FL_CACHEDRPG); */ } - return 0; + return 0; } #ifdef CONFIG_MTD_NAND_VERIFY_WRITE @@ -944,19 +942,19 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa * @oobmode: 1 = full buffer verify, 0 = ecc only * * The NAND device assumes that it is always writing to a cleanly erased page. - * Hence, it performs its internal write verification only on bits that + * Hence, it performs its internal write verification only on bits that * transitioned from 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was not completely erased - * or the page is becoming unusable due to wear. The read with ECC would catch - * the error later when the ECC page check fails, but we would rather catch + * byte by byte basis. It is possible that the page was not completely erased + * or the page is becoming unusable due to wear. The read with ECC would catch + * the error later when the ECC page check fails, but we would rather catch * it early in the page write stage. Better to write no data than invalid data. */ -static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, +static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode) { int i, j, datidx = 0, oobofs = 0, res = -EIO; int eccsteps = this->eccsteps; - int hweccbytes; + int hweccbytes; u_char oobdata[64]; hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0; @@ -996,7 +994,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) { int ecccnt = oobsel->eccbytes; - + for (i = 0; i < ecccnt; i++) { int idx = oobsel->eccpos[i]; if (oobdata[idx] != oob_buf[oobofs + idx] ) { @@ -1006,38 +1004,38 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int goto out; } } - } + } } oobofs += mtd->oobsize - hweccbytes * eccsteps; page++; numpages--; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. * Do this also before returning, so the chip is * ready for the next command. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + while (!this->dev_ready(mtd)); /* All done, return happy */ if (!numpages) return 0; - - - /* Check, if the chip supports auto page increment */ + + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this)) this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); } - /* + /* * Terminate the read command. We come here in case of an error * So we must issue a reset command. */ -out: +out: this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1); return res; } @@ -1056,7 +1054,7 @@ out: static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); -} +} /** @@ -1080,7 +1078,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, u_char *data_poi, *oob_data = oob_buf; u_char ecc_calc[32]; u_char ecc_code[32]; - int eccmode, eccsteps; + int eccmode, eccsteps; int *oob_config, datidx; int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1; int eccbytes; @@ -1103,11 +1101,11 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) oobsel = &mtd->oobinfo; - + /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) oobsel = this->autooob; - + eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; oob_config = oobsel->eccpos; @@ -1125,28 +1123,28 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, end = mtd->oobblock; ecc = this->eccsize; eccbytes = this->eccbytes; - + if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME)) compareecc = 0; oobreadlen = mtd->oobsize; - if (this->options & NAND_HWECC_SYNDROME) + if (this->options & NAND_HWECC_SYNDROME) oobreadlen -= oobsel->eccbytes; /* Loop until all data read */ while (read < len) { - + int aligned = (!col && (len - read) >= end); - /* + /* * If the read is not page aligned, we have to read into data buffer * due to ecc, else we read into return buffer direct */ if (aligned) data_poi = &buf[read]; - else + else data_poi = this->data_buf; - - /* Check, if we have this page in the buffer + + /* Check, if we have this page in the buffer * * FIXME: Make it work when we must provide oob data too, * check the usage of data_buf oob field @@ -1162,7 +1160,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, if (sndcmd) { this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); sndcmd = 0; - } + } /* get oob area, if we have no oob buffer from fs-driver */ if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || @@ -1170,7 +1168,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, oob_data = &this->data_buf[end]; eccsteps = this->eccsteps; - + switch (eccmode) { case NAND_ECC_NONE: { /* No ECC, Read in a page */ /* XXX U-BOOT XXX */ @@ -1186,12 +1184,12 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->read_buf(mtd, data_poi, end); break; } - + case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ this->read_buf(mtd, data_poi, end); - for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) + for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); - break; + break; default: for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) { @@ -1209,15 +1207,15 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, * generator for an error, reads back the syndrome and * does the error correction on the fly */ if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; } } else { this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]); - } + } } - break; + break; } /* read oobdata */ @@ -1225,8 +1223,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ if (!compareecc) - goto readoob; - + goto readoob; + /* Pick the ECC bytes out of the oob data */ for (j = 0; j < oobsel->eccbytes; j++) ecc_code[j] = oob_data[oob_config[j]]; @@ -1234,24 +1232,24 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* correct data, if neccecary */ for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) { ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]); - + /* Get next chunk of ecc bytes */ j += eccbytes; - - /* Check, if we have a fs supplied oob-buffer, + + /* Check, if we have a fs supplied oob-buffer, * This is the legacy mode. Used by YAFFS1 * Should go away some day */ - if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { + if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { int *p = (int *)(&oob_data[mtd->oobsize]); p[i] = ecc_status; } - - if (ecc_status == -1) { + + if (ecc_status == -1) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } - } + } readoob: /* check, if we have a fs supplied oob-buffer */ @@ -1278,25 +1276,25 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } readdata: /* Partial page read, transfer data into fs buffer */ - if (!aligned) { + if (!aligned) { for (j = col; j < end && read < len; j++) buf[read++] = data_poi[j]; - this->pagebuf = realpage; - } else + this->pagebuf = realpage; + } else read += mtd->oobblock; - /* Apply delay or wait for ready/busy pin + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); - + while (!this->dev_ready(mtd)); + if (read == len) - break; + break; /* For subsequent reads align to page boundary. */ col = 0; @@ -1310,11 +1308,11 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) - sndcmd = 1; + sndcmd = 1; } /* Deselect and wake up anyone waiting on the device */ @@ -1350,7 +1348,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Shift to get page */ page = (int)(from >> this->page_shift); chipnr = (int)(from >> this->chip_shift); - + /* Mask to get column */ col = from & (mtd->oobsize - 1); @@ -1372,7 +1370,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t /* Send the read command */ this->cmdfunc (mtd, NAND_CMD_READOOB, col, page & this->pagemask); - /* + /* * Read the data, if we read more than one page * oob data, let the device transfer the data ! */ @@ -1382,16 +1380,16 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t thislen = min_t(int, thislen, len); this->read_buf(mtd, &buf[i], thislen); i += thislen; - - /* Apply delay or wait for ready/busy pin + + /* Apply delay or wait for ready/busy pin * Do this before the AUTOINCR check, so no problems * arise if a chip which does auto increment * is marked as NOAUTOINCR by the board driver. */ - if (!this->dev_ready) + if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); + while (!this->dev_ready(mtd)); /* Read more ? */ if (i < len) { @@ -1404,13 +1402,13 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t this->select_chip(mtd, -1); this->select_chip(mtd, chipnr); } - - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ + + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) { /* For subsequent page reads set offset to 0 */ - this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); + this->cmdfunc (mtd, NAND_CMD_READOOB, 0x0, page & this->pagemask); } } } @@ -1453,27 +1451,27 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, nand_get_device (this, mtd , FL_READING); this->select_chip (mtd, chip); - + /* Add requested oob length */ len += ooblen; - + while (len) { if (sndcmd) this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask); - sndcmd = 0; + sndcmd = 0; this->read_buf (mtd, &buf[cnt], pagesize); len -= pagesize; cnt += pagesize; page++; - - if (!this->dev_ready) + + if (!this->dev_ready) udelay (this->chip_delay); else - while (!this->dev_ready(mtd)); - - /* Check, if the chip supports auto page increment */ + while (!this->dev_ready(mtd)); + + /* Check, if the chip supports auto page increment */ if (!NAND_CANAUTOINCR(this) || !(page & blockcheck)) sndcmd = 1; } @@ -1484,8 +1482,8 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, } -/** - * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer +/** + * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * @mtd: MTD device structure * @fsbuf: buffer given by fs driver * @oobsel: out of band selection structre @@ -1514,20 +1512,20 @@ static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct int i, len, ofs; /* Zero copy fs supplied buffer */ - if (fsbuf && !autoplace) + if (fsbuf && !autoplace) return fsbuf; /* Check, if the buffer must be filled with ff again */ - if (this->oobdirty) { - memset (this->oob_buf, 0xff, + if (this->oobdirty) { + memset (this->oob_buf, 0xff, mtd->oobsize << (this->phys_erase_shift - this->page_shift)); this->oobdirty = 0; - } - + } + /* If we have no autoplacement or no fs buffer use the internal one */ if (!autoplace || !fsbuf) return this->oob_buf; - + /* Walk through the pages and place the data */ this->oobdirty = 1; ofs = 0; @@ -1561,7 +1559,7 @@ static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * ret { return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); } - + /** * nand_write_ecc - [MTD Interface] NAND write with ECC * @mtd: MTD device structure @@ -1594,7 +1592,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, return -EINVAL; } - /* reject writes, which are not page aligned */ + /* reject writes, which are not page aligned */ if (NOTALIGNED (to) || NOTALIGNED(len)) { printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; @@ -1613,14 +1611,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, goto out; /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; - + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; autoplace = 1; - } + } if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) autoplace = 1; @@ -1628,9 +1626,9 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, totalpages = len >> this->page_shift; page = (int) (to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) + if (page <= this->pagebuf && this->pagebuf < (page + totalpages)) this->pagebuf = -1; - + /* Set it relative to chip */ page &= this->pagemask; startpage = page; @@ -1652,14 +1650,14 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: write_page failed %d\n", ret); goto out; - } + } /* Next oob page */ oob += mtd->oobsize; /* Update written bytes count */ written += mtd->oobblock; - if (written == len) + if (written == len) goto cmp; - + /* Increment page address */ page++; @@ -1670,13 +1668,13 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, if (!(page & (ppblock - 1))){ int ofs; this->data_poi = bufstart; - ret = nand_verify_pages (mtd, this, startpage, + ret = nand_verify_pages (mtd, this, startpage, page - startpage, oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (ret) { DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); goto out; - } + } *retlen = written; ofs = autoplace ? mtd->oobavail : mtd->oobsize; @@ -1686,7 +1684,7 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, numpages = min (totalpages, ppblock); page &= this->pagemask; startpage = page; - oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, + oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages); /* Check, if we cross a chip boundary */ if (!page) { @@ -1703,7 +1701,7 @@ cmp: oobbuf, oobsel, chipnr, (eccbuf != NULL)); if (!ret) *retlen = written; - else + else DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: verify_pages failed %d\n", ret); out: @@ -1763,7 +1761,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * /* Check, if it is write protected */ if (nand_check_wp(mtd)) goto out; - + /* Invalidate the page cache, if we write to the cached page */ if (page == this->pagebuf) this->pagebuf = -1; @@ -1827,10 +1825,10 @@ out: * * NAND write with kvec. This just calls the ecc function */ -static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, +static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen) { - return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); + return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, NULL)); } /** @@ -1845,7 +1843,7 @@ static int nand_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned * * NAND write with iovec with ecc */ -static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, +static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { int i, page, len, total_len, ret = -EIO, written = 0, chipnr; @@ -1871,7 +1869,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig return -EINVAL; } - /* reject writes, which are not page aligned */ + /* reject writes, which are not page aligned */ if (NOTALIGNED (to) || NOTALIGNED(total_len)) { printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); return -EINVAL; @@ -1890,21 +1888,21 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig goto out; /* if oobsel is NULL, use chip defaults */ - if (oobsel == NULL) - oobsel = &mtd->oobinfo; + if (oobsel == NULL) + oobsel = &mtd->oobinfo; /* Autoplace of oob data ? Use the default placement scheme */ if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) { oobsel = this->autooob; autoplace = 1; - } + } if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR) autoplace = 1; /* Setup start page */ page = (int) (to >> this->page_shift); /* Invalidate the page cache, if we write to the cached page */ - if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) + if (page <= this->pagebuf && this->pagebuf < ((to + total_len) >> this->page_shift)) this->pagebuf = -1; startpage = page & this->pagemask; @@ -1928,10 +1926,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig oob = 0; for (i = 1; i <= numpages; i++) { /* Write one page. If this is the last page to write - * then use the real pageprogram command, else select + * then use the real pageprogram command, else select * cached programming if supported by the chip. */ - ret = nand_write_page (mtd, this, page & this->pagemask, + ret = nand_write_page (mtd, this, page & this->pagemask, &oobbuf[oob], oobsel, i != numpages); if (ret) goto out; @@ -1947,12 +1945,12 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig count--; } } else { - /* We must use the internal buffer, read data out of each + /* We must use the internal buffer, read data out of each * tuple until we have a full page to write */ int cnt = 0; while (cnt < mtd->oobblock) { - if (vecs->iov_base != NULL && vecs->iov_len) + if (vecs->iov_base != NULL && vecs->iov_len) this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; /* Check, if we have to switch to the next tuple */ if (len >= (int) vecs->iov_len) { @@ -1961,10 +1959,10 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig count--; } } - this->pagebuf = page; - this->data_poi = this->data_buf; + this->pagebuf = page; + this->data_poi = this->data_buf; bufstart = this->data_poi; - numpages = 1; + numpages = 1; oobbuf = nand_prepare_oobbuf (mtd, NULL, oobsel, autoplace, numpages); ret = nand_write_page (mtd, this, page & this->pagemask, oobbuf, oobsel, 0); @@ -1977,7 +1975,7 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig ret = nand_verify_pages (mtd, this, startpage, numpages, oobbuf, oobsel, chipnr, 0); if (ret) goto out; - + written += mtd->oobblock * numpages; /* All done ? */ if (!count) @@ -2046,7 +2044,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) { return nand_erase_nand (mtd, instr, 0); } - + /** * nand_erase_intern - [NAND Interface] erase block(s) * @mtd: MTD device structure @@ -2116,14 +2114,14 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb instr->state = MTD_ERASE_FAILED; goto erase_exit; } - - /* Invalidate the page cache, if we erase the block which contains + + /* Invalidate the page cache, if we erase the block which contains the current cached page */ if (page <= this->pagebuf && this->pagebuf < (page + pages_per_block)) this->pagebuf = -1; this->erase_cmd (mtd, page & this->pagemask); - + status = this->waitfunc (mtd, this, FL_ERASING); /* See if block erase succeeded */ @@ -2133,7 +2131,7 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb instr->fail_addr = (page << this->page_shift); goto erase_exit; } - + /* Increment page address and decrement length */ len -= (1 << this->phys_erase_shift); page += pages_per_block; @@ -2188,9 +2186,9 @@ static void nand_sync (struct mtd_info *mtd) static int nand_block_isbad (struct mtd_info *mtd, loff_t ofs) { /* Check for invalid offset */ - if (ofs > mtd->size) + if (ofs > mtd->size) return -EINVAL; - + return nand_block_checkbad (mtd, ofs, 1, 0); } @@ -2204,12 +2202,12 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs) struct nand_chip *this = mtd->priv; int ret; - if ((ret = nand_block_isbad(mtd, ofs))) { - /* If it was bad already, return success and do nothing. */ + if ((ret = nand_block_isbad(mtd, ofs))) { + /* If it was bad already, return success and do nothing. */ if (ret > 0) return 0; - return ret; - } + return ret; + } return this->block_markbad(mtd, ofs); } @@ -2281,13 +2279,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - - if (nand_dev_id != nand_flash_ids[i].id) + + if (nand_dev_id != nand_flash_ids[i].id) continue; if (!mtd->name) mtd->name = nand_flash_ids[i].name; this->chipsize = nand_flash_ids[i].chipsize << 20; - + /* New devices have all the information in additional id bytes */ if (!nand_flash_ids[i].pagesize) { int extid; @@ -2306,7 +2304,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) extid >>= 2; /* Get buswidth information */ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - + } else { /* Old devices have this data hardcoded in the * device id table */ @@ -2320,23 +2318,23 @@ int nand_scan (struct mtd_info *mtd, int maxchips) * this correct ! */ if (busw != (this->options & NAND_BUSWIDTH_16)) { printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[i].name , mtd->name); - printk (KERN_WARNING - "NAND bus width %d instead %d bit\n", + printk (KERN_WARNING + "NAND bus width %d instead %d bit\n", (this->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); this->select_chip(mtd, -1); - return 1; + return 1; } - - /* Calculate the address shift from the page size */ + + /* Calculate the address shift from the page size */ this->page_shift = ffs(mtd->oobblock) - 1; this->bbt_erase_shift = this->phys_erase_shift = ffs(mtd->erasesize) - 1; this->chip_shift = ffs(this->chipsize) - 1; /* Set the bad block position */ - this->badblockpos = mtd->oobblock > 512 ? + this->badblockpos = mtd->oobblock > 512 ? NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; /* Get chip options, preserve non chip based options */ @@ -2346,10 +2344,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->options |= NAND_NO_AUTOINCR; /* Check if this is a not a samsung device. Do not clear the options * for chips which are not having an extended id. - */ + */ if (nand_maf_id != NAND_MFR_SAMSUNG && !nand_flash_ids[i].pagesize) this->options &= ~NAND_SAMSUNG_LP_OPTIONS; - + /* Check for AND chips with 4 page planes */ if (this->options & NAND_4PAGE_ARRAY) this->erase_cmd = multi_erase_cmd; @@ -2359,14 +2357,14 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* Do not replace user supplied command function ! */ if (mtd->oobblock > 512 && this->cmdfunc == nand_command) this->cmdfunc = nand_command_lp; - + /* Try to identify manufacturer */ for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { if (nand_manuf_ids[j].id == nand_maf_id) break; } printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, nand_manuf_ids[j].name , nand_flash_ids[i].name); break; } @@ -2390,7 +2388,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } if (i > 1) printk(KERN_INFO "%d NAND chips detected\n", i); - + /* Allocate buffers, if neccecary */ if (!this->oob_buf) { size_t len; @@ -2402,7 +2400,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } this->options |= NAND_OOBBUF_ALLOC; } - + if (!this->data_buf) { size_t len; len = mtd->oobblock + mtd->oobsize; @@ -2429,7 +2427,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) if (!this->autooob) { /* Select the appropriate default oob placement scheme for * placement agnostic filesystems */ - switch (mtd->oobsize) { + switch (mtd->oobsize) { case 8: this->autooob = &nand_oob_8; break; @@ -2445,7 +2443,7 @@ int nand_scan (struct mtd_info *mtd, int maxchips) /* BUG(); */ } } - + /* The number of bytes available for the filesystem to place fs dependend * oob data */ if (this->options & NAND_BUSWIDTH_16) { @@ -2455,12 +2453,12 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } else mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1); - /* + /* * check ECC mode, default to software * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize - * fallback to software ECC + * fallback to software ECC */ - this->eccsize = 256; /* set default eccsize */ + this->eccsize = 256; /* set default eccsize */ this->eccbytes = 3; switch (this->eccmode) { @@ -2475,27 +2473,27 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->eccsize = 2048; break; - case NAND_ECC_HW3_512: - case NAND_ECC_HW6_512: - case NAND_ECC_HW8_512: + case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: + case NAND_ECC_HW8_512: if (mtd->oobblock == 256) { printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); this->eccmode = NAND_ECC_SOFT; this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; - } else + } else this->eccsize = 512; /* set eccsize to 512 */ break; - + case NAND_ECC_HW3_256: break; - - case NAND_ECC_NONE: + + case NAND_ECC_NONE: printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); this->eccmode = NAND_ECC_NONE; break; - case NAND_ECC_SOFT: + case NAND_ECC_SOFT: this->calculate_ecc = nand_calculate_ecc; this->correct_data = nand_correct_data; break; @@ -2503,28 +2501,28 @@ int nand_scan (struct mtd_info *mtd, int maxchips) default: printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); /* BUG(); */ - } + } - /* Check hardware ecc function availability and adjust number of ecc bytes per + /* Check hardware ecc function availability and adjust number of ecc bytes per * calculation step */ switch (this->eccmode) { case NAND_ECC_HW12_2048: this->eccbytes += 4; - case NAND_ECC_HW8_512: + case NAND_ECC_HW8_512: this->eccbytes += 2; - case NAND_ECC_HW6_512: + case NAND_ECC_HW6_512: this->eccbytes += 3; - case NAND_ECC_HW3_512: + case NAND_ECC_HW3_512: case NAND_ECC_HW3_256: if (this->calculate_ecc && this->correct_data && this->enable_hwecc) break; printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); /* BUG(); */ } - + mtd->eccsize = this->eccsize; - + /* Set the number of read / write steps for one page to ensure ECC generation */ switch (this->eccmode) { case NAND_ECC_HW12_2048: @@ -2536,17 +2534,17 @@ int nand_scan (struct mtd_info *mtd, int maxchips) this->eccsteps = mtd->oobblock / 512; break; case NAND_ECC_HW3_256: - case NAND_ECC_SOFT: + case NAND_ECC_SOFT: this->eccsteps = mtd->oobblock / 256; break; - - case NAND_ECC_NONE: + + case NAND_ECC_NONE: this->eccsteps = 1; break; } /* XXX U-BOOT XXX */ -#if 0 +#if 0 /* Initialize state, waitqueue and spinlock */ this->state = FL_READY; init_waitqueue_head (&this->wq); @@ -2600,9 +2598,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips) } /** - * nand_release - [NAND Interface] Free resources held by the NAND device + * nand_release - [NAND Interface] Free resources held by the NAND device * @mtd: MTD device structure -*/ + */ void nand_release (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; diff --git a/drivers/nand/nand_bbt.c b/drivers/nand/nand_bbt.c index 6f7e05b7eb..dfa88a3af6 100644 --- a/drivers/nand/nand_bbt.c +++ b/drivers/nand/nand_bbt.c @@ -3,7 +3,7 @@ * * Overview: * Bad block table support for the NAND driver - * + * * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $ @@ -14,23 +14,23 @@ * * Description: * - * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the bbt descriptor(s). If a bbt is found - * then the contents are read and the memory based bbt is created. If a + * When nand_scan_bbt is called, then it tries to find the bad block table + * depending on the options in the bbt descriptor(s). If a bbt is found + * then the contents are read and the memory based bbt is created. If a * mirrored bbt is selected then the mirror is searched too and the - * versions are compared. If the mirror has a greater version number + * versions are compared. If the mirror has a greater version number * than the mirror bbt is used to build the memory based bbt. * If the tables are not versioned, then we "or" the bad block information. - * If one of the bbt's is out of date or does not exist it is (re)created. - * If no bbt exists at all then the device is scanned for factory marked - * good / bad blocks and the bad block tables are created. + * If one of the bbt's is out of date or does not exist it is (re)created. + * If no bbt exists at all then the device is scanned for factory marked + * good / bad blocks and the bad block tables are created. * - * For manufacturer created bbts like the one found on M-SYS DOC devices + * For manufacturer created bbts like the one found on M-SYS DOC devices * the bbt is searched and read but never created * - * The autogenerated bad block table is located in the last good blocks - * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the oob area with an ident pattern and a version + * The autogenerated bad block table is located in the last good blocks + * of the device. The table is mirrored, so it can be updated eventually. + * The table is marked in the oob area with an ident pattern and a version * number which indicates which of both tables is more up to date. * * The table uses 2 bits per block @@ -43,13 +43,13 @@ * 01b: block is marked bad due to wear * 10b: block is reserved (to protect the bbt area) * 11b: block is factory marked bad - * + * * Multichip devices like DOC store the bad block info per floor. * * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary * - the space neccecary for a bbt in FLASH does not exceed a block boundary - * + * */ #include <common.h> @@ -63,7 +63,7 @@ #include <asm/errno.h> -/** +/** * check_pattern - [GENERIC] check if a pattern is in the buffer * @buf: the buffer to search * @len: the length of buffer to search @@ -87,9 +87,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des if (p[i] != 0xff) return -1; } - } + } p += end; - + /* Compare the pattern */ for (i = 0; i < td->len; i++) { if (p[i] != td->pattern[i]) @@ -120,7 +120,7 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des * Read the bad block table starting from page. * */ -static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, +static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, int bits, int offs, int reserved_block_code) { int res, i, j, act = 0; @@ -131,7 +131,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, totlen = (num * bits) >> 3; from = ((loff_t)page) << this->page_shift; - + while (totlen) { len = min (totlen, (size_t) (1 << this->bbt_erase_shift)); res = mtd->read_ecc (mtd, from, len, &retlen, buf, NULL, this->autooob); @@ -141,7 +141,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, return res; } printk (KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); - } + } /* Analyse data */ for (i = 0; i < len; i++) { @@ -161,12 +161,12 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, * message to MTD_DEBUG_LEVEL0 */ printk (KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - /* Factory marked bad or worn out ? */ + /* Factory marked bad or worn out ? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); else this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); - } + } } totlen -= len; from += len; @@ -178,7 +178,7 @@ static int read_bbt (struct mtd_info *mtd, uint8_t *buf, int page, int num, * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @chip: read the table for a specific chip, -1 read all chips. * Applies only if NAND_BBT_PERCHIP option is set * @@ -213,7 +213,7 @@ static int read_abs_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Read the bad block table(s) for all chips starting at a given page @@ -225,16 +225,16 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de { struct nand_chip *this = mtd->priv; - /* Read the primary version, if available */ + /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw (mtd, buf, td->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); td->version[0] = buf[mtd->oobblock + td->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", td->pages[0], td->version[0]); } - /* Read the mirror version, if available */ + /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw (mtd, buf, md->pages[0] << this->page_shift, mtd->oobblock, mtd->oobsize); md->version[0] = buf[mtd->oobblock + md->veroffs]; printk (KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", md->pages[0], md->version[0]); } @@ -268,7 +268,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc else { if (bd->options & NAND_BBT_SCAN2NDPAGE) len = 2; - else + else len = 1; } scanlen = mtd->oobblock + mtd->oobsize; @@ -285,20 +285,20 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (chip >= this->numchips) { printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", chip + 1, this->numchips); - return; + return; } numblocks = this->chipsize >> (this->bbt_erase_shift - 1); startblock = chip * numblocks; numblocks += startblock; from = startblock << (this->bbt_erase_shift - 1); } - + for (i = startblock; i < numblocks;) { nand_read_raw (mtd, buf, from, readlen, ooblen); for (j = 0; j < len; j++) { if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n", i >> 1, (unsigned int) from); break; } @@ -315,15 +315,15 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc * @td: descriptor for the bad block table * * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of + * Search is preformed either from the beginning up or from the end of * the device downwards. The search starts always at the start of a * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched + * If the option NAND_BBT_PERCHIP is given, each chip is searched * for a bbt, which contains the bad block information of this chip. * This is neccecary to provide support for certain DOC devices. * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page + * in a block. */ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { @@ -338,10 +338,10 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr startblock = (mtd->size >> this->bbt_erase_shift) -1; dir = -1; } else { - startblock = 0; + startblock = 0; dir = 1; - } - + } + /* Do we have a bbt per chip ? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; @@ -351,19 +351,19 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr chips = 1; bbtblocks = mtd->size >> this->bbt_erase_shift; } - + /* Number of bits for each erase block in the bbt */ bits = td->options & NAND_BBT_NRBITS_MSK; - + for (i = 0; i < chips; i++) { /* Reset version information */ - td->version[i] = 0; + td->version[i] = 0; td->pages[i] = -1; /* Scan the maximum number of blocks */ for (block = 0; block < td->maxblocks; block++) { int actblock = startblock + dir * block; /* Read first page */ - nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); + nand_read_raw (mtd, buf, actblock << this->bbt_erase_shift, mtd->oobblock, mtd->oobsize); if (!check_pattern(buf, scanlen, mtd->oobblock, td)) { td->pages[i] = actblock << (this->bbt_erase_shift - this->page_shift); if (td->options & NAND_BBT_VERSION) { @@ -381,46 +381,46 @@ static int search_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr else printk (KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); } - return 0; + return 0; } /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * * Search and read the bad block table(s) */ -static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, +static int search_read_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ search_bbt (mtd, buf, td); - + /* Search the mirror table */ if (md) search_bbt (mtd, buf, md); - + /* Force result check */ - return 1; + return 1; } - -/** + +/** * write_bbt - [GENERIC] (Re)write the bad block table * * @mtd: MTD device structure * @buf: temporary buffer - * @td: descriptor for the bad block table + * @td: descriptor for the bad block table * @md: descriptor for the bad block table mirror * @chipsel: selector for a specific chip, -1 for all * * (Re)write the bad block table * */ -static int write_bbt (struct mtd_info *mtd, uint8_t *buf, +static int write_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) { struct nand_chip *this = mtd->priv; @@ -439,7 +439,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, /* Write bad block table per chip rather than per device ? */ if (td->options & NAND_BBT_PERCHIP) { numblocks = (int) (this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip ? */ + /* Full device write or specific chip ? */ if (chipsel == -1) { nrchips = this->numchips; } else { @@ -449,19 +449,19 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, } else { numblocks = (int) (mtd->size >> this->bbt_erase_shift); nrchips = 1; - } - + } + /* Loop through the chips */ for (; chip < nrchips; chip++) { - - /* There was already a version of the table, reuse the page - * This applies for absolute placement too, as we have the + + /* There was already a version of the table, reuse the page + * This applies for absolute placement too, as we have the * page nr. in td->pages. */ if (td->pages[chip] != -1) { page = td->pages[chip]; goto write; - } + } /* Automatic placement of the bad block table */ /* Search direction top -> down ? */ @@ -471,7 +471,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, } else { startblock = chip * numblocks; dir = 1; - } + } for (i = 0; i < td->maxblocks; i++) { int block = startblock + dir * i; @@ -488,7 +488,7 @@ static int write_bbt (struct mtd_info *mtd, uint8_t *buf, } printk (KERN_ERR "No space left to write bad block table\n"); return -ENOSPC; -write: +write: /* Set up shift count and masks for the flash table */ bits = td->options & NAND_BBT_NRBITS_MSK; @@ -499,14 +499,14 @@ write: case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; msk[2] = ~rcode; msk[3] = 0xff; break; default: return -EINVAL; } - + bbtoffs = chip * (numblocks >> 2); - + to = ((loff_t) page) << this->page_shift; memcpy (&oobinfo, this->autooob, sizeof(oobinfo)); oobinfo.useecc = MTD_NANDECC_PLACEONLY; - + /* Must we save the block contents ? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ @@ -545,7 +545,7 @@ write: buf[len + td->veroffs] = td->version[chip]; } } - + /* walk through the memory table */ for (i = 0; i < numblocks; ) { uint8_t dat; @@ -557,7 +557,7 @@ write: dat >>= 2; } } - + memset (&einfo, 0, sizeof (einfo)); einfo.mtd = mtd; einfo.addr = (unsigned long) to; @@ -567,18 +567,18 @@ write: printk (KERN_WARNING "nand_bbt: Error during block erase: %d\n", res); return res; } - + res = mtd->write_ecc (mtd, to, len, &retlen, buf, &buf[len], &oobinfo); if (res < 0) { printk (KERN_WARNING "nand_bbt: Error while writing bad block table %d\n", res); return res; } - printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", + printk (KERN_DEBUG "Bad block table written to 0x%08x, version 0x%02X\n", (unsigned int) to, td->version[chip]); - + /* Mark it as used */ td->pages[chip] = page; - } + } return 0; } @@ -587,7 +587,7 @@ write: * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern * - * The function creates a memory based bbt by scanning the device + * The function creates a memory based bbt by scanning the device * for manufacturer / software marked good / bad blocks */ static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) @@ -621,11 +621,11 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des struct nand_bbt_descr *rd, *rd2; /* Do we have a bbt per chip ? */ - if (td->options & NAND_BBT_PERCHIP) + if (td->options & NAND_BBT_PERCHIP) chips = this->numchips; - else + else chips = 1; - + for (i = 0; i < chips; i++) { writeops = 0; rd = NULL; @@ -640,7 +640,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des } if (td->pages[i] == -1) { - rd = md; + rd = md; td->version[i] = md->version[i]; writeops = 1; goto writecheck; @@ -658,7 +658,7 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des if (!(td->options & NAND_BBT_VERSION)) rd2 = md; goto writecheck; - } + } if (((int8_t) (td->version[i] - md->version[i])) > 0) { rd = td; @@ -683,15 +683,15 @@ static int check_create (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_des create: /* Create the bad block table by scanning the device ? */ if (!(td->options & NAND_BBT_CREATE)) - continue; - + continue; + /* Create the table in memory by scanning the chip(s) */ create_bbt (mtd, buf, bd, chipsel); - + td->version[i] = 1; if (md) - md->version[i] = 1; -writecheck: + md->version[i] = 1; +writecheck: /* read back first ? */ if (rd) read_abs_bbt (mtd, buf, rd, chipsel); @@ -705,7 +705,7 @@ writecheck: if (res < 0) return res; } - + /* Write the mirror bad block table to the device ? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { res = write_bbt (mtd, buf, md, td, chipsel); @@ -713,11 +713,11 @@ writecheck: return res; } } - return 0; + return 0; } /** - * mark_bbt_regions - [GENERIC] mark the bad block table regions + * mark_bbt_regions - [GENERIC] mark the bad block table regions * @mtd: MTD device structure * @td: bad block table descriptor * @@ -738,14 +738,14 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) } else { chips = 1; nrblocks = (int)(mtd->size >> this->bbt_erase_shift); - } - + } + for (i = 0; i < chips; i++) { if ((td->options & NAND_BBT_ABSPAGE) || !(td->options & NAND_BBT_WRITE)) { if (td->pages[i] == -1) continue; block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); - block <<= 1; + block <<= 1; oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; @@ -756,16 +756,16 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) update = 0; if (td->options & NAND_BBT_LASTBLOCK) block = ((i + 1) * nrblocks) - td->maxblocks; - else + else block = i * nrblocks; - block <<= 1; + block <<= 1; for (j = 0; j < td->maxblocks; j++) { oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; if (oldval != newval) update = 1; block += 2; - } + } /* If we want reserved blocks to be recorded to flash, and some new ones have been marked, then we need to update the stored bbts. This should only happen once. */ @@ -779,7 +779,7 @@ static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td) * @mtd: MTD device structure * @bd: descriptor for the good/bad block search pattern * - * The function checks, if a bad block table(s) is/are already + * The function checks, if a bad block table(s) is/are already * available. If not it scans the device for manufacturer * marked good / bad blocks and writes the bad block table(s) to * the selected place. @@ -822,30 +822,30 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd) this->bbt = NULL; return -ENOMEM; } - + /* Is the bbt at a given page ? */ if (td->options & NAND_BBT_ABSPAGE) { res = read_abs_bbts (mtd, buf, td, md); - } else { + } else { /* Search the bad block table using a pattern in oob */ res = search_read_bbts (mtd, buf, td, md); - } + } - if (res) + if (res) res = check_create (mtd, buf, bd); - + /* Prevent the bbt regions from erasing / writing */ mark_bbt_region (mtd, td); if (md) mark_bbt_region (mtd, md); - + kfree (buf); return res; } /** - * nand_update_bbt - [NAND Interface] update bad block table(s) + * nand_update_bbt - [NAND Interface] update bad block table(s) * @mtd: MTD device structure * @offs: the offset of the newly marked block * @@ -872,7 +872,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) printk (KERN_ERR "nand_update_bbt: Out of memory\n"); return -ENOMEM; } - + writeops = md != NULL ? 0x03 : 0x01; /* Do we have a bbt per chip ? */ @@ -886,7 +886,7 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) td->version[chip]++; if (md) - md->version[chip]++; + md->version[chip]++; /* Write the bad block table to the device ? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { @@ -899,15 +899,15 @@ int nand_update_bbt (struct mtd_info *mtd, loff_t offs) res = write_bbt (mtd, buf, md, td, chipsel); } -out: +out: kfree (buf); return res; } -/* Define some generic bad / good block scan pattern which are used +/* Define some generic bad / good block scan pattern which are used * while scanning a device for factory marked good / bad blocks - * - * The memory based patterns just + * + * The memory based patterns just */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; @@ -954,7 +954,7 @@ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, .offs = 8, .len = 4, @@ -964,7 +964,7 @@ static struct nand_bbt_descr bbt_main_descr = { }; static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, .offs = 8, .len = 4, @@ -974,7 +974,7 @@ static struct nand_bbt_descr bbt_mirror_descr = { }; /** - * nand_default_bbt - [NAND Interface] Select a default bad block table for the device + * nand_default_bbt - [NAND Interface] Select a default bad block table for the device * @mtd: MTD device structure * * This function selects the default bad block table @@ -984,29 +984,29 @@ static struct nand_bbt_descr bbt_mirror_descr = { int nand_default_bbt (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - - /* Default for AG-AND. We must use a flash based + + /* Default for AG-AND. We must use a flash based * bad block table as the devices have factory marked * _good_ blocks. Erasing those blocks leads to loss * of the good / bad information, so we _must_ store - * this information in a good / bad table during + * this information in a good / bad table during * startup */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ - if (!this->bbt_td) { + if (!this->bbt_td) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; - } + } this->options |= NAND_USE_FLASH_BBT; return nand_scan_bbt (mtd, &agand_flashbased); } - - + + /* Is a flash based bad block table requested ? */ if (this->options & NAND_USE_FLASH_BBT) { - /* Use the default pattern descriptors */ - if (!this->bbt_td) { + /* Use the default pattern descriptors */ + if (!this->bbt_td) { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } @@ -1026,23 +1026,23 @@ int nand_default_bbt (struct mtd_info *mtd) } /** - * nand_isbad_bbt - [NAND Interface] Check if a block is bad + * nand_isbad_bbt - [NAND Interface] Check if a block is bad * @mtd: MTD device structure * @offs: offset in the device * @allowbbt: allow access to bad block table region * -*/ + */ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt) { struct nand_chip *this = mtd->priv; int block; uint8_t res; - + /* Get block number * 2 */ block = (int) (offs >> (this->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", + DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1); switch ((int)res) { diff --git a/drivers/nand/nand_ecc.c b/drivers/nand/nand_ecc.c index dc9db4b480..6e11c22858 100644 --- a/drivers/nand/nand_ecc.c +++ b/drivers/nand/nand_ecc.c @@ -13,16 +13,16 @@ * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 or (at your option) any * later version. - * + * * This file 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 file; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * + * * As a special exception, if other files instantiate templates or use * macros or inline functions from these files, or you compile these * files and link them with other works to produce a work based on these @@ -30,7 +30,7 @@ * covered by the GNU General Public License. However the source code for * these files must still be made available in accordance with section (3) * of the GNU General Public License. - * + * * This exception does not invalidate any other reasons why a work based on * this file might be covered by the GNU General Public License. */ @@ -66,7 +66,7 @@ static const u_char nand_ecc_precalc_table[] = { * nand_trans_result - [GENERIC] create non-inverted ECC * @reg2: line parity reg 2 * @reg3: line parity reg 3 - * @ecc_code: ecc + * @ecc_code: ecc * * Creates non-inverted ECC code from line parity */ @@ -74,11 +74,11 @@ static void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code) { u_char a, b, i, tmp1, tmp2; - + /* Initialize variables */ a = b = 0x80; tmp1 = tmp2 = 0; - + /* Calculate first ECC byte */ for (i = 0; i < 4; i++) { if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ @@ -89,7 +89,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, b >>= 1; a >>= 1; } - + /* Calculate second ECC byte */ b = 0x80; for (i = 0; i < 4; i++) { @@ -101,7 +101,7 @@ static void nand_trans_result(u_char reg2, u_char reg3, b >>= 1; a >>= 1; } - + /* Store two of the ECC bytes */ ecc_code[0] = tmp1; ecc_code[1] = tmp2; @@ -117,28 +117,28 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code { u_char idx, reg1, reg2, reg3; int j; - + /* Initialize variables */ reg1 = reg2 = reg3 = 0; ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; - - /* Build up column parity */ + + /* Build up column parity */ for(j = 0; j < 256; j++) { - + /* Get CP0 - CP5 from table */ idx = nand_ecc_precalc_table[dat[j]]; reg1 ^= (idx & 0x3f); - + /* All bit XOR = 1 ? */ if (idx & 0x40) { reg3 ^= (u_char) j; reg2 ^= ~((u_char) j); } } - + /* Create non-inverted ECC code from line parity */ nand_trans_result(reg2, reg3, ecc_code); - + /* Calculate final ECC code */ ecc_code[0] = ~ecc_code[0]; ecc_code[1] = ~ecc_code[1]; @@ -158,12 +158,12 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { u_char a, b, c, d1, d2, d3, add, bit, i; - - /* Do error detection */ + + /* Do error detection */ d1 = calc_ecc[0] ^ read_ecc[0]; d2 = calc_ecc[1] ^ read_ecc[1]; d3 = calc_ecc[2] ^ read_ecc[2]; - + if ((d1 | d2 | d3) == 0) { /* No errors */ return 0; @@ -172,7 +172,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha a = (d1 ^ (d1 >> 1)) & 0x55; b = (d2 ^ (d2 >> 1)) & 0x55; c = (d3 ^ (d3 >> 1)) & 0x54; - + /* Found and will correct single bit error in the data */ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { c = 0x80; @@ -205,8 +205,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha a ^= (b << bit); dat[add] = a; return 1; - } - else { + } else { i = 0; while (d1) { if (d1 & 0x01) @@ -236,7 +235,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_cha } } } - + /* Should never happen */ return -1; } diff --git a/drivers/nand/nand_ids.c b/drivers/nand/nand_ids.c index 5df1e8971d..39882cc76b 100644 --- a/drivers/nand/nand_ids.c +++ b/drivers/nand/nand_ids.c @@ -18,14 +18,14 @@ /* * Chip ID list -* +* * Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, * options -* +* * Pagesize; 0, 256, 512 * 0 get this information from the extended chip ID + 256 256 Byte page size -* 512 512 Byte page size +* 512 512 Byte page size */ struct nand_flash_dev nand_flash_ids[] = { {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0}, @@ -38,36 +38,36 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0}, {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0}, {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0}, - + {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0}, {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0}, {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16}, {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16}, - + {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0}, {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0}, {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16}, {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0}, {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0}, {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16}, {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0}, {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0}, {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16}, {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0}, {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0}, {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16}, {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16}, - + {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0}, - + /* These are the new chips with large page size. The pagesize * and the erasesize is determined from the extended id bytes */ @@ -82,13 +82,13 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - + /* 4 Gigabit */ {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - + /* 8 Gigabit */ {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR}, @@ -101,11 +101,11 @@ struct nand_flash_dev nand_flash_ids[] = { {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR}, - /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! + /* Renesas AND 1 Gigabit. Those chips do not support extended id and have a strange page/block layout ! * The chosen minimum erasesize is 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page planes * 1 block = 2 pages, but due to plane arrangement the blocks 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 * Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go - * There are more speed improvements for reads and writes possible, but not implemented now + * There are more speed improvements for reads and writes possible, but not implemented now */ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY}, diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index e53aa31eff..6658512b20 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -143,7 +143,7 @@ /* keeps pointer to currentlu processed partition */ static struct part_info *current_part; -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE) /* * Support for jffs2 on top of NAND-flash * @@ -290,7 +290,7 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf) return get_fl_mem_nor(off); #endif -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE) if (id->type == MTD_DEV_TYPE_NAND) return get_fl_mem_nand(off, size, ext_buf); #endif @@ -308,7 +308,7 @@ static inline void *get_node_mem(u32 off) return get_node_mem_nor(off); #endif -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE) if (id->type == MTD_DEV_TYPE_NAND) return get_node_mem_nand(off); #endif @@ -319,7 +319,7 @@ static inline void *get_node_mem(u32 off) static inline void put_fl_mem(void *buf) { -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) +#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CONFIG_NEW_NAND_CODE) struct mtdids *id = current_part->dev->id; if (id->type == MTD_DEV_TYPE_NAND) diff --git a/fs/jffs2/jffs2_nand_1pass.c b/fs/jffs2/jffs2_nand_1pass.c index ce80a43fa1..e5c2a7dd41 100644 --- a/fs/jffs2/jffs2_nand_1pass.c +++ b/fs/jffs2/jffs2_nand_1pass.c @@ -1,6 +1,6 @@ #include <common.h> -#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) +#if defined(CONFIG_NEW_NAND_CODE) && (CONFIG_COMMANDS & CFG_CMD_JFFS2) #include <malloc.h> #include <linux/stat.h> @@ -12,12 +12,12 @@ #include "jffs2_nand_private.h" -#define NODE_CHUNK 1024 /* size of memory allocation chunk in b_nodes */ +#define NODE_CHUNK 1024 /* size of memory allocation chunk in b_nodes */ /* Debugging switches */ #undef DEBUG_DIRENTS /* print directory entry list after scan */ #undef DEBUG_FRAGMENTS /* print fragment list after scan */ -#undef DEBUG /* enable debugging messages */ +#undef DEBUG /* enable debugging messages */ #ifdef DEBUG # define DEBUGF(fmt,args...) printf(fmt ,##args) @@ -25,7 +25,6 @@ # define DEBUGF(fmt,args...) #endif -static int nanddev = -1; /* nand device of current partition */ static nand_info_t *nand; /* Compression names */ @@ -385,10 +384,10 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino) continue; if (jDir->version == version && inode != 0) { - /* I'm pretty sure this isn't legal */ + /* I'm pretty sure this isn't legal */ putstr(" ** ERROR ** "); -// putnstr(jDir->name, jDir->nsize); -// putLabeledWord(" has dup version =", version); +/* putnstr(jDir->name, jDir->nsize); */ +/* putLabeledWord(" has dup version =", version); */ } inode = jDir->ino; version = jDir->version; @@ -574,15 +573,15 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino) /* we need to search all and return the inode with the highest version */ for (jDir = (struct b_dirent *)pL->dir.listHead; jDir; jDir = jDir->next) { if (ino == jDir->ino) { - if (jDir->version < version) + if (jDir->version < version) continue; if (jDir->version == version && jDirFoundType) { - /* I'm pretty sure this isn't legal */ + /* I'm pretty sure this isn't legal */ putstr(" ** ERROR ** "); -// putnstr(jDir->name, jDir->nsize); -// putLabeledWord(" has dup version (resolve) = ", -// version); +/* putnstr(jDir->name, jDir->nsize); */ +/* putLabeledWord(" has dup version (resolve) = ", */ +/* version); */ } jDirFoundType = jDir->type; @@ -686,12 +685,6 @@ jffs2_1pass_rescan_needed(struct part_info *part) return 1; } -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) - if (nanddev != (int)part->usr_priv - 1) { - DEBUGF ("rescan: nand device changed\n"); - return -1; - } -#endif /* defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) */ /* FIXME */ #if 0 /* but suppose someone reflashed a partition at the same offset... */ @@ -806,10 +799,8 @@ jffs2_1pass_build_lists(struct part_info * part) u32 counterF = 0; u32 counterN = 0; -#if defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) - nanddev = (int)part->usr_priv - 1; - nand = &nand_info[nanddev]; -#endif /* defined(CONFIG_JFFS2_NAND) && (CONFIG_COMMANDS & CFG_CMD_NAND) */ + struct mtdids *id = part->dev->id; + nand = nand_info + id->num; /* if we are building a list we need to refresh the cache. */ jffs_init_1pass_list(part); @@ -993,7 +984,7 @@ jffs2_1pass_load(char *dest, struct part_info * part, const char *fname) long ret = 0; u32 inode; - if (! (pl = jffs2_get_list(part, "load"))) + if (! (pl = jffs2_get_list(part, "load"))) return 0; if (! (inode = jffs2_1pass_search_inode(pl, fname, 1))) { @@ -1025,7 +1016,7 @@ jffs2_1pass_info(struct part_info * part) struct b_lists *pl; int i; - if (! (pl = jffs2_get_list(part, "info"))) + if (! (pl = jffs2_get_list(part, "info"))) return 0; jffs2_1pass_fill_info(pl, &info); diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h index c2b69fb2dd..648a10dd92 100644 --- a/include/asm-arm/io.h +++ b/include/asm-arm/io.h @@ -58,6 +58,14 @@ extern void __raw_readsl(unsigned int addr, void *data, int longlen); #define __raw_readw(a) __arch_getw(a) #define __raw_readl(a) __arch_getl(a) +#define writeb(v,a) __arch_putb(v,a) +#define writew(v,a) __arch_putw(v,a) +#define writel(v,a) __arch_putl(v,a) + +#define readb(a) __arch_getb(a) +#define readw(a) __arch_getw(a) +#define readl(a) __arch_getl(a) + /* * The compiler seems to be incapable of optimising constants * properly. Spell it out to the compiler in some cases. diff --git a/include/configs/netstar.h b/include/configs/netstar.h new file mode 100644 index 0000000000..30d2654732 --- /dev/null +++ b/include/configs/netstar.h @@ -0,0 +1,265 @@ +/* + * (C) Copyright 2005 2N TELEKOMUNIKACE, Ladislav Michl + * + * Configuation settings for the TI OMAP NetStar board. + * + * 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 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include <configs/omap1510.h> + +/* + * High Level Configuration Options + * (easy to change) + */ +#define CONFIG_ARM925T 1 /* This is an arm925t CPU */ +#define CONFIG_OMAP 1 /* in a TI OMAP core */ +#define CONFIG_OMAP1510 1 /* which is in a 5910 */ + +/* Input clock of PLL */ +#define CONFIG_SYS_CLK_FREQ 150000000 /* 150MHz input clock */ +#define CONFIG_XTAL_FREQ 12000000 + +#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */ + +#define CONFIG_MISC_INIT_R /* There is nothing to really init */ +#define BOARD_LATE_INIT /* but we flash the LEDs here */ + +#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */ +#define CONFIG_SETUP_MEMORY_TAGS 1 +#define CONFIG_INITRD_TAG 1 + +#define CFG_DEVICE_NULLDEV 1 /* enable null device */ +#define CONFIG_SILENT_CONSOLE 1 /* enable silent startup */ + +/* + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ +#define PHYS_SDRAM_1 0x10000000 /* SDRAM Bank #1 */ +#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */ + +/* + * FLASH organization + */ +#define CFG_FLASH_BASE PHYS_FLASH_1 +#define CFG_MAX_FLASH_BANKS 1 +#if (PHYS_SDRAM_1_SIZE == SZ_32M) +/*#if 1*/ +#define CFG_FLASH_CFI /* Flash is CFI conformant */ +#define CFG_FLASH_CFI_DRIVER /* Use the common driver */ +#define CFG_FLASH_EMPTY_INFO +#define CFG_MAX_FLASH_SECT 128 +#else +#define PHYS_FLASH_1_SIZE SZ_1M +#define CFG_MAX_FLASH_SECT 19 +#define CFG_FLASH_ERASE_TOUT (5*CFG_HZ) /* in ticks */ +#define CFG_FLASH_WRITE_TOUT (5*CFG_HZ) +#endif + +#define CFG_MONITOR_BASE PHYS_FLASH_1 +#define CFG_MONITOR_LEN SZ_256K + +/* + * Environment settings + */ +#define CFG_ENV_IS_IN_FLASH +#define ENV_IS_SOLITARY +#define CFG_ENV_ADDR 0x4000 +#define CFG_ENV_SIZE SZ_8K +#define CFG_ENV_SECT_SIZE SZ_8K +#define CFG_ENV_ADDR_REDUND 0x6000 +#define CFG_ENV_SIZE_REDUND CFG_ENV_SIZE +#define CONFIG_ENV_OVERWRITE + +/* + * Size of malloc() pool + */ +#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ +/* XXX #define CFG_MALLOC_LEN (SZ_64K - CFG_GBL_DATA_SIZE)*/ +#define CFG_MALLOC_LEN SZ_4M + +/* + * The stack size is set up in start.S using the settings below + */ +/* XXX #define CONFIG_STACKSIZE SZ_8K /XXX* regular stack */ +#define CONFIG_STACKSIZE SZ_1M /* regular stack */ + +/* + * Hardware drivers + */ +#define CONFIG_DRIVER_SMC91111 +#define CONFIG_SMC91111_BASE 0x04000300 + +/* + * NS16550 Configuration + */ +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE (-4) +#define CFG_NS16550_CLK (CONFIG_XTAL_FREQ) /* can be 12M/32Khz or 48Mhz */ +#define CFG_NS16550_COM1 OMAP1510_UART1_BASE /* uart1 */ + +#define CONFIG_CONS_INDEX 1 +#define CONFIG_BAUDRATE 115200 +#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } + +/*#define CONFIG_SKIP_RELOCATE_UBOOT*/ +/*#define CONFIG_SKIP_LOWLEVEL_INIT */ + +/* + * NAND flash + */ +#define CFG_MAX_NAND_DEVICE 1 +#define CFG_NAND_BASE 0x04000000 + (2 << 23) +#define CONFIG_NEW_NAND_CODE + +/* + * JFFS2 partitions (mtdparts command line support) + */ +#define CONFIG_JFFS2_CMDLINE +#define MTDIDS_DEFAULT "nor0=omapflash.0,nand0=omapnand.0" +#define MTDPARTS_DEFAULT "mtdparts=omapflash.0:8k@16k(env),8k(r_env),448k@576k(u-boot);omapnand.0:48M(rootfs0),48M(rootfs1),-(data)" + +#if 0 +#define CONFIG_COMMANDS (CFG_CMD_BDI | \ + CFG_CMD_BOOTD | \ + CFG_CMD_DHCP | \ + CFG_CMD_ENV | \ + CFG_CMD_FLASH | \ + CFG_CMD_IMI | \ + CFG_CMD_LOADB | \ + CFG_CMD_NET | \ + CFG_CMD_MEMORY | \ + CFG_CMD_PING | \ + CFG_CMD_RUN) + +#else +#define CONFIG_COMMANDS (CFG_CMD_BDI | \ + CFG_CMD_BOOTD | \ + CFG_CMD_DHCP | \ + CFG_CMD_ENV | \ + CFG_CMD_FLASH | \ + CFG_CMD_NAND | \ + CFG_CMD_IMI | \ + CFG_CMD_JFFS2 | \ + CFG_CMD_LOADB | \ + CFG_CMD_NET | \ + CFG_CMD_MEMORY | \ + CFG_CMD_PING | \ + CFG_CMD_RUN) + +#define CONFIG_JFFS2_NAND 1 /* jffs2 on nand support */ +#endif + +#define CONFIG_BOOTP_MASK CONFIG_BOOTP_DEFAULT +#define CONFIG_LOOPW + +/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ +#include <cmd_confdefs.h> + +#define CONFIG_BOOTDELAY 3 +#define CONFIG_ZERO_BOOTDELAY_CHECK /* allow to break in always */ +#undef CONFIG_BOOTARGS /* the boot command will set bootargs*/ +#define CFG_AUTOLOAD "n" /* No autoload */ +#define CONFIG_BOOTCOMMAND "run nboot" +#define CONFIG_PREBOOT "run setup" +#define CONFIG_EXTRA_ENV_SETTINGS \ + "setup=setenv bootargs console=ttyS0,$baudrate " \ + "$mtdparts\0" \ + "ospart=0\0" \ + "setpart=" \ + "if test -n $swapos; then " \ + "if test $ospart -eq 0; then chpart nand0,1; else chpart nand0,0; fi; "\ + "setenv swapos; saveenv; " \ + "else " \ + "chpart nand0,$ospart; " \ + "fi\0" \ + "nfsargs=setenv bootargs $bootargs " \ + "ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname::off " \ + "nfsroot=$rootpath root=/dev/nfs\0" \ + "flashargs=run setpart;setenv bootargs $bootargs " \ + "root=/dev/mtdblock$partition ro " \ + "rootfstype=jffs2\0" \ + "initrdargs=setenv bootargs $bootargs " \ + "ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname::off\0" \ + "iboot=bootp;run initrdargs;tftp;bootm\0" \ + "fboot=run flashargs;fsload /boot/uImage;bootm\0" \ + "nboot=bootp;run nfsargs;tftp;bootm\0" + +#if 0 /* feel free to disable for development */ +#define CONFIG_AUTOBOOT_KEYED /* Enable password protection */ +#define CONFIG_AUTOBOOT_PROMPT "\nNetStar PBX - boot in %d sec...\n" +#define CONFIG_AUTOBOOT_DELAY_STR "R" /* 1st "password" */ +#define CONFIG_BOOT_RETRY_TIME 30 +#endif + +/* + * Miscellaneous configurable options + */ +#define CFG_LONGHELP /* undef to save memory */ +#define CFG_PROMPT "# " /* Monitor Command Prompt */ +#define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ + +#define CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#define CONFIG_AUTO_COMPLETE + +#define CFG_MEMTEST_START PHYS_SDRAM_1 +#define CFG_MEMTEST_END PHYS_SDRAM_1 + PHYS_SDRAM_1_SIZE + +#undef CFG_CLKS_IN_HZ /* everything, incl board info, in Hz */ + +#define CFG_LOAD_ADDR PHYS_SDRAM_1 + 0x400000 /* default load address */ + +/* The 1510 has 3 timers, they can be driven by the RefClk (12Mhz) or by DPLL1. + * This time is further subdivided by a local divisor. + */ +#define CFG_TIMERBASE OMAP1510_TIMER1_BASE +#define CFG_PVT 7 /* 2^(pvt+1), divide by 256 */ +#define CFG_HZ ((CONFIG_SYS_CLK_FREQ)/(2 << CFG_PVT)) + +#define OMAP5910_DPLL_DIV 1 +#define OMAP5910_DPLL_MUL ((CONFIG_SYS_CLK_FREQ * \ + (1 << OMAP5910_DPLL_DIV)) / CONFIG_XTAL_FREQ) + +#define OMAP5910_ARM_PER_DIV 2 /* CKL/4 */ +#define OMAP5910_LCD_DIV 2 /* CKL/4 */ +#define OMAP5910_ARM_DIV 0 /* CKL/1 */ +#define OMAP5910_DSP_DIV 0 /* CKL/1 */ +#define OMAP5910_TC_DIV 1 /* CKL/2 */ +#define OMAP5910_DSP_MMU_DIV 1 /* CKL/2 */ +#define OMAP5910_ARM_TIM_SEL 1 /* CKL used for MPU timers */ + +#define OMAP5910_ARM_EN_CLK 0x03d6 /* 0000 0011 1101 0110b Clock Enable */ +#define OMAP5910_ARM_CKCTL ((OMAP5910_ARM_PER_DIV) | \ + (OMAP5910_LCD_DIV << 2) | \ + (OMAP5910_ARM_DIV << 4) | \ + (OMAP5910_DSP_DIV << 6) | \ + (OMAP5910_TC_DIV << 8) | \ + (OMAP5910_DSP_MMU_DIV << 10) | \ + (OMAP5910_ARM_TIM_SEL << 12)) + +#endif /* __CONFIG_H */ diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h index afe96b59cb..3d1d416810 100644 --- a/include/linux/mtd/mtd-abi.h +++ b/include/linux/mtd/mtd-abi.h @@ -1,7 +1,7 @@ /* * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $ * - * Portions of MTD ABI definition which are shared by kernel and user space + * Portions of MTD ABI definition which are shared by kernel and user space */ #ifndef __MTD_ABI_H__ @@ -27,17 +27,17 @@ struct mtd_oob_buf { #define MTD_OTHER 14 #define MTD_UNKNOWN 15 -#define MTD_CLEAR_BITS 1 // Bits can be cleared (flash) -#define MTD_SET_BITS 2 // Bits can be set -#define MTD_ERASEABLE 4 // Has an erase function -#define MTD_WRITEB_WRITEABLE 8 // Direct IO is possible -#define MTD_VOLATILE 16 // Set for RAMs -#define MTD_XIP 32 // eXecute-In-Place possible -#define MTD_OOB 64 // Out-of-band data (NAND flash) -#define MTD_ECC 128 // Device capable of automatic ECC -#define MTD_NO_VIRTBLOCKS 256 // Virtual blocks not allowed +#define MTD_CLEAR_BITS 1 /* Bits can be cleared (flash) */ +#define MTD_SET_BITS 2 /* Bits can be set */ +#define MTD_ERASEABLE 4 /* Has an erase function */ +#define MTD_WRITEB_WRITEABLE 8 /* Direct IO is possible */ +#define MTD_VOLATILE 16 /* Set for RAMs */ +#define MTD_XIP 32 /* eXecute-In-Place possible */ +#define MTD_OOB 64 /* Out-of-band data (NAND flash) */ +#define MTD_ECC 128 /* Device capable of automatic ECC */ +#define MTD_NO_VIRTBLOCKS 256 /* Virtual blocks not allowed */ -// Some common devices / combinations of capabilities +/* Some common devices / combinations of capabilities */ #define MTD_CAP_ROM 0 #define MTD_CAP_RAM (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE) #define MTD_CAP_NORFLASH (MTD_CLEAR_BITS|MTD_ERASEABLE) @@ -45,31 +45,31 @@ struct mtd_oob_buf { #define MTD_WRITEABLE (MTD_CLEAR_BITS|MTD_SET_BITS) -// Types of automatic ECC/Checksum available -#define MTD_ECC_NONE 0 // No automatic ECC available -#define MTD_ECC_RS_DiskOnChip 1 // Automatic ECC on DiskOnChip -#define MTD_ECC_SW 2 // SW ECC for Toshiba & Samsung devices +/* Types of automatic ECC/Checksum available */ +#define MTD_ECC_NONE 0 /* No automatic ECC available */ +#define MTD_ECC_RS_DiskOnChip 1 /* Automatic ECC on DiskOnChip */ +#define MTD_ECC_SW 2 /* SW ECC for Toshiba & Samsung devices */ /* ECC byte placement */ -#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended) -#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode) -#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme -#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read) -#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default +#define MTD_NANDECC_OFF 0 /* Switch off ECC (Not recommended) */ +#define MTD_NANDECC_PLACE 1 /* Use the given placement in the structure (YAFFS1 legacy mode) */ +#define MTD_NANDECC_AUTOPLACE 2 /* Use the default placement scheme */ +#define MTD_NANDECC_PLACEONLY 3 /* Use the given placement in the structure (Do not store ecc result on read) */ +#define MTD_NANDECC_AUTOPL_USR 4 /* Use the given autoplacement scheme rather than using the default */ struct mtd_info_user { uint8_t type; uint32_t flags; - uint32_t size; // Total size of the MTD + uint32_t size; /* Total size of the MTD */ uint32_t erasesize; - uint32_t oobblock; // Size of OOB blocks (e.g. 512) - uint32_t oobsize; // Amount of OOB data per block (e.g. 16) + uint32_t oobblock; /* Size of OOB blocks (e.g. 512) */ + uint32_t oobsize; /* Amount of OOB data per block (e.g. 16) */ uint32_t ecctype; uint32_t eccsize; }; struct region_info_user { - uint32_t offset; /* At which this region starts, + uint32_t offset; /* At which this region starts, * from the beginning of the MTD */ uint32_t erasesize; /* For this region */ uint32_t numblocks; /* Number of blocks in this region */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 9ef4cced5e..13e90803a1 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -1,4 +1,4 @@ -/* +/* * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $ * * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al. @@ -46,7 +46,7 @@ struct mtd_erase_region_info { struct mtd_info { u_char type; u_int32_t flags; - u_int32_t size; // Total size of the MTD + u_int32_t size; /* Total size of the MTD */ /* "Major" erase size for the device. Naïve users may take this * to be the only erase size available, or may use the more detailed @@ -54,25 +54,25 @@ struct mtd_info { */ u_int32_t erasesize; - u_int32_t oobblock; // Size of OOB blocks (e.g. 512) - u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) - u_int32_t oobavail; // Number of bytes in OOB area available for fs + u_int32_t oobblock; /* Size of OOB blocks (e.g. 512) */ + u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */ + u_int32_t oobavail; /* Number of bytes in OOB area available for fs */ u_int32_t ecctype; u_int32_t eccsize; - - // Kernel-only stuff starts here. + + /* Kernel-only stuff starts here. */ char *name; int index; - // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) + /* oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) */ struct nand_oobinfo oobinfo; /* Data for variable erase regions. If numeraseregions is zero, - * it means that the whole device has erasesize as given above. + * it means that the whole device has erasesize as given above. */ int numeraseregions; - struct mtd_erase_region_info *eraseregions; + struct mtd_erase_region_info *eraseregions; /* This really shouldn't be here. It can go away in 2.5 */ u_int32_t bank_size; @@ -95,10 +95,10 @@ struct mtd_info { int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - /* - * Methods to access the protection register area, present in some + /* + * Methods to access the protection register area, present in some * flash devices. The user data is one time programmable but the - * factory data is read only. + * factory data is read only. */ int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); @@ -109,14 +109,14 @@ struct mtd_info { #if 0 /* kvec-based read/write methods. We need these especially for NAND flash, with its limited number of write cycles per erase. - NB: The 'count' parameter is the number of _vectors_, each of + NB: The 'count' parameter is the number of _vectors_, each of which contains an (ofs, len) tuple. */ int (*readv) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen); - int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, + int (*readv_ecc) (struct mtd_info *mtd, struct kvec *vecs, unsigned long count, loff_t from, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); - int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, + int (*writev_ecc) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); #endif /* Sync */ @@ -179,7 +179,7 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, #define MTD_WRITEECC(mtd, args...) (*(mtd->write_ecc))(mtd, args) #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) -#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) +#define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) #ifdef CONFIG_MTD_PARTITIONS diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9a0108f78c..065e1cb4e4 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -24,7 +24,7 @@ * bat later if I did something naughty. * 10-11-2000 SJH Added private NAND flash structure for driver * 10-24-2000 SJH Added prototype for 'nand_scan' function - * 10-29-2001 TG changed nand_chip structure to support + * 10-29-2001 TG changed nand_chip structure to support * hardwarespecific function for accessing control lines * 02-21-2002 TG added support for different read/write adress and * ready/busy line access function @@ -36,14 +36,14 @@ * CONFIG_MTD_NAND_ECC_JFFS2 is not set * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC * - * 08-29-2002 tglx nand_chip structure: data_poi for selecting + * 08-29-2002 tglx nand_chip structure: data_poi for selecting * internal / fs-driver buffer * support for 6byte/512byte hardware ECC * read_ecc, write_ecc extended for different oob-layout * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, * NAND_YAFFS_OOB * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL - * Split manufacturer and device ID structures + * Split manufacturer and device ID structures * * 02-08-2004 tglx added option field to nand structure for chip anomalities * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id @@ -120,7 +120,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_STATUS_READY 0x40 #define NAND_STATUS_WP 0x80 -/* +/* * Constants for ECC_MODES */ @@ -162,12 +162,12 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_CACHEPRG 0x00000008 /* Chip has copy back function */ #define NAND_COPYBACK 0x00000010 -/* AND Chip which has 4 banks and a confusing page / block +/* AND Chip which has 4 banks and a confusing page / block * assignment. See Renesas datasheet for further information */ #define NAND_IS_AND 0x00000020 /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ -#define NAND_4PAGE_ARRAY 0x00000040 +#define NAND_4PAGE_ARRAY 0x00000040 /* Options valid for Samsung large page devices */ #define NAND_SAMSUNG_LP_OPTIONS \ @@ -186,8 +186,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* Use a flash based bad block table. This option is passed to the * default bad block table function. */ #define NAND_USE_FLASH_BBT 0x00010000 -/* The hw ecc generator provides a syndrome instead a ecc value on read - * This can only work if we have the ecc bytes directly behind the +/* The hw ecc generator provides a syndrome instead a ecc value on read + * This can only work if we have the ecc bytes directly behind the * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ #define NAND_HWECC_SYNDROME 0x00020000 @@ -218,7 +218,7 @@ struct nand_chip; #if 0 /** * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices - * @lock: protection lock + * @lock: protection lock * @active: the mtd device which holds the controller currently */ struct nand_hw_control { @@ -229,8 +229,8 @@ struct nand_hw_control { /** * struct nand_chip - NAND Private Flash Chip Data - * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device - * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device + * @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the flash device + * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the flash device * @read_byte: [REPLACEABLE] read one byte from the chip * @write_byte: [REPLACEABLE] write one byte to the chip * @read_word: [REPLACEABLE] read one word from the chip @@ -253,7 +253,7 @@ struct nand_hw_control { * be provided if a hardware ECC is available * @erase_cmd: [INTERN] erase command write function, selectable due to AND support * @scan_bbt: [REPLACEABLE] function to scan bad block table - * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines + * @eccmode: [BOARDSPECIFIC] mode of ecc, see defines * @eccsize: [INTERN] databytes used per ecc-calculation * @eccbytes: [INTERN] number of ecc bytes per ecc-calculation step * @eccsteps: [INTERN] number of ecc calculation steps per page @@ -265,7 +265,7 @@ struct nand_hw_control { * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock * @bbt_erase_shift: [INTERN] number of address bits in a bbt entry * @chip_shift: [INTERN] number of address bits in one chip - * @data_buf: [INTERN] internal buffer for one page + oob + * @data_buf: [INTERN] internal buffer for one page + oob * @oob_buf: [INTERN] oob buffer for one eraseblock * @oobdirty: [INTERN] indicates that oob_buf must be reinitialized * @data_poi: [INTERN] pointer to a data buffer @@ -280,20 +280,20 @@ struct nand_hw_control { * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash lookup * @bbt_md: [REPLACEABLE] bad block table mirror descriptor - * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan + * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices * @priv: [OPTIONAL] pointer to private chip date */ - + struct nand_chip { void __iomem *IO_ADDR_R; void __iomem *IO_ADDR_W; - + u_char (*read_byte)(struct mtd_info *mtd); void (*write_byte)(struct mtd_info *mtd, u_char byte); u16 (*read_word)(struct mtd_info *mtd); void (*write_word)(struct mtd_info *mtd, u16 word); - + void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); @@ -358,7 +358,7 @@ struct nand_chip { * @name: Identify the device type * @id: device ID code * @pagesize: Pagesize in bytes. Either 256 or 512 or 0 - * If the pagesize is 0, then the real pagesize + * If the pagesize is 0, then the real pagesize * and the eraseize are determined from the * extended id bytes in the chip * @erasesize: Size of an erase block in the flash device. @@ -387,7 +387,7 @@ struct nand_manufacturers { extern struct nand_flash_dev nand_flash_ids[]; extern struct nand_manufacturers nand_manuf_ids[]; -/** +/** * struct nand_bbt_descr - bad block table descriptor * @options: options for this descriptor * @pages: the page(s) where we find the bbt, used with option BBT_ABSPAGE @@ -398,14 +398,14 @@ extern struct nand_manufacturers nand_manuf_ids[]; * @version: version read from the bbt page during scan * @len: length of the pattern, if 0 no pattern check is performed * @maxblocks: maximum number of blocks to search for a bbt. This number of - * blocks is reserved at the end of the device where the tables are + * blocks is reserved at the end of the device where the tables are * written. * @reserved_block_code: if non-0, this pattern denotes a reserved (rather than * bad) block in the stored bbt - * @pattern: pattern to identify bad block table or factory marked good / + * @pattern: pattern to identify bad block table or factory marked good / * bad blocks, can be NULL, if len = 0 * - * Descriptor for the bad block table marker and the descriptor for the + * Descriptor for the bad block table marker and the descriptor for the * pattern which identifies good and bad blocks. The assumption is made * that the pattern and the version count are always located in the oob area * of the first block. diff --git a/include/nand.h b/include/nand.h index 29580da4fe..6dbaa42402 100644 --- a/include/nand.h +++ b/include/nand.h @@ -24,7 +24,7 @@ #ifndef _NAND_H_ #define _NAND_H_ -#include <linux_compat.h> +#include <linux/mtd/compat.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> |