int saveenv(void) { env_t env_new; ssize_t len; char *res; int ret = 0; nand_erase_options_t nand_erase_options; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; res = (char *)&env_new.data; len = hexport_r(&env_htab, '\0', &res, ENV_SIZE); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; } env_new.crc = crc32(0, env_new.data, ENV_SIZE); env_new.flags = ++env_flags; /* increase the serial */ if(gd->env_valid == 1) { puts("Erasing redundant NAND...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to redundant NAND... "); ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new); } else { puts("Erasing NAND...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to NAND... "); ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new); } if (ret) { puts("FAILED!\n"); return 1; } puts("done\n"); gd->env_valid = (gd->env_valid == 2 ? 1 : 2); return ret; }
int saveenv(void) { struct mtd_info * mtd=get_mtd_device_nm(NAND_NORMAL_NAME); if (IS_ERR(mtd)) return 1; struct aml_nand_chip *aml_chip = mtd_to_nand_chip(mtd); size_t total; size_t offset = CONFIG_ENV_OFFSET; int ret = 0; nand_erase_options_t nand_erase_options; offset = (1024 * aml_chip->page_size * (mtd->writesize / (aml_chip->plane_num * aml_chip->page_size))); if (CONFIG_ENV_OFFSET < offset) _debug ("env define offset must larger than 1024 page size: %d \n", mtd->writesize); else offset = CONFIG_ENV_OFFSET; env_ptr->flags++; total = CONFIG_ENV_SIZE; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; if(gd->env_valid == 1) { puts ("Erasing redundant Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; if (nand_erase_opts(mtd, &nand_erase_options)) return 1; puts ("Writing to redundant Nand... "); ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr); } else { puts ("Erasing Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET; if (nand_erase_opts(mtd, &nand_erase_options)) return 1; puts ("Writing to Nand... "); ret = writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr); } if (ret) { puts("FAILED!\n"); return 1; } puts ("done\n"); gd->env_valid = (gd->env_valid == 2 ? 1 : 2); return ret; }
/* * The legacy NAND code saved the environment in the first NAND device i.e., * nand_dev_desc + 0. This is also the behaviour using the new NAND code. */ int writeenv(size_t offset, u_char *buf) { size_t end = offset + CONFIG_ENV_RANGE; size_t amount_saved = 0; size_t blocksize, len; u_char *char_ptr; blocksize = nand_info[0].erasesize; len = min(blocksize, CONFIG_ENV_SIZE); while (amount_saved < CONFIG_ENV_SIZE && offset < end) { if (nand_block_isbad(&nand_info[0], offset)) { offset += blocksize; } else { char_ptr = &buf[amount_saved]; if (nand_write(&nand_info[0], offset, &len, char_ptr)) return 1; offset += blocksize; amount_saved += len; } } if (amount_saved != CONFIG_ENV_SIZE) return 1; return 0; } #ifdef CONFIG_ENV_OFFSET_REDUND int saveenv(void) { int ret = 0; nand_erase_options_t nand_erase_options; env_ptr->flags++; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; if(gd->env_valid == 1) { puts ("Erasing redundant Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to redundant Nand... "); ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr); } else { puts ("Erasing Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to Nand... "); ret = writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr); } if (ret) { puts("FAILED!\n"); return 1; } puts ("done\n"); gd->env_valid = (gd->env_valid == 2 ? 1 : 2); return ret; } #else /* ! CONFIG_ENV_OFFSET_REDUND */ int saveenv(void) { int ret = 0; nand_erase_options_t nand_erase_options; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; nand_erase_options.offset = CONFIG_ENV_OFFSET; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; puts ("Erasing Nand...\n"); if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to Nand... "); if (writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr)) { puts("FAILED!\n"); return 1; } puts ("done\n"); return ret; }
static int dfu_flush_medium_nand(struct dfu_entity *dfu) { int ret = 0; /* in case of ubi partition, erase rest of the partition */ if (dfu->data.nand.ubi) { nand_info_t *nand; nand_erase_options_t opts; if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[nand_curr_device].name) { printf("%s: invalid nand device\n", __func__); return -1; } nand = &nand_info[nand_curr_device]; memset(&opts, 0, sizeof(opts)); opts.offset = dfu->data.nand.start + dfu->offset + dfu->bad_skip; opts.length = dfu->data.nand.start + dfu->data.nand.size - opts.offset; ret = nand_erase_opts(nand, &opts); if (ret != 0) printf("Failure erase: %d\n", ret); } return ret; }
/* * The legacy NAND code saved the environment in the first NAND device i.e., * nand_dev_desc + 0. This is also the behaviour using the new NAND code. */ int writeenv(size_t offset, u_char *buf) { size_t end = offset + CONFIG_ENV_RANGE; size_t amount_saved = 0; size_t blocksize, len; u_char *char_ptr; blocksize = nand_info[0].erasesize; len = min(blocksize, CONFIG_ENV_SIZE); while (amount_saved < CONFIG_ENV_SIZE && offset < end) { if (nand_block_isbad(&nand_info[0], offset)) { offset += blocksize; } else { char_ptr = &buf[amount_saved]; if (nand_write(&nand_info[0], offset, &len, char_ptr)) return 1; offset += blocksize; amount_saved += len; } } if (amount_saved != CONFIG_ENV_SIZE) return 1; return 0; } #ifdef CONFIG_ENV_OFFSET_REDUND int saveenv(void) { int ret = 0; nand_erase_options_t nand_erase_options; env_ptr->flags++; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; if(gd->env_valid == 1) { puts ("Erasing redundant Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to redundant Nand... "); ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr); } else { puts ("Erasing Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to Nand... "); ret = writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr); } if (ret) { puts("FAILED!\n"); return 1; } puts ("done\n"); gd->env_valid = (gd->env_valid == 2 ? 1 : 2); return ret; } #else /* ! CONFIG_ENV_OFFSET_REDUND */ int saveenv(void) { int ret = 0; nand_erase_options_t nand_erase_options; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; nand_erase_options.offset = CONFIG_ENV_OFFSET; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; /* we will erase the block anyway, so prevent warning */ if (nand_erase_options.length < nand_info[0].erasesize) nand_erase_options.length = nand_info[0].erasesize; puts ("Erasing Nand...\n"); if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to Nand... "); if (writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr)) { puts("FAILED!\n"); return 1; } puts ("done\n"); return ret; }
static int upgrade_erase_nftl_part() { char str[128]; nand_erase_options_t opts; int error, nand_scrub_flag = 0, i, blk_num; size_t pagesize, blocksize, len; loff_t nftl_erase_addr; struct mtd_info *mtd = nand_info[nand_curr_device]; if (mtd == NULL) { printk("mtd name err: %s\n", mtd->name); return -1; } pagesize = mtd->writesize; blocksize = mtd->erasesize; len = pagesize; u_char temp_buf[pagesize]; nftl_erase_addr = 0; blk_num = mtd->size / mtd->erasesize; printk("nftl_erase_addr %llx blks: %d\n", nftl_erase_addr, blk_num); for (i=0; i<blk_num; i++) { memset(temp_buf, 0xff, 16); error = nand_read(mtd, nftl_erase_addr + i*blocksize, &len, temp_buf); if ((error) && (error != -EUCLEAN)) { printf("read data from nand error: %d\n",error); //continue; } if(!strncmp(temp_buf, "amlnftl", 7) || !strncmp((temp_buf + pagesize / 2), "amlnftl", 7)) { nand_scrub_flag = 1; break; } } printk("nand_scrub_flag: %d\n", nand_scrub_flag); if (nand_scrub_flag) { i = 0; memset(&opts, 0, sizeof(opts)); opts.offset = 0; opts.length = mtd->size; opts.quiet = 1; opts.scrub = 1; nand_erase_opts(mtd, &opts); sprintf(str, "fatload mmc 0:%d ${loadaddr} ${bootloader_path}", (i + 1)); UPGRADE_DPRINT("command: %s\n", str); run_command (str, 0); run_command ("nand rom_protect off", 0); run_command ("nand rom_write ${loadaddr} ${bootloader_start} ${bootloader_size}", 0); run_command ("nand rom_protect on", 0); } return 0; }
int saveenv(void) { int ret = 0; nand_erase_options_t nand_erase_options; env_ptr->flags++; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; if(gd->env_valid == 1) { puts ("Erasing redundant Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to redundant Nand... "); ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr); } else { puts ("Erasing Nand...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts ("Writing to Nand... "); ret = writeenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr); } if (ret) { puts("FAILED!\n"); return 1; } puts ("done\n"); gd->env_valid = (gd->env_valid == 2 ? 1 : 2); return ret; }
/* Write nboot loader image into the nand flash */ int nand_burn_nboot_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int filesize; MV_U32 ret = 0; extern char console_buffer[]; nand_info_t *nand = &nand_info[0]; nand_erase_options_t er_opts; nand_write_options_t wr_opts; load_addr = CFG_LOAD_ADDR; if(argc == 2) { copy_filename (BootFile, argv[1], sizeof(BootFile)); } else { copy_filename (BootFile, "nboot.bin", sizeof(BootFile)); printf("using default file \"nboot.bin\" \n"); } if ((filesize = NetLoop(TFTP)) < 0) return 0; printf("Erase %d - %d ... ",CFG_NBOOT_BASE, CFG_NBOOT_LEN); memset(&er_opts, 0, sizeof(er_opts)); er_opts.offset = CFG_NBOOT_BASE; er_opts.length = CFG_NBOOT_LEN; er_opts.quiet = 1; nand_erase_opts(nand, &er_opts); //nand_erase(nand_dev_desc + 0, CFG_NBOOT_BASE, CFG_NBOOT_LEN , 0); printf("\nCopy to Nand Flash... "); memset(&wr_opts, 0, sizeof(wr_opts)); wr_opts.buffer = (u_char*) load_addr; wr_opts.length = CFG_NBOOT_LEN; wr_opts.offset = CFG_NBOOT_BASE; /* opts.forcejffs2 = 1; */ wr_opts.pad = 1; wr_opts.blockalign = 1; wr_opts.quiet = 1; ret = nand_write_opts(nand, &wr_opts); /* ret = nand_rw(nand_dev_desc + 0, NANDRW_WRITE | NANDRW_JFFS2, CFG_NBOOT_BASE, CFG_NBOOT_LEN, &total, (u_char*)0x100000); */ if (ret) printf("Error - NAND burn faild!\n"); else printf("\ndone\n"); return 1; }
static int eraseNandFlash(int nOffsetAddr, int nLength) { int nRet = -1; nand_info_t *nand = &nand_info[nand_curr_device]; nand_erase_options_t opts; memset(&opts, 0, sizeof(opts)); opts.offset = nOffsetAddr; opts.length = nLength; opts.jffs2 = 0; opts.quiet = 1; opts.spread = 0; nRet = nand_erase_opts(nand, &opts); printf("Erase NAND flash 0x%x 0x%x %s\n", nOffsetAddr, nLength, nRet?"ERROR":"OK"); return (nRet?FALSE:TRUE ); }
/******************************************************************************* Reset environment variables. ********************************************************************************/ extern flash_info_t flash_info[]; /* info for FLASH chips */ int resetenv_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { #if defined(CFG_NAND_BOOT) printf("Erase Env parameters offset 0x%x... ",CFG_ENV_OFFSET); nand_info_t *nand = &nand_info[0]; nand_erase_options_t er_opts; memset(&er_opts, 0, sizeof(er_opts)); er_opts.offset = CFG_ENV_OFFSET; er_opts.length = CFG_ENV_SECT_SIZE; er_opts.quiet = 1; nand_erase_opts(nand, &er_opts); //nand_erase(nand_dev_desc + 0, CFG_ENV_OFFSET, CFG_ENV_SECT_SIZE, 0); printf("done"); #else MV_U32 env_sec = flash_in_which_sec(&flash_info[BOOT_FLASH_INDEX], CFG_ENV_ADDR); if (env_sec == -1) { printf("Could not find ENV Sector\n"); return 0; } printf("Un-Protect ENV Sector\n"); flash_protect(FLAG_PROTECT_CLEAR, CFG_ENV_ADDR,CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, &flash_info[BOOT_FLASH_INDEX]); printf("Erase sector %d ... ",env_sec); flash_erase(&flash_info[BOOT_FLASH_INDEX], env_sec, env_sec); printf("done\nProtect ENV Sector\n"); flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR,CFG_ENV_ADDR + CFG_ENV_SECT_SIZE - 1, &flash_info[BOOT_FLASH_INDEX]); #endif /* defined(CFG_NAND_BOOT) */ printf("\nWarning: Default Environment Variables will take effect Only after RESET \n\n"); return 1; }
static int erase_and_write_env(const struct nand_env_location *location, u_char *env_new) { struct mtd_info *mtd; int ret = 0; mtd = get_nand_dev_by_index(0); if (!mtd) return 1; printf("Erasing %s...\n", location->name); if (nand_erase_opts(mtd, &location->erase_opts)) return 1; printf("Writing to %s... ", location->name); ret = writeenv(location->erase_opts.offset, env_new); puts(ret ? "FAILED!\n" : "OK\n"); return ret; }
static int _fb_nand_erase(struct mtd_info *mtd, struct part_info *part) { nand_erase_options_t opts; int ret; memset(&opts, 0, sizeof(opts)); opts.offset = part->offset; opts.length = part->size; opts.quiet = 1; printf("Erasing blocks 0x%llx to 0x%llx\n", part->offset, part->offset + part->size); ret = nand_erase_opts(mtd, &opts); if (ret) return ret; printf("........ erased 0x%llx bytes from '%s'\n", part->size, part->name); return 0; }
/* * The legacy NAND code saved the environment in the first NAND device i.e., * nand_dev_desc + 0. This is also the behaviour using the new NAND code. */ int writeenv(size_t offset, u_char *buf) { size_t end = offset + CONFIG_ENV_RANGE; size_t amount_saved = 0; size_t blocksize, len; u_char *char_ptr; blocksize = nand_info[0].erasesize; len = min(blocksize, CONFIG_ENV_SIZE); while (amount_saved < CONFIG_ENV_SIZE && offset < end) { if (nand_block_isbad(&nand_info[0], offset)) { offset += blocksize; } else { char_ptr = &buf[amount_saved]; if (nand_write(&nand_info[0], offset, &len, char_ptr)) return 1; offset += blocksize; amount_saved += len; } } if (amount_saved != CONFIG_ENV_SIZE) return 1; return 0; } #ifdef CONFIG_ENV_OFFSET_REDUND static unsigned char env_flags; int saveenv(void) { env_t env_new; ssize_t len; char *res; int ret = 0; nand_erase_options_t nand_erase_options; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; res = (char *)&env_new.data; len = hexport_r(&env_htab, '\0', &res, ENV_SIZE); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; } env_new.crc = crc32(0, env_new.data, ENV_SIZE); env_new.flags = ++env_flags; /* increase the serial */ if(gd->env_valid == 1) { puts("Erasing redundant NAND...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to redundant NAND... "); ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new); } else { puts("Erasing NAND...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to NAND... "); ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new); } if (ret) { puts("FAILED!\n"); return 1; } puts("done\n"); gd->env_valid = (gd->env_valid == 2 ? 1 : 2); return ret; } #else /* ! CONFIG_ENV_OFFSET_REDUND */ int saveenv(void) { int ret = 0; env_t env_new; ssize_t len; char *res; nand_erase_options_t nand_erase_options; nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 0; nand_erase_options.jffs2 = 0; nand_erase_options.scrub = 0; nand_erase_options.offset = CONFIG_ENV_OFFSET; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; res = (char *)&env_new.data; len = hexport_r(&env_htab, '\0', &res, ENV_SIZE); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; } env_new.crc = crc32(0, env_new.data, ENV_SIZE); puts("Erasing Nand...\n"); if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to Nand... "); if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) { puts("FAILED!\n"); return 1; } puts("done\n"); return ret; }
/* * The legacy NAND code saved the environment in the first NAND device i.e., * nand_dev_desc + 0. This is also the behaviour using the new NAND code. */ int writeenv(size_t offset, u_char *buf) { uint64_t end = offset + CONFIG_ENV_RANGE; uint64_t amount_saved = 0; uint64_t blocksize, len; u_char *char_ptr; blocksize = nand_info[0].erasesize; len = min(blocksize, CONFIG_ENV_SIZE); offset = CONFIG_ENV_OFFSET; while (amount_saved < CONFIG_ENV_SIZE && offset < end) { if (nand_block_isbad(&nand_info[0], offset)) { offset += blocksize; } else { char_ptr = &buf[amount_saved]; if (nand_write(&nand_info[0], offset, (size_t *)&len, char_ptr)) return 1; offset += blocksize; amount_saved += len; } } if (amount_saved != CONFIG_ENV_SIZE) return 1; return 0; } #ifdef CONFIG_ENV_OFFSET_REDUND static unsigned char env_flags; int saveenv(void) { env_t env_new; ssize_t len; char *res; int ret = 0; nand_erase_options_t nand_erase_options; memset(&nand_erase_options, 0, sizeof(nand_erase_options)); nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 1; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; res = (char *)&env_new.data; len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; } env_new.crc = crc32(0, env_new.data, ENV_SIZE); env_new.flags = ++env_flags; /* increase the serial */ if (gd->env_valid == 1) { puts("Erasing redundant NAND...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET_REDUND; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to redundant NAND... "); ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *)&env_new); } else { puts("Erasing NAND...\n"); nand_erase_options.offset = CONFIG_ENV_OFFSET; if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to NAND... "); ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new); } if (ret) { puts("FAILED!\n"); return 1; } puts("done\n"); gd->env_valid = gd->env_valid == 2 ? 1 : 2; return ret; } #else /* ! CONFIG_ENV_OFFSET_REDUND */ int saveenv(void) { int ret = 0; ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1); ssize_t len; char *res; nand_erase_options_t nand_erase_options; memset(&nand_erase_options, 0, sizeof(nand_erase_options)); nand_erase_options.length = CONFIG_ENV_RANGE; nand_erase_options.quiet = 1; nand_erase_options.offset = CONFIG_ENV_OFFSET; if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE) return 1; res = (char *)&env_new->data; len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; } env_new->crc = crc32(0, env_new->data, ENV_SIZE); puts("Erasing Nand...\n"); if (nand_erase_opts(&nand_info[0], &nand_erase_options)) return 1; puts("Writing to Nand... "); if (writeenv(CONFIG_ENV_OFFSET, (u_char *)env_new)) { puts("FAILED!\n"); return 1; } puts("done\n"); return ret; }
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int i, dev, ret = 0; ulong addr, off; size_t size; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET int quiet = CONFIG_SYS_NAND_QUIET; #else int quiet = 0; #endif const char *quiet_str = getenv("quiet"); /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; if (strcmp(cmd, "info") == 0) { putc('\n'); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { if (nand_info[i].name) nand_print_info(i); } return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); if ((nand_curr_device < 0) || (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE)) puts("no devices available\n"); else nand_print_info(nand_curr_device); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); if (dev < 0 || dev >= CONFIG_SYS_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; #ifdef CONFIG_SYS_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(nand_info[dev].priv, dev); #endif 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 && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && strcmp(cmd, "biterr") != 0 && strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 #ifdef CONFIG_ENV_OFFSET_OOB && strcmp(cmd, "env.oob") != 0 #endif ) goto usage; #ifdef CONFIG_ENV_OFFSET_OOB /* this command operates only on the first nand device */ if (strcmp(cmd, "env.oob") == 0) { return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1); } #endif /* 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; } 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(" %08lx\n", off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) { nand_erase_options_t opts; /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > 2 && !strcmp("clean", argv[2]); int o = clean ? 3 : 2; int scrub = !strcmp(cmd, "scrub"); printf("\nNAND %s: ", scrub ? "scrub" : "erase"); /* skip first two or three arguments, look for offset and size */ if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) return 1; memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; if (scrub) { puts("Warning: " "scrub option will erase all factory set " "bad blocks!\n" " " "There is no reliable way to recover them.\n" " " "Use this command only for testing purposes " "if you\n" " " "are sure of what you are doing!\n" "\nReally scrub this NAND flash? <y/N>\n"); if (getc() == 'y') { puts("y"); if (getc() == '\r') opts.scrub = 1; else { puts("scrub aborted\n"); return -1; } } else { puts("scrub aborted\n"); return -1; } } ret = nand_erase_opts(nand, &opts); 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(nand, off, 1); else ret = nand_dump(nand, off, 0); return ret == 0 ? 1 : 0; } if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { int read; if (argc < 4) goto usage; addr = (ulong)simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) return 1; s = strchr(cmd, '.'); if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr); } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = size, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else {
void set_env_funcptrs(void) { #ifdef CONFIG_SOC_HAYDN env_init = serialflash_env_init ; saveenv = serialflash_saveenv ; env_get_char_spec = serialflash_env_get_char_spec ; env_relocate_spec = serialflash_env_relocate_spec ; #elif (defined(CONFIG_SOC_MOZART) || defined(CONFIG_SOC_BEETHOVEN)) unsigned long val = inl(BOOTING_DEVICE_INFO); int sdbootSucess = 0 ; #ifdef CONFIG_CMD_MMC if(val == SYSCTRL_DATA_IN_SD && SD_Card_Detect(0)) { printf( " Boot Storage : SD Card\n" ) ; gd->env_valid = 0 ;//We always use default envs when booting from SD. env_init = sd_env_init ; saveenv = sd_saveenv ; env_get_char_spec = sd_env_get_char_spec ; env_relocate_spec = sd_env_relocate_spec ; //check if real sd boot if(SD_Read(MAGIC_SD_ADDR, MAGIC_DATA_SIZE, MAGIC_DRAM_ADDR) != 0) { printf("[ERR] SD-Read fails!\n") ; sdbootSucess = 0 ; goto SDBOOT_FAIL; } if((v_inl(MAGIC_DRAM_ADDR) != MAGIC_NUM0) || (v_inl(MAGIC_DRAM_ADDR+4) != MAGIC_NUM1)) { printf(" !! MAGIC# of SD Card is wrong\n") ; printf(" !! Find other Boot Storage..\n\n") ; sdbootSucess = 0 ; goto SDBOOT_FAIL ; } printf(" SD Card has correct Magic#.\n") ; printf(" SD Boot Sucessfully.\n\n") ; update_default_envs_ifsdboot() ; sdbootSucess = 1 ; #ifdef SDAUTOBURN_FLOW_FROMSD printf(" ****** Auto Burn Flow ******\n") ; printf(" Step 1. Copy data(size 0x%08x) from 0x%08x of SD to 0x%08x of DRAM\n", AUTOBURN_DATASIZE, AUTOBURN_SDADDR, AUTOBURN_DRAMADDR) ; SD_Read(AUTOBURN_SDADDR, AUTOBURN_DATASIZE, AUTOBURN_DRAMADDR) ; if(AUTOBURN_FLASHTYPE == AUTOBURN_SPIFLASH) { printf(" Step 2. Write data from 0x%08x of DRAM to 0x%08x of SPI FLASH\n", AUTOBURN_DRAMADDR, AUTOBURN_FLASHADDR) ; autoburn_sf = spi_flash_probe(0, 0, CONFIG_SF_DEFAULT_SPEED, CONFIG_DEFAULT_SPI_MODE); spi_flash_erase(autoburn_sf, AUTOBURN_FLASHADDR, AUTOBURN_DATASIZE, 0) ; spi_flash_write(autoburn_sf, AUTOBURN_FLASHADDR, AUTOBURN_DATASIZE, AUTOBURN_DRAMADDR, 0) ; printf(" Done\n") ; outl(0xFFF, 0x49000004); } else if(AUTOBURN_FLASHTYPE == AUTOBURN_NANDFLASH) { printf(" Step 3. Write data from 0x%08x of DRAM to 0x%08x of NAND FLASH\n", AUTOBURN_DRAMADDR, AUTOBURN_FLASHADDR) ; nand_info_t *mtd ; mtd = &nand_info[0] ; nand_erase_options_t opts; memset(&opts, 0, sizeof(opts)); opts.offset = AUTOBURN_FLASHADDR; opts.length = AUTOBURN_DATASIZE; //opts.jffs2 = clean; opts.jffs2 = 0;//[patch] we do not allow jffs2 in our u-boot opts.quiet = 0; opts.all = 1 ; unsigned long datasize = AUTOBURN_DATASIZE ; nand_erase_opts(mtd, &opts) ; //printf("chipsize=%d, blocksize=%d, block#=%d\n", mtd->totalsize, mtd->erasesize, (mtd->totalsize / mtd->erasesize)) ; nand_write_skip_bad(mtd, AUTOBURN_FLASHADDR, &datasize, AUTOBURN_DRAMADDR) ;//100 temporary } #endif //SDAUTOBURN_FLOW_FROMSD } if(sdbootSucess) return ; #endif //CONFIG_CMD_SD SDBOOT_FAIL: if ( val == SYSCTRL_DATA_IN_SERIALFLASH) { printf( " Boot Storage : Serial Flash\n" ) ; env_init = serialflash_env_init ; saveenv = serialflash_saveenv ; env_get_char_spec = serialflash_env_get_char_spec ; env_relocate_spec = serialflash_env_relocate_spec ; } #if defined(CONFIG_CMD_NAND) else if ( val == SYSCTRL_DATA_IN_NANDFLASH) { update_default_envs_ifnfboot() ; printf( " Boot Storage : Nand Flash\n" ) ; env_init = nand_env_init ; saveenv = nand_saveenv ; env_get_char_spec = nand_env_get_char_spec ; env_relocate_spec = nand_env_relocate_spec ; } #endif #endif //CONFIG_SOC_MOZART }
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { int i, dev, ret = 0; uint32_t addr, cmp_addr; uint64_t off; uint64_t size; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET int quiet = CONFIG_SYS_NAND_QUIET; #else int quiet = 0; #endif const char *quiet_str = getenv("quiet"); /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; if (strcmp(cmd, "info") == 0) { for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { if (nand_info[i].name) nand_print_info(i); } return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); if ((nand_curr_device < 0) || (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE)) puts("no devices available\n"); else nand_print_info(nand_curr_device); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); if (dev < 0 || dev >= CONFIG_SYS_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; #ifdef CONFIG_SYS_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(nand_info[dev].priv, dev); #endif 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 && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && strcmp(cmd, "biterr") != 0 && strcmp(cmd, "pattern") != 0 && strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) goto usage; /* 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; } 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(" %12llx\n", off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) { nand_erase_options_t opts; /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > 2 && !strcmp("clean", argv[2]); int o = clean ? 3 : 2; int scrub = !strcmp(cmd, "scrub"); printf("\nNAND %s: ", scrub ? "scrub" : "erase"); /* skip first two or three arguments, look for offset and size */ if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) return 1; memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; if (scrub) { puts("Warning: " "scrub option will erase all factory set " "bad blocks!\n" " " "There is no reliable way to recover them.\n" " " "Use this command only for testing purposes " "if you\n" " " "are sure of what you are doing!\n" "\nReally scrub this NAND flash? <y/N>\n"); if (getc() == 'y' && getc() == '\r') { opts.scrub = 1; } else { puts("scrub aborted\n"); return -1; } } ret = nand_erase_opts(nand, &opts); 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 = simple_strtoull(argv[2], NULL, 16); if (s != NULL && strcmp(s, ".oob") == 0) ret = nand_dump(nand, off, 1); else ret = nand_dump(nand, off, 0); return ret == 0 ? 1 : 0; } if (strncmp(cmd, "pattern", 4) == 0) { int chunk_num; uint64_t offset, chunk64, cmp64; nand_erase_options_t opts; memset(&opts, 0, sizeof(opts)); // nand pattern addr cmp_addr chunk_size // 0 1 2 3 4 if (argc < 5) goto usage; addr = simple_strtoul(argv[2], NULL, 16); cmp_addr = simple_strtoul(argv[3], NULL, 16); chunk64 = simple_strtoull(argv[4], NULL, 16); cmp64 = chunk64; chunk_num = (int) (nand->size / chunk64); printf("NAND size [0x%llx], chunk size [0x%llx], number of chunks [%d]\n", nand->size, chunk64, chunk_num); printf("Erasing all chip...\n"); opts.offset = 0; opts.length = nand->size; opts.jffs2 = 0; opts.quiet = 0; opts.scrub = 0; if (nand_erase_opts(nand, &opts) != 0) { printf("[FAILED]\n"); return 1; } else { printf("[OK]\n"); } offset = 0; while(offset < nand->size) { printf("0x%010llx:", offset); // printf("\tB:"); // if (nand_block_isbad(nand, i*chunk_size & ~(nand->erasesize - 1))) { // printf("[V]\n"); // continue; // } else { // printf("[X]"); // } // size_include_bad = get_len_incl_bad (nand, offset, chunk_size); // opts.offset = offset; // opts.length = size_include_bad; // opts.quiet = 1; // printf("\tE:"); // if (nand_erase_opts(nand, &opts) != 0) { // printf("[X]\n"); // return 1; // } else { // printf("[V]"); // } printf("\tW:"); chunk64 = cmp64; if (nand_write_skip_bad(nand, offset, &chunk64, (u_char *)addr) != 0) { printf("[X]\n"); return 1; } else { printf("[V]"); } printf("\tR:"); chunk64 = cmp64; if (nand_read_skip_bad(nand, offset, &chunk64, (u_char *)cmp_addr) != 0) { printf("[X]\n"); return 1; } else { printf("[V]"); } printf("\tC:"); if (memcmp((void *)addr, (void *)cmp_addr, cmp64) != 0) { printf("[X]\n"); return 1; } else { printf("[V]"); } printf("\n"); if (ctrlc()) { puts ("\nAbort\n"); return (-1); } offset += get_len_incl_bad (nand, offset, cmp64); } printf("NAND Pattern Test PASSED!\n"); return 0; } if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { int read; if (argc < 4) goto usage; addr = simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) return 1; s = strchr(cmd, '.'); if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr); } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (uint8_t *)addr, .ooblen = size, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else {
/******************************************************************************* * mvNandReadWriteTest - Performs read-write test on NAND chip. * * DESCRIPTION: * This routine writes pattern 0x55,0xaa in 16 blocks at offset immediately * after ENV section and reads them back and verifies. * * INPUT: * None. * * OUTPUT: * None. * * RETURN: * Returns 1 on failure, else 0 *******************************************************************************/ int mvNandReadWriteTest(void) { int i,j,ret; int testFlag; unsigned int pageSize; unsigned char rbuf[2048]; nand_write_options_t wr_opts; nand_erase_options_t er_opts; nand_read_options_t rd_opts; testFlag = DIAG_PASS; printf("\tNAND read/write test "); do { pageSize = nand_info[0].oobblock; /***************** ERASE ***********************/ memset(&er_opts, 0, sizeof(er_opts)); er_opts.offset = CFG_ENV_OFFSET + CFG_ENV_SIZE; er_opts.length = pageSize * PAGES_PER_BLOCK * 16; er_opts.quiet = 1; ret = nand_erase_opts(&nand_info[0], &er_opts); if (ret) { printf("\tError: NAND Erase faild!\n"); testFlag = DIAG_FAIL; break; } if(DIAG_PASS != testFlag) { break; } /***************** WRITE ***********************/ memset(&wr_opts, 0, sizeof(wr_opts)); for(i=0; i < pageSize; i=i+2) { wr_opts.buffer[i] = 0x55; wr_opts.buffer[i+1] = 0xaa; } wr_opts.length = pageSize; wr_opts.offset = CFG_ENV_OFFSET + CFG_ENV_SIZE; /* opts.forcejffs2 = 1; */ wr_opts.pad = 1; wr_opts.blockalign = 1; wr_opts.quiet = 1; for(i=0; i < PAGES_PER_BLOCK * 16;i++) { ret = nand_write_opts(&nand_info[0], &wr_opts); if (ret) { printf("\tError: NAND write faild!\n"); testFlag = DIAG_FAIL; break; } wr_opts.offset += pageSize; } if(DIAG_PASS != testFlag) { break; } /**************** READ *************************/ memset(&rd_opts, 0, sizeof(rd_opts)); rd_opts.buffer = rbuf; rd_opts.length = (ulong)pageSize; rd_opts.offset = CFG_ENV_OFFSET + CFG_ENV_SIZE; rd_opts.quiet = 1; for(i=0; i < PAGES_PER_BLOCK * 16;i++) { ret = nand_read_opts(&nand_info[0], &rd_opts); if (ret) { printf("\tError: NAND read faild!\n"); testFlag = DIAG_FAIL; break; } for(j=0; j < pageSize; j=j+4) { if (rbuf[j] != 0x55 && rbuf[j+1] != 0xaa && rbuf[j+2] != 0x55 && rbuf[j+3] != 0xaa) { printf("\tError: Data verify failed\n"); testFlag = DIAG_FAIL; break; } } rd_opts.offset += pageSize; } if(DIAG_PASS != testFlag) { break; } }while(0); printf((testFlag==DIAG_PASS)?"PASSED\n":"FAIL\n"); return testFlag; }
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { int i, dev, ret = 0; ulong addr; loff_t off, size; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET int quiet = CONFIG_SYS_NAND_QUIET; #else int quiet = 0; #endif const char *quiet_str = getenv("quiet"); #if ((defined CONFIG_AML_NAND_KEY) || (defined MX_REVD) || (defined CONFIG_SECURE_NAND)) int chip_num , tmp_chip_num, error; nand = nand_info[nand_curr_device]; struct mtd_info *mtd =nand; struct aml_nand_chip *aml_chip = mtd_to_nand_chip(nand); #endif /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; #ifdef CONFIG_AML_NAND_KEY if (strcmp(cmd, "key") == 0){ aml_chip->key_protect = 1; //force nand key can be erased return 0; } #endif #ifdef CONFIG_SECURE_NAND if (strcmp(cmd, "secure") == 0){ aml_chip->secure_protect = 1; //force nand key can be erased return 0; } #endif #ifdef CONFIG_SECURE_NAND if (strcmp(cmd, "secure") == 0){ aml_chip->secure_protect = 1; //force nand key can be erased return 0; } #endif if(strcmp(cmd, "exist") == 0){ if(nand_info[1]){ printf("nand exist return 0\n"); return 0; } else{ printf("nand exist return 1\n"); return 1; } } #ifdef MX_REVD if (strcmp(cmd, "errstat") == 0){ printk("checking chiprev here\n"); if(aml_chip->err_sts == NAND_CHIP_REVB_HY_ERR){ printk("Must use RevD chip for Hynix 26nm/20nm nand boot without SPI!!!\n"); return NAND_CHIP_REVB_HY_ERR; } return 0; } #endif #ifdef CONFIG_SECURE_NAND if (strcmp(cmd, "secure") == 0){ aml_chip->secure_protect = 1; //force nand key can be erased return 0; } #endif if (strcmp(cmd, "info") == 0) { #ifdef CONFIG_AML_NAND_KEY aml_chip->key_protect = 0; //protect nand key can not be erased #endif #ifdef CONFIG_SECURE_NAND aml_chip->secure_protect = 0; //protect nand secure can not be erased #endif putc('\n'); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { nand = nand_info[i]; if (!nand) { nand_init(); if (!nand) return -1; } if (nand->name) nand_print_info(i); } return 0; } if (strcmp(cmd, "init") == 0) { nand_init(); return 0; } //cmd for nand test , if nand is ok , then trigger power off if (strcmp(cmd, "test") == 0) { int ret=-1; puts("\ntest the nand flash ***\n"); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { nand = nand_info[i]; if (!nand) { ret=nand_test_init(); printf("\n***nand_test_init()in NAND DEVICE %d returned:%d***\n ", i,ret); if (ret) return -1; } } return 0; } if (strcmp(cmd, "scrub_detect") == 0) { if (nand_curr_device < 0 || nand_curr_device >= (CONFIG_SYS_MAX_NAND_DEVICE+2)) { puts("\nno devices available\n"); return 1; } nand = nand_info[nand_curr_device]; aml_nand_stupid_dectect_badblock(nand); return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); if ((nand_curr_device < 0) || (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE)) puts("no devices available\n"); else nand_print_info(nand_curr_device); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); if (dev < 0 || dev >= (CONFIG_SYS_MAX_NAND_DEVICE+1) || !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; #ifdef CONFIG_SYS_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(nand_info[dev]->priv, dev); #endif 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 && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && strcmp(cmd, "biterr") != 0 && strncmp(cmd, "rom_protect", 11) != 0 && strncmp(cmd, "wr_rd_cmp", 9) != 0 && strncmp(cmd, "rom_write", 9) != 0 && (strncmp(cmd, "rom_read", 8) != 0) && strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 && strcmp(cmd, "factory_info") != 0 && strcmp(cmd, "show_para_page")&& strncmp(cmd, "scrub_safe", 10) != 0) //my_ goto usage; /* the following commands operate on the current device */ if (nand_curr_device < 0 || nand_curr_device >= (CONFIG_SYS_MAX_NAND_DEVICE+2)) { puts("\nno devices available\n"); return 1; } nand = nand_info[nand_curr_device]; if (!nand) return -1; 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(" %09llx\n", off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0 || strcmp(cmd, "scrub_safe") == 0) { nand_erase_options_t opts; int argc_cnt = 2; //printk("%s\n", argv[2]); /* if (isstring(argv[2])) { nand = get_mtd_device_nm(argv[2]); if (IS_ERR(nand)){ printf("get nand device err\n"); return 1; } argc_cnt++; } */ /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > argc_cnt && !strcmp("clean", argv[argc_cnt]); if (clean) argc_cnt++; int o = argc_cnt; int scrub = !strncmp(cmd, "scrub",10); int scrub_safe = !strncmp(cmd, "scrub_safe",10); if(scrub_safe) printf("\nNAND %s: ", scrub_safe ? "scrub_safe" : "erase"); else printf("\nNAND %s: ", scrub ? "scrub" : "erase"); if (argv[argc_cnt]) { if(!strcmp(argv[argc_cnt], "whole")) { off = 0; size = nand->size; printf("whole chip.\n"); } } else { /* skip first two or three arguments, look for offset and size */ if ((strcmp(cmd, "erase") == 0) && (argc < 3)) { goto usage; } if ((arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)) { return 1; } } memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; if (scrub) { puts("Warning: " "scrub option will erase all factory set " "bad blocks!\n" " " "There is no reliable way to recover them.\n" " " "Use this command only for testing purposes " "if you\n" " " "are sure of what you are doing!\n" "\nReally scrub this NAND flash? <y/N>\n"); if(nand_protect) { if (getc() == 'y') { puts("y"); if (getc() == '\r') opts.scrub = 1; else { puts("scrub aborted\n"); return -1; } } else { puts("scrub aborted\n"); return -1; } } else { opts.scrub = 1; } } else if(scrub_safe){ puts("Warning: " "scrub_safe option will erase all " "bad blocks except factory bad blocks!\n"); opts.scrub = 2; // indicate scrub_safe } ret = nand_erase_opts(nand, &opts); printf("%s\n", ret ? "ERROR" : "OK"); #ifdef CONFIG_AML_NAND_KEY aml_chip->key_protect = 0; //protect nand key can not be erased #endif #ifdef CONFIG_SECURE_NAND aml_chip->secure_protect = 0; //protect nand secure can not be erased #endif return ret == 0 ? 0 : 1; } if (strncmp(cmd, "dump", 4) == 0) { if (argc < 3) goto usage; s = strchr(cmd, '.'); //off = (loff_t)simple_strtoul(argv[2], NULL, 16); if (!(str2longlong(argv[2], (unsigned long long*)(&off)))) return -1; if (s != NULL && strcmp(s, ".oob") == 0) ret = nand_dump(nand, off, 1); else ret = nand_dump(nand, off, 0); return ret == 0 ? 1 : 0; } if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { int read; if (argc < 4) goto usage; if (isstring(argv[2])) { nand = get_mtd_device_nm(argv[2]); if (IS_ERR(nand)) goto usage; addr = (ulong)simple_strtoul(argv[3], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: %s ", read ? "read" : "write", argv[2]); if (argc == 4) { extern unsigned int get_mtd_size(char *name); off = 0; size = get_mtd_size(argv[2]); } else { if (arg_off_size(argc - 4, argv + 4, nand, &off, &size) != 0) return 1; } } else { addr = (ulong)simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) return 1; } #ifdef CONFIG_AMLROM_NANDBOOT if((read==0) && ((off)<(1024* nand->writesize)) && (nand_curr_device == 0)){ printf("offset 0x%llx in aml-boot area ,abort\n", off); return -1; } #endif s = strchr(cmd, '.'); if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &size, (u_char *)addr, 0); else ret = nand_write_skip_bad(nand, off, &size, (u_char *)addr, 0); } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = size, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else if (!strcmp(s, ".raw")) {
static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count, int read) { int ret = 0; while (count--) { /* Raw access */ mtd_oob_ops_t ops = { .datbuf = (u8 *)addr, .oobbuf = ((u8 *)addr) + nand->writesize, .len = nand->writesize, .ooblen = nand->oobsize, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); if (ret) { printf("%s: error at offset %llx, ret %d\n", __func__, (long long)off, ret); break; } addr += nand->writesize + nand->oobsize; off += nand->writesize; } return ret; } int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int i, ret = 0; ulong addr; loff_t off, size, maxsize; char *cmd, *s; nand_info_t *nand; #ifdef CONFIG_SYS_NAND_QUIET int quiet = CONFIG_SYS_NAND_QUIET; #else int quiet = 0; #endif const char *quiet_str = getenv("quiet"); int dev = nand_curr_device; int repeat = flag & CMD_FLAG_REPEAT; /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; /* Only "dump" is repeatable. */ if (repeat && strcmp(cmd, "dump")) return 0; if (strcmp(cmd, "info") == 0) { putc('\n'); for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { if (nand_info[i].name) nand_print_and_set_info(i); } return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { putc('\n'); if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE) puts("no devices available\n"); else nand_print_and_set_info(dev); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); set_dev(dev); return 0; } #ifdef CONFIG_ENV_OFFSET_OOB /* this command operates only on the first nand device */ if (strcmp(cmd, "env.oob") == 0) return do_nand_env_oob(cmdtp, argc - 1, argv + 1); #endif /* The following commands operate on the current device, unless * overridden by a partition specifier. Note that if somehow the * current device is invalid, it will have to be changed to a valid * one before these commands can run, even if a partition specifier * for another device is to be used. */ if (dev < 0 || dev >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[dev].name) { puts("\nno devices available\n"); return 1; } nand = &nand_info[dev]; if (strcmp(cmd, "bad") == 0) { printf("\nDevice %d bad blocks:\n", dev); for (off = 0; off < nand->size; off += nand->erasesize) if (nand_block_isbad(nand, off)) printf(" %08llx\n", (unsigned long long)off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strncmp(cmd, "erase", 5) == 0 || strncmp(cmd, "scrub", 5) == 0) { nand_erase_options_t opts; /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > 2 && !strcmp("clean", argv[2]); int scrub_yes = argc > 2 && !strcmp("-y", argv[2]); int o = (clean || scrub_yes) ? 3 : 2; int scrub = !strncmp(cmd, "scrub", 5); int spread = 0; int args = 2; const char *scrub_warn = "Warning: " "scrub option will erase all factory set bad blocks!\n" " " "There is no reliable way to recover them.\n" " " "Use this command only for testing purposes if you\n" " " "are sure of what you are doing!\n" "\nReally scrub this NAND flash? <y/N>\n"; if (cmd[5] != 0) { if (!strcmp(&cmd[5], ".spread")) { spread = 1; } else if (!strcmp(&cmd[5], ".part")) { args = 1; } else if (!strcmp(&cmd[5], ".chip")) { args = 0; } else { goto usage; } } /* * Don't allow missing arguments to cause full chip/partition * erases -- easy to do accidentally, e.g. with a misspelled * variable name. */ if (argc != o + args) goto usage; printf("\nNAND %s: ", cmd); /* skip first two or three arguments, look for offset and size */ if (arg_off_size(argc - o, argv + o, &dev, &off, &size, &maxsize) != 0) return 1; nand = &nand_info[dev]; memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; opts.spread = spread; if (scrub) { if (!scrub_yes) puts(scrub_warn); if (scrub_yes) opts.scrub = 1; else if (getc() == 'y') { puts("y"); if (getc() == '\r') opts.scrub = 1; else { puts("scrub aborted\n"); return -1; } } else { puts("scrub aborted\n"); return -1; } } ret = nand_erase_opts(nand, &opts); printf("%s\n", ret ? "ERROR" : "OK"); return ret == 0 ? 0 : 1; } if (strncmp(cmd, "dump", 4) == 0) { if (argc < 3) goto usage; off = (int)simple_strtoul(argv[2], NULL, 16); ret = nand_dump(nand, off, !strcmp(&cmd[4], ".oob"), repeat); return ret == 0 ? 1 : 0; } if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { size_t rwsize; ulong pagecount = 1; int read; int raw; if (argc < 4) goto usage; addr = (ulong)simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf("\nNAND %s: ", read ? "read" : "write"); nand = &nand_info[dev]; s = strchr(cmd, '.'); if (s && !strcmp(s, ".raw")) { raw = 1; if (arg_off(argv[3], &dev, &off, &size, &maxsize)) return 1; if (argc > 4 && !str2long(argv[4], &pagecount)) { printf("'%s' is not a number\n", argv[4]); return 1; } if (pagecount * nand->writesize > size) { puts("Size exceeds partition or device limit\n"); return -1; } rwsize = pagecount * (nand->writesize + nand->oobsize); } else { if (arg_off_size(argc - 3, argv + 3, &dev, &off, &size, &maxsize) != 0) return 1; rwsize = size; } if (!s || !strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i")) { if (read) ret = nand_read_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr); else ret = nand_write_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr, 0); #ifdef CONFIG_CMD_NAND_TRIMFFS } else if (!strcmp(s, ".trimffs")) { if (read) { printf("Unknown nand command suffix '%s'\n", s); return 1; } ret = nand_write_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr, WITH_DROP_FFS); #endif #ifdef CONFIG_CMD_NAND_YAFFS } else if (!strcmp(s, ".yaffs")) { if (read) { printf("Unknown nand command suffix '%s'.\n", s); return 1; } ret = nand_write_skip_bad(nand, off, &rwsize, NULL, maxsize, (u_char *)addr, WITH_YAFFS_OOB); #endif } else if (!strcmp(s, ".oob")) { /* out-of-band data */ mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = rwsize, .mode = MTD_OOB_RAW }; if (read) ret = nand->read_oob(nand, off, &ops); else ret = nand->write_oob(nand, off, &ops); } else if (raw) {
static int nand_block_op(enum dfu_nand_op op, struct dfu_entity *dfu, u64 offset, void *buf, long *len) { loff_t start, lim; size_t count, actual; int ret; nand_info_t *nand; /* if buf == NULL return total size of the area */ if (buf == NULL) { *len = dfu->data.nand.size; return 0; } start = dfu->data.nand.start + offset + dfu->bad_skip; lim = dfu->data.nand.start + dfu->data.nand.size - start; count = *len; if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[nand_curr_device].name) { printf("%s: invalid nand device\n", __func__); return -1; } nand = &nand_info[nand_curr_device]; if (op == DFU_OP_READ) { ret = nand_read_skip_bad(nand, start, &count, &actual, lim, buf); } else { nand_erase_options_t opts; memset(&opts, 0, sizeof(opts)); opts.offset = start; opts.length = count; opts.spread = 1; opts.quiet = 1; opts.lim = lim; /* first erase */ ret = nand_erase_opts(nand, &opts); if (ret) return ret; /* then write */ ret = nand_write_skip_bad(nand, start, &count, &actual, lim, buf, 0); } if (ret != 0) { printf("%s: nand_%s_skip_bad call failed at %llx!\n", __func__, op == DFU_OP_READ ? "read" : "write", start); return ret; } /* * Find out where we stopped writing data. This can be deeper into * the NAND than we expected due to having to skip bad blocks. So * we must take this into account for the next write, if any. */ if (actual > count) dfu->bad_skip += actual - count; return ret; }
/* Write u-boot image into the nand flash */ int nand_burn_uboot_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int filesize; MV_U32 ret = 0; extern char console_buffer[]; nand_info_t *nand = &nand_info[0]; nand_erase_options_t er_opts; nand_write_options_t wr_opts; load_addr = CFG_LOAD_ADDR; if(argc == 2) { copy_filename (BootFile, argv[1], sizeof(BootFile)); } else { copy_filename (BootFile, "u-boot.bin", sizeof(BootFile)); printf("using default file \"u-boot.bin\" \n"); } if ((filesize = NetLoop(TFTP)) < 0) return 0; printf("\n**Warning**\n"); printf("If U-Boot Endiannes is going to change (LE->BE or BE->LE), Then Env parameters should be overriden..\n"); printf("Override Env parameters? (y/n)"); readline(" "); if( strcmp(console_buffer,"Y") == 0 || strcmp(console_buffer,"yes") == 0 || strcmp(console_buffer,"y") == 0 ) { printf("Erase Env parameters sector %d... ",CFG_ENV_OFFSET); memset(&er_opts, 0, sizeof(er_opts)); er_opts.offset = CFG_ENV_OFFSET; er_opts.length = CFG_ENV_SECT_SIZE; er_opts.quiet = 1; nand_erase_opts(nand, &er_opts); //nand_erase(nand_dev_desc + 0, CFG_ENV_OFFSET, CFG_ENV_SECT_SIZE, 0); printf("\n"); } printf("Erase %d - %d ... ",CFG_MONITOR_BASE, CFG_MONITOR_LEN); memset(&er_opts, 0, sizeof(er_opts)); er_opts.offset = CFG_MONITOR_BASE; er_opts.length = CFG_MONITOR_LEN; er_opts.quiet = 1; nand_erase_opts(nand, &er_opts); //nand_erase(nand_dev_desc + 0, CFG_MONITOR_BASE, CFG_MONITOR_LEN, 0); printf("\nCopy to Nand Flash... "); memset(&wr_opts, 0, sizeof(wr_opts)); wr_opts.buffer = (u_char*) load_addr; wr_opts.length = CFG_MONITOR_LEN; wr_opts.offset = CFG_MONITOR_BASE; /* opts.forcejffs2 = 1; */ wr_opts.pad = 1; wr_opts.blockalign = 1; wr_opts.quiet = 1; ret = nand_write_opts(nand, &wr_opts); /* ret = nand_rw(nand_dev_desc + 0, NANDRW_WRITE | NANDRW_JFFS2, CFG_MONITOR_BASE, CFG_MONITOR_LEN, &total, (u_char*)0x100000 + CFG_MONITOR_IMAGE_OFFSET); */ if (ret) printf("Error - NAND burn faild!\n"); else printf("\ndone\n"); return 1; }
static int nand_biterr(nand_info_t *nand, loff_t addr, int bit) { nand_erase_options_t opts; struct mtd_oob_ops ops; uint8_t *datbuf, *pagebuf, *write_buf; size_t size; loff_t write_addr; int ret, pages; datbuf = malloc(nand->erasesize); if (!datbuf) { printf("biterr: out of memory\n"); return 1; } pagebuf = malloc(nand->writesize + nand->oobsize); if (!pagebuf) { printf("biterr: out of memory\n"); free(datbuf); return 1; } /* first read the whole erase block */ size = nand->erasesize; ret = nand_read(nand, addr & ~(nand->erasesize - 1), &size, datbuf); if (ret < 0 && ret != -EUCLEAN) { printf("biterr: nand_read failed\n"); goto err; } nand_use_ecc(nand, 0); /* read the affected page with oob */ memset(&ops, 0, sizeof(ops)); ops.datbuf = pagebuf; ops.oobbuf = pagebuf + nand->writesize; ops.len = nand->writesize; ops.ooblen = nand->oobsize; ops.mode = MTD_OOB_RAW; ret = nand->read_oob(nand, addr & ~(nand->writesize - 1), &ops); if (ret < 0) { printf("biterr: read_oob failed\n"); nand_use_ecc(nand, 1); goto err; } /* flip the bit(s) */ pagebuf[(addr & (nand->writesize - 1)) + (bit & ~7)] ^= 1 << (bit & 7); /* erase */ memset(&opts, 0, sizeof(opts)); opts.quiet = 1; opts.offset = addr & ~(nand->erasesize - 1); opts.length = nand->erasesize; ret = nand_erase_opts(nand, &opts); if (ret < 0) { printf("biterr: erase failed\n"); nand_use_ecc(nand, 1); goto err; } /* write the affected page back with oob in raw mode */ memset(&ops, 0, sizeof(ops)); ops.datbuf = pagebuf; ops.oobbuf = pagebuf + nand->writesize; ops.len = nand->writesize; ops.ooblen = nand->oobsize; ops.mode = MTD_OOB_RAW; ret = nand->write_oob(nand, addr & ~(nand->writesize - 1), &ops); if (ret < 0) { printf("biterr: write_oob failed\n"); nand_use_ecc(nand, 1); goto err; } nand_use_ecc(nand, 1); /* write back the other pages as normal */ write_addr = addr & ~(nand->erasesize - 1); write_buf = datbuf; for (pages = nand->erasesize / nand->writesize; pages > 0; pages--, write_addr += nand->writesize, write_buf += nand->writesize) { /* skip the block that was written back raw */ if (write_addr == (addr & ~(nand->writesize - 1))) continue; size = nand->writesize; ret = nand_write(nand, write_addr, &size, write_buf); if (ret < 0) printf("biterr: error writing back page 0x%llx\n", write_addr); } free(datbuf); free(pagebuf); return 0; err: free(datbuf); free(pagebuf); return 1; }