diff options
author | Daniel Schaeffer <daniel.schaeffer@timesys.com> | 2009-10-08 13:37:39 -0400 |
---|---|---|
committer | Daniel Schaeffer <daniel.schaeffer@timesys.com> | 2009-10-08 13:37:39 -0400 |
commit | 0d01165105959ee63c492cfe0bb3acf903c611a8 (patch) | |
tree | 96122c5137d3e23cbe462b9fc65bb4de7859e829 | |
parent | d2788bb87bc499f7a04970766f0972683ce6f002 (diff) |
This patch originally from LogicPD OMAP35x Release 1.6.1 Original Patch Name: u-boot-2009.03-lv-som-09-yaffs2.patch
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | board/omap3/lv_som/lv_som.c | 3 | ||||
-rw-r--r-- | common/cmd_nand.c | 15 | ||||
-rw-r--r-- | cpu/arm_cortexa8/omap3/board.c | 20 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_util.c | 276 | ||||
-rw-r--r-- | drivers/mtd/nand/omap_gpmc.c | 22 | ||||
-rw-r--r-- | include/asm-arm/arch-omap3/omap_gpmc.h | 15 | ||||
-rw-r--r-- | include/configs/omap3_lv_som.h | 46 | ||||
-rw-r--r-- | lib_arm/board.c | 6 |
10 files changed, 395 insertions, 11 deletions
@@ -276,7 +276,7 @@ LIBBOARD = board/$(BOARDDIR)/lib$(BOARD).a LIBBOARD := $(addprefix $(obj),$(LIBBOARD)) # Add GCC lib -PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc +PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc -lgcc_eh # The "tools" are needed early, so put this first # Don't include stuff already done in $(LIBS) diff --git a/board/omap3/lv_som/lv_som.c b/board/omap3/lv_som/lv_som.c index 2d6967a8e7..ebcedcc01b 100644 --- a/board/omap3/lv_som/lv_som.c +++ b/board/omap3/lv_som/lv_som.c @@ -225,6 +225,9 @@ int misc_init_r(void) fix_flash_sync(); + /* Switch to Hardware ECC mode */ + omap_nand_switch_ecc(1); + dieid_num_r(); return 0; } diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 04b3200e57..f657172b9f 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -381,6 +381,19 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) else ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr); + } else if (s != NULL && !strcmp(s, ".yaffs")) { + nand_write_options_t opts; + memset(&opts, 0, sizeof(opts)); + opts.buffer = (u_char *) addr; + opts.length = size; + opts.offset = off; + opts.pad = 0; + opts.blockalign = 1; + opts.quiet = quiet; + opts.writeoob = 1; + opts.autoplace = 1; + opts.forceyaffs = 1; + nand_write_opts(nand, &opts); } else if (s != NULL && !strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { @@ -475,6 +488,8 @@ U_BOOT_CMD(nand, 5, 1, do_nand, "nand write - addr off|partition size\n" " read/write 'size' bytes starting at offset 'off'\n" " to/from memory address 'addr', skipping bad blocks.\n" + "nand write[.yaffs] - addr off size - write `size' byte yaffs2 image\n" + " at offset `off' 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" diff --git a/cpu/arm_cortexa8/omap3/board.c b/cpu/arm_cortexa8/omap3/board.c index 7bb3e284b5..a591082992 100644 --- a/cpu/arm_cortexa8/omap3/board.c +++ b/cpu/arm_cortexa8/omap3/board.c @@ -36,6 +36,7 @@ #include <asm/io.h> #include <asm/arch/sys_proto.h> #include <asm/arch/mem.h> +#include <nand.h> extern omap3_sysinfo sysinfo; @@ -319,6 +320,25 @@ void abort(void) *****************************************************************************/ static int do_switch_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { + struct mtd_info *mtd; + struct nand_chip *nand; + + /* the following commands operate on the current device */ + if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || + !nand_info[nand_curr_device].name) { + puts("\nno devices available\n"); + return 1; + } + mtd = &nand_info[nand_curr_device]; + nand = mtd->priv; + + if (argc == 1) { + if (nand->ecc.mode == NAND_ECC_SOFT) + printf("Software ECC\n"); + else + printf("Hardware ECC\n"); + return 0; + } if (argc != 2) goto usage; if (strncmp(argv[1], "hw", 2) == 0) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d33fee242f..4af3f50f3d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1993,6 +1993,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int)to, (int)ops->ooblen); + if (ops->mode == MTD_OOB_AUTO) len = chip->ecc.layout->oobavail; else diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 6ba52b30c0..34b9755858 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -204,7 +204,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) } /* XXX U-BOOT XXX */ -#if 0 #define MAX_PAGE_SIZE 2048 #define MAX_OOB_SIZE 64 @@ -217,26 +216,48 @@ static unsigned char oob_buf[MAX_OOB_SIZE]; /* OOB layouts to pass into the kernel as default */ static struct nand_ecclayout none_ecclayout = { - .useecc = MTD_NANDECC_OFF, + .eccbytes = 0, }; static struct nand_ecclayout jffs2_ecclayout = { - .useecc = MTD_NANDECC_PLACE, .eccbytes = 6, - .eccpos = { 0, 1, 2, 3, 6, 7 } + .eccpos = {0, 1, 2, 3, 6, 7}, + .oobfree = { {8, 8} }, + .oobavail = 8, }; static struct nand_ecclayout yaffs_ecclayout = { - .useecc = MTD_NANDECC_PLACE, .eccbytes = 6, - .eccpos = { 8, 9, 10, 13, 14, 15} + .eccpos = { 8, 9, 10, 13, 14, 15}, + .oobfree = { {0, 4}, {6, 2}, {11, 2} }, + .oobavail = 8, }; -static struct nand_ecclayout autoplace_ecclayout = { - .useecc = MTD_NANDECC_AUTOPLACE +#ifdef CONFIG_OMAP3_LV_SOM +/* ecclayout for OMAP3_LV_SOM, using omap HW ecc */ +static struct nand_ecclayout yaffs2_ecclayout = { + .eccbytes = 12, + .eccpos = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, + .oobfree = { { 1, 1}, { 14, 50} }, + .oobavail = 51, +}; +#else +/* ecclayout on chips that page_size = 2K, byte 0,1 is bad block marker */ +static struct nand_ecclayout yaffs2_ecclayout = { + .eccbytes = 24, + .eccpos = { + 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} }, + .oobavail = 38, }; #endif +static struct nand_ecclayout autoplace_ecclayout = { + .oobavail = 38, +}; + /* XXX U-BOOT XXX */ #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK @@ -534,6 +555,245 @@ int nand_write_skip_bad(nand_info_t *nand, size_t offset, size_t *length, } /** + * nand_write_opts: - write image to NAND flash with support for various options + * + * @param meminfo NAND device to erase + * @param opts write options (@see nand_write_options) + * @return 0 in case of success + * + * This code is ported from nandwrite.c from Linux mtd utils by + * Steven J. Hill and Thomas Gleixner. + */ +int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts) +{ + int imglen = 0; + int pagelen; + int baderaseblock; + int blockstart = -1; + loff_t offs; + int readlen; + int ecclayout_changed = 0; + int percent_complete = -1; + struct nand_ecclayout *old_ecclayout; + struct nand_chip *chip = meminfo->priv; + ulong mtdoffset = opts->offset; + ulong erasesize_blockalign; + u_char *buffer = opts->buffer; + size_t written; + int result; + + if (opts->pad && opts->writeoob) { + printf("Can't pad when oob data is present.\n"); + return -1; + } + + /* set erasesize to specified number of blocks - to match + * jffs2 (virtual) block size */ + if (opts->blockalign == 0) + erasesize_blockalign = meminfo->erasesize; + else + erasesize_blockalign = meminfo->erasesize * opts->blockalign; + + /* make sure device page sizes are valid */ + if (!(meminfo->oobsize == 16 && meminfo->writesize == 512) + && !(meminfo->oobsize == 8 && meminfo->writesize == 256) + && !(meminfo->oobsize == 64 && meminfo->writesize == 2048)) { + printf("Unknown flash (not normal NAND)\n"); + return -1; + } + + /* read the current ecclayout */ + old_ecclayout = meminfo->ecclayout; + + /* write without ecc? */ + if (opts->noecc) { + meminfo->ecclayout = &none_ecclayout; + ecclayout_changed = 1; + } + + /* autoplace ECC? */ + if (opts->autoplace && (chip->ecc.mode != MTD_NANDECC_AUTOPLACE)) { + + meminfo->ecclayout = &autoplace_ecclayout, + ecclayout_changed = 1; + } + + /* force OOB layout for jffs2 or yaffs? */ + if (opts->forcejffs2 || opts->forceyaffs) { + struct nand_ecclayout *oobsel = + opts->forcejffs2 ? &jffs2_ecclayout : &yaffs2_ecclayout; + + if (meminfo->oobsize == 8) { + if (opts->forceyaffs) { + printf("YAFSS cannot operate on " + "256 Byte page size\n"); + goto restoreoob; + } + } + + meminfo->ecclayout = oobsel; + ecclayout_changed = 1; + } + + /* get image length */ + imglen = opts->length; + pagelen = meminfo->writesize + + ((opts->writeoob != 0) ? meminfo->oobsize : 0); + + /* check, if file is pagealigned */ + if ((!opts->pad) && ((imglen % pagelen) != 0)) { + printf("Input block length is not page aligned\n"); + goto restoreoob; + } + + /* check, if length fits into device */ + if (((imglen / pagelen) * meminfo->writesize) + > (meminfo->size - opts->offset)) { + printf("Image %d bytes, NAND page %d bytes, " + "OOB area %u bytes, device size %u bytes\n", + imglen, pagelen, meminfo->writesize, meminfo->size); + printf("Input block does not fit into device\n"); + goto restoreoob; + } + + if (!opts->quiet) + printf("\n"); + + /* get data from input and write to the device */ + while (imglen && (mtdoffset < meminfo->size)) { + + WATCHDOG_RESET(); + + /* + * new eraseblock, check for bad block(s). Stay in the + * loop to be sure if the offset changes because of + * a bad block, that the next block that will be + * written to is also checked. Thus avoiding errors if + * the block(s) after the skipped block(s) is also bad + * (number of blocks depending on the blockalign + */ + while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) { + blockstart = mtdoffset & (~erasesize_blockalign+1); + offs = blockstart; + baderaseblock = 0; + + /* check all the blocks in an erase block for + * bad blocks */ + do { + int ret = meminfo->block_isbad(meminfo, offs); + + if (ret < 0) { + printf("Bad block check failed\n"); + goto restoreoob; + } + if (ret == 1) { + baderaseblock = 1; + if (!opts->quiet) + printf("\rBad block at 0x%lx " + "in erase block from " + "0x%x will be skipped\n", + (long) offs, + blockstart); + } + + if (baderaseblock) { + mtdoffset = blockstart + + erasesize_blockalign; + } + offs += erasesize_blockalign + / opts->blockalign; + } while (offs < blockstart + erasesize_blockalign); + } + + readlen = meminfo->writesize; + if (opts->pad && (imglen < readlen)) { + readlen = imglen; + memset(data_buf + readlen, 0xff, + meminfo->writesize - readlen); + } + + /* read page data from input memory buffer */ + memcpy(data_buf, buffer, readlen); + buffer += readlen; + + if (opts->writeoob) { + /* read OOB data from input memory block, exit + * on failure */ + memcpy(oob_buf, buffer, meminfo->oobsize); + buffer += meminfo->oobsize; + + struct mtd_oob_ops ops = { + .mode = MTD_OOB_AUTO, + .len = meminfo->writesize, + .retlen = 0, + .ooblen = meminfo->ecclayout->oobavail, + .oobretlen = 0, + .ooboffs = 0, + .datbuf = NULL, + .oobbuf = oob_buf, + }; + + result = meminfo->write_oob(meminfo, mtdoffset, &ops); + + if (result != 0) { + printf("\nMTD writeoob failure: %d\n", + result); + goto restoreoob; + } + imglen -= meminfo->oobsize; + } + + /* write out the page data */ + result = meminfo->write(meminfo, + mtdoffset, + meminfo->writesize, + &written, + (unsigned char *) &data_buf); + + if (result != 0) { + printf("writing NAND page at offset 0x%lx failed\n", + mtdoffset); + goto restoreoob; + } + imglen -= readlen; + + if (!opts->quiet) { + int percent = (int) + ((unsigned long long) + (opts->length-imglen) * 100 + / opts->length); + /* output progress message only at whole percent + * steps to reduce the number of messages printed + * on (slow) serial consoles + */ + if (percent != percent_complete) { + printf("\rWriting data at 0x%lx " + "-- %3d%% complete.", + mtdoffset, percent); + percent_complete = percent; + } + } + + mtdoffset += meminfo->writesize; + } + + if (!opts->quiet) + printf("\n"); + +restoreoob: + if (ecclayout_changed) + meminfo->ecclayout = old_ecclayout; + + if (imglen > 0) { + printf("Data did not fit into device(imglen %d), due to bad blocks\n", imglen); + return -1; + } + + /* return happy */ + return 0; +} + +/** * nand_read_skip_bad: * * Read image from NAND flash. diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 5f8ed3984d..b60fa958f9 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -150,7 +150,9 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat, */ if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000)) return 0; +#if 0 printf("Error: Bad compare! failed\n"); +#endif /* detected 2 bit error */ return -1; } @@ -269,12 +271,12 @@ void omap_nand_switch_ecc(int32_t hardware) nand->ecc.correct = omap_correct_data; nand->ecc.calculate = omap_calculate_ecc; omap_hwecc_init(nand); - printf("HW ECC selected\n"); + printf("NAND: HW ECC selected\n"); } else { nand->ecc.mode = NAND_ECC_SOFT; /* Use mtd default settings */ nand->ecc.layout = NULL; - printf("SW ECC selected\n"); + printf("NAND: SW ECC selected\n"); } /* Update NAND handling after ECC mode switch */ @@ -298,6 +300,17 @@ void omap_nand_switch_ecc(int32_t hardware) * nand_scan about special functionality. See the defines for further * explanation */ + +#ifdef CONFIG_OMAP3_LV_SOM +static uint8_t omap3_lv_som_scan_ff_pattern[] = { 0xff, 0xff }; +static struct nand_bbt_descr omap3_lv_som_largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 1, /* to match LoLo, only first byte is looked at */ + .pattern = omap3_lv_som_scan_ff_pattern +}; +#endif + int board_nand_init(struct nand_chip *nand) { int32_t gpmc_config = 0; @@ -349,5 +362,10 @@ int board_nand_init(struct nand_chip *nand) /* Default ECC mode */ nand->ecc.mode = NAND_ECC_SOFT; +#ifdef CONFIG_OMAP3_LV_SOM + /* Use our specific bad-block definition (first byte only) */ + nand->badblock_pattern = &omap3_lv_som_largepage_memorybased; +#endif + return 0; } diff --git a/include/asm-arm/arch-omap3/omap_gpmc.h b/include/asm-arm/arch-omap3/omap_gpmc.h index bd22bce837..601f4b45ad 100644 --- a/include/asm-arm/arch-omap3/omap_gpmc.h +++ b/include/asm-arm/arch-omap3/omap_gpmc.h @@ -48,14 +48,29 @@ /* Large Page x16 NAND device Layout */ #ifdef GPMC_NAND_ECC_LP_x16_LAYOUT +#ifdef CONFIG_OMAP3_LV_SOM +/* OMAP3_LV_SOM only uses first byte for bad block marker, not first + half-word */ #define GPMC_NAND_HW_ECC_LAYOUT {\ .eccbytes = 12,\ .eccpos = {2, 3, 4, 5, 6, 7, 8, 9,\ 10, 11, 12, 13},\ .oobfree = {\ + {.offset = 1,\ + .length = 1 }, \ {.offset = 14,\ .length = 50 } } \ } +#else +#define GPMC_NAND_HW_ECC_LAYOUT {\ + .eccbytes = 12,\ + .eccpos = {2, 3, 4, 5, 6, 7, 8, 9,\ + 10, 11, 12, 13},\ + .oobfree = {\ + {.offset = 14,\ + .length = 50 } } \ +} +#endif #endif /* Small Page x8 NAND device Layout */ diff --git a/include/configs/omap3_lv_som.h b/include/configs/omap3_lv_som.h index 4733ab51cd..3a038d4757 100644 --- a/include/configs/omap3_lv_som.h +++ b/include/configs/omap3_lv_som.h @@ -114,6 +114,7 @@ #define CONFIG_CMD_NET /* bootp, tftpboot, rarpboot */ #define CONFIG_CMD_PING /* ping */ #define CONFIG_CMD_DHCP /* dhcp */ +#define CONFIG_CMD_ASKENV /* askenv */ /*---------------------------------------------------------------------------- * SMSC9115 Ethernet from SMSC9118 family @@ -174,6 +175,25 @@ /* Environment information */ #define CONFIG_BOOTDELAY 10 +#if 1 +#define CONFIG_EXTRA_ENV_SETTINGS \ + "display=15\0" \ + "loadaddr=0x81000000\0" \ + "rootfsaddr=0x81300000\0" \ + "consoledev=ttyS0\0" \ + "rootpath=/opt/nfs-exports/ltib-omap\0" \ + "ramdisksize=89000\0" \ + "nfsoptions=,wsize=1500,rsize=1500\0" \ + "nfsboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=/dev/nfs rw nfsroot=${serverip}:${rootpath}${nfsoptions} ip=dhcp ${otherbootargs};tftpboot ${loadaddr} uImage;bootm ${loadaddr}\0" \ + "ramboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=/dev/ram rw ramdisk_size=${ramdisksize} ${otherbootargs};tftpboot ${loadaddr} uImage;tftpboot ${rootfsaddr} rootfs.ext2.gz.uboot;bootm ${loadaddr} ${rootfsaddr}\0" \ + "xipboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=/dev/ram rw ramdisk_size=${ramdisksize} ${otherbootargs};bootm ${loadaddr} ${rootfsaddr}\0" \ + "mtdboot=setenv bootargs display=${display} console=${consoledev},${baudrate} root=/dev/mtdblock3 rw ${otherbootargs};tftpboot ${loadaddr} uImage;bootm ${loadaddr}\0" + +#define CONFIG_BOOTCOMMAND "run xipboot" + +#else + +// Beagle ENV_SETTINGS #define CONFIG_EXTRA_ENV_SETTINGS \ "loadaddr=0x82000000\0" \ "console=ttyS2,115200n8\0" \ @@ -199,6 +219,7 @@ "nand read ${loadaddr} 280000 400000; " \ "bootm ${loadaddr}\0" \ +// Beagle BOOTCOMMAND #define CONFIG_BOOTCOMMAND \ "if mmcinit; then " \ "if run loadbootscript; then " \ @@ -210,8 +231,28 @@ "fi; " \ "fi; " \ "else run nandboot; fi" +#endif +#define CONFIG_PREBOOT \ + "echo ======================NOTICE============================;" \ + "echo This is the first time that you boot up this board. You are;" \ + "echo required to set a valid display for your LCD panel.;" \ + "echo Enter the display number of the LCD panel(none for no LCD panel);" \ + "echo Pick one of:;" \ + "echo 2 == LQ121S1DG31 TFT SVGA (12.1) Sharp;" \ + "echo 3 == LQ036Q1DA01 TFT QVGA (3.6) Sharp w/ASIC;" \ + "echo 5 == LQ064D343 TFT VGA (6.4) Sharp;" \ + "echo 7 == LQ10D368 TFT VGA (10.4) Sharp;" \ + "echo 15 == LQ043T1DG01 TFT WQVGA (4.3) Sharp;" \ + "echo MAKE SURE YOUR DISPLAY IS CORRECTLY ENTERED!;" \ + "askenv display 'Please enter your LCD display number:' 2;" \ + "printenv display;" \ + "setenv preboot;" \ + "saveenv;" + +#define CONFIG_CMDLINE_EDITING 1 #define CONFIG_AUTO_COMPLETE 1 + /* * Miscellaneous configurable options */ @@ -298,6 +339,11 @@ #define CONFIG_ENV_OFFSET boot_flash_off #define CONFIG_ENV_ADDR boot_flash_env_addr +#if 0 +#define CONFIG_MTD_DEBUG 1 +#define CONFIG_MTD_DEBUG_VERBOSE 2 // Loud MTD debug messages +#endif + /*----------------------------------------------------------------------- * CFI FLASH driver setup */ diff --git a/lib_arm/board.c b/lib_arm/board.c index 3dfaec01b4..c7b77e521b 100644 --- a/lib_arm/board.c +++ b/lib_arm/board.c @@ -353,6 +353,12 @@ void start_armboot (void) #if defined(CONFIG_CMD_NAND) puts ("NAND: "); nand_init(); /* go init the NAND */ + +#ifdef CONFIG_OMAP3_LV_SOM + /* Switch to Hardware ECC mode */ + omap_nand_switch_ecc(1); +#endif + #endif #if defined(CONFIG_CMD_ONENAND) |