int saveenv(void) { unsigned long env_addr = CFG_ENV_ADDR; struct erase_info instr; int retlen; instr.len = CFG_ENV_SIZE; instr.addr = env_addr; instr.addr -= (unsigned long)onenand_chip.base; if (onenand_erase(&onenand_mtd, &instr)) { printf("OneNAND: erase failed at 0x%08x\n", env_addr); return 1; } /* update crc */ env_ptr->crc = crc32(0, env_ptr->data, onenand_mtd.oobblock - ENV_HEADER_SIZE); env_addr -= (unsigned long)onenand_chip.base; if (onenand_write(&onenand_mtd, env_addr, onenand_mtd.oobblock, &retlen, (u_char *) env_ptr)) { printf("OneNAND: write failed at 0x%08x\n", instr.addr); return 2; } return 0; }
int saveenv(void) { unsigned long env_addr = CFG_ENV_ADDR; struct erase_info instr = { .callback = NULL, }; size_t retlen; instr.len = CFG_ENV_SIZE; instr.addr = env_addr; if (onenand_erase(&onenand_mtd, &instr)) { printf("OneNAND: erase failed at 0x%08lx\n", env_addr); return 1; } /* update crc */ env_ptr->crc = crc32(0, env_ptr->data, ONENAND_ENV_SIZE(onenand_mtd)); if (onenand_write(&onenand_mtd, env_addr, onenand_mtd.writesize, &retlen, (u_char *) env_ptr)) { printf("OneNAND: write failed at 0x%08x\n", instr.addr); return 2; } return 0; }
int do_onenand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int ret = 0; switch (argc) { case 0: case 1: printf("Usage:\n%s\n", cmdtp->usage); return 1; case 2: onenand_print_device_info(onenand_chip.device_id, 1); return 0; default: /* At least 4 args */ if (strncmp(argv[1], "erase", 5) == 0) { struct erase_info instr; ulong start, end; char *endtail; ulong block; if (strncmp(argv[2], "block", 5) == 0) { start = simple_strtoul(argv[3], NULL, 10); endtail = strchr(argv[3], '-'); end = simple_strtoul(endtail+1, NULL, 10); } else { start = simple_strtoul(argv[2], NULL, 10); end = simple_strtoul(argv[3], NULL, 10); start -= (unsigned long) onenand_chip.base; end -= (unsigned long) onenand_chip.base; } if (!end || end < 0) end = start; printf("Erase block from %d to %d\n", start, end); for (block = start; block <= end; block++) { instr.addr = block << onenand_chip.erase_shift; instr.len = 1 << onenand_chip.erase_shift; ret = onenand_erase(&onenand_mtd, &instr); if (ret) { printf("erase failed %d\n", block); break; } } return 0; } if (strncmp(argv[1], "read", 4) == 0) { ulong addr = simple_strtoul(argv[2], NULL, 16); ulong ofs = simple_strtoul(argv[3], NULL, 16); size_t len = simple_strtoul(argv[4], NULL, 16); size_t retlen = 0; int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1; if (oob) onenand_read_oob(&onenand_mtd, ofs, len, &retlen, (u_char *) addr); else onenand_read(&onenand_mtd, ofs, len, &retlen, (u_char *) addr); printf("Done\n"); return 0; } if (strncmp(argv[1], "write", 5) == 0) { int ret ; ulong addr = simple_strtoul(argv[2], NULL, 16); ulong ofs = simple_strtoul(argv[3], NULL, 16); size_t len = simple_strtoul(argv[4], NULL, 16); size_t retlen = 0; printf("onenadwrite: addr = 0x%x, ofs = 0x%x, len = 0x%x\n", addr, ofs, len); ret = onenand_write(&onenand_mtd, ofs, len, &retlen, (u_char *) addr); if (ret) printf("Error writing oneNAND: ret = %d\n", ret); else printf("Done. ret = %d\n", ret); return 0; } if (strncmp(argv[1], "block", 5) == 0) { ulong addr = simple_strtoul(argv[2], NULL, 16); ulong block = simple_strtoul(argv[3], NULL, 10); ulong page = simple_strtoul(argv[4], NULL, 10); size_t len = simple_strtol(argv[5], NULL, 10); size_t retlen = 0; ulong ofs; int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1; ofs = block << onenand_chip.erase_shift; if (page) ofs += page << onenand_chip.page_shift; if (!len) { if (oob) len = 64; else len = 512; } if (oob) onenand_read_oob(&onenand_mtd, ofs, len, &retlen, (u_char *) addr); else onenand_read(&onenand_mtd, ofs, len, &retlen, (u_char *) addr); return 0; } if (strncmp(argv[1], "unlock", 6) == 0) { ulong start = simple_strtoul(argv[2], NULL, 10); ulong ofs = simple_strtoul(argv[3], NULL, 10); if (!ofs) ofs = (1 << onenand_chip.erase_shift); start = start << onenand_chip.erase_shift; printf("start = 0x%08x, ofs = 0x%08x\n", start, ofs); onenand_unlock(&onenand_mtd, start, start + ofs); return 0; } if (strncmp(argv[1], "save", 4) == 0 && strncmp(argv[2], "bootloader", 10) == 0) { ulong addr = simple_strtoul(argv[3], NULL, 16); struct erase_info instr; int ofs = 0; int len = 0x20000; size_t retlen; printf("save bootloader...\n"); if (!addr) break; onenand_unlock(&onenand_mtd, ofs, len); instr.addr = 0 << onenand_chip.erase_shift; instr.len = 1 << onenand_chip.erase_shift; onenand_erase(&onenand_mtd, &instr); onenand_write(&onenand_mtd, ofs, len, &retlen, (u_char *) addr); onenand_unlock(&onenand_mtd, CFG_ENV_ADDR, onenand_mtd.size - CFG_ENV_ADDR); return 0; } break; } return 0; }
int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { int ret = 0; switch (argc) { case 0: case 1: printf("Usage:\n%s\n", cmdtp->usage); return 1; case 2: if (strncmp(argv[1], "open", 4) == 0) { onenand_init(); return 0; } printf("%s\n", onenand_mtd.name); return 0; default: /* At least 4 args */ if (strncmp(argv[1], "erase", 5) == 0) { struct erase_info instr = { .callback = NULL, }; ulong start, size; ulong block; char *endtail; int clean = 0; struct jffs2_unknown_node cleanmarker; struct mtd_oob_ops ops = { .datbuf = NULL, .oobbuf = (uint8_t *)&cleanmarker, .ooblen = 8, .ooboffs= 0, .mode = MTD_OOB_PLACE, }; if (strncmp(argv[2], "block", 5) == 0) { start = simple_strtoul(argv[3], NULL, 10); endtail = strchr(argv[3], '-'); size = simple_strtoul(endtail + 1, NULL, 10) - start; } else if (strncmp(argv[2], "clean", 5) == 0) { cleanmarker.magic = JFFS2_MAGIC_BITMASK; cleanmarker.nodetype = JFFS2_NODETYPE_CLEANMARKER; cleanmarker.totlen = 8; start = simple_strtoul(argv[3], NULL, 10); size = simple_strtoul(argv[4], NULL, 10); start >>= onenand_chip.erase_shift; size >>= onenand_chip.erase_shift; /* Don't include the end block */ size--; clean = 1; printf("ready to erase with cleanmarker\n"); } else { start = simple_strtoul(argv[2], NULL, 10); size = simple_strtoul(argv[3], NULL, 10); start >>= onenand_chip.erase_shift; size >>= onenand_chip.erase_shift; /* Don't include the end block */ size--; } if (!size || size < 0) size = 0; printf("Erase begin with %luth block, erase size is %lu blocks\n", start, size); for (block = start; block <= start + size; block++) { instr.addr = block << onenand_chip.erase_shift; instr.len = 1 << onenand_chip.erase_shift; ret = onenand_erase(&onenand_mtd, &instr); if (ret) { printf("erase failed %lu\n", block); break; } if (clean == 1) { ret = onenand_write_oob(&onenand_mtd, instr.addr, &ops); if (ret) { printf("write OOB failed %lu\n", block); break; } } } return 0; } if (strncmp(argv[1], "dump", 4) == 0) { ulong ofs = simple_strtoul(argv[2], NULL, 16); onenand_dump(&onenand_mtd, ofs); printf("Done\n"); return 0; } if (strncmp(argv[1], "read", 4) == 0) { ulong addr = simple_strtoul(argv[2], NULL, 16); ulong ofs = simple_strtoul(argv[3], NULL, 16); size_t len = simple_strtoul(argv[4], NULL, 16); int oob = strncmp(argv[1], "read.oob", 8) ? 0 : 1; struct mtd_oob_ops ops; ops.mode = MTD_OOB_PLACE; if (oob) { ops.len = 0; ops.datbuf = NULL; ops.ooblen = len; ops.oobbuf = (u_char *) addr; } else { ops.len = len; ops.datbuf = (u_char *) addr; ops.ooblen = 0; ops.oobbuf = NULL; } ops.retlen = ops.oobretlen = 0; onenand_mtd.read_oob(&onenand_mtd, ofs, &ops); printf("Done\n"); return 0; } if (strncmp(argv[1], "write", 5) == 0) { ulong addr = simple_strtoul(argv[2], NULL, 16); ulong ofs = simple_strtoul(argv[3], NULL, 16); size_t len = simple_strtoul(argv[4], NULL, 16); size_t retlen = 0; struct mtd_oob_ops ops = { .datbuf = (uint8_t *) addr, .len = len, .oobbuf = (uint8_t *) addr, .ooblen = len, .mode = MTD_OOB_PLACE, }; onenand_mtd.owner = "UBOOT"; if (strncmp(argv[1], "write.yaffs", 11) == 0) { onenand_write_oob(&onenand_mtd, ofs, &ops); } else onenand_write(&onenand_mtd, ofs, len, &retlen, (u_char *) addr); printf("Done\n"); return 0; } if (strncmp(argv[1], "block", 5) == 0) { ulong addr = simple_strtoul(argv[2], NULL, 16); ulong block = simple_strtoul(argv[3], NULL, 10); ulong page = simple_strtoul(argv[4], NULL, 10); size_t len = simple_strtol(argv[5], NULL, 10); ulong ofs; int oob = strncmp(argv[1], "block.oob", 9) ? 0 : 1; struct mtd_oob_ops ops; ops.mode = MTD_OOB_PLACE; ofs = block << onenand_chip.erase_shift; if (page) ofs += page << onenand_chip.page_shift; if (!len) { if (oob) ops.ooblen = 64; else ops.len = 512; } if (oob) { ops.datbuf = NULL; ops.oobbuf = (u_char *) addr; } else { ops.datbuf = (u_char *) addr; ops.oobbuf = NULL; } ops.retlen = ops.oobretlen = 0; onenand_read_oob(&onenand_mtd, ofs, &ops); return 0; } break; }
int saveenv_onenand(void) { size_t total; int ret = 0, i; u32 erasebase; u32 eraselength; u32 eraseblock; u32 erasesize = onenand_info[0].erasesize; uint8_t *data; struct mtd_info *onenand; puts("Erasing Onenand...\n"); /* the following commands operate on the current device */ if (onenand_curr_device < 0 || onenand_curr_device >= CFG_MAX_ONENAND_DEVICE || !onenand_info[onenand_curr_device].name) { puts("\nno devices available\n"); return 1; } onenand = &onenand_info[onenand_curr_device]; /* If the value of CFG_ENV_OFFSET is not a NAND block boundary, the * NAND erase operation will fail. So first check if the CFG_ENV_OFFSET * is equal to a NAND block boundary */ if ((CFG_ENV_OFFSET % (erasesize - 1)) != 0 ) { /* CFG_ENV_OFFSET is not equal to block boundary address. So, read * the read the NAND block (in which ENV has to be stored), and * copy the ENV data into the copied block data. */ /* Step 1: Find out the starting address of the NAND block to * be erased. Also allocate memory whose size is equal to tbe * NAND block size (NAND erasesize). */ eraseblock = CFG_ENV_OFFSET / erasesize; erasebase = eraseblock * erasesize; printf("the baseaddr is 0x%08x ...\n", erasebase); data = (uint8_t*)malloc(erasesize); if (data == NULL) { printf("Could not save enviroment variables\n"); return 1; } /* Step 2: Read the NAND block into which the ENV data has * to be copied */ total = erasesize; printf("the total is 0x%08x ...\n", total); for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { if (onenand_scan(&onenand_info[i], 1) == 0) { ret = onenand_read(onenand, erasebase, &total, data); } else { printf("no devices available\n"); return 1; } } if (ret || total != erasesize) { printf("Could not save enviroment variables %d\n",ret); return 1; } /* Step 3: Copy the ENV data into the local copy of the block * contents. */ memcpy((data + (CFG_ENV_OFFSET - erasebase)), (void*)env_ptr, CFG_ENV_SIZE); } else { /* CFG_ENV_OFFSET is equal to a NAND block boundary. So * no special care is required when erasing and writing NAND * block */ data = env_ptr; erasebase = CFG_ENV_OFFSET; erasesize = CFG_ENV_SIZE; } /* Erase the NAND block which will hold the ENV data */ if (onenand_erase(onenand, erasebase, erasesize)) return 1; puts("Writing to onenand... \n"); total = erasesize; /* Write the ENV data to the NAND block */ printf("the baseaddr is 0x%08x ...\n", erasebase); printf("the baseaddr is 0x%08x ...\n", total); ret = onenand_write(onenand, erasebase, &total, (u_char*)data); if (ret || total != erasesize) { printf("Could not save enviroment variables\n"); return 1; } if ((CFG_ENV_OFFSET % (erasesize - 1)) != 0 ) free(data); puts("Saved enviroment variables\n"); return ret; return 1; }