blob: a3e46bcca8eeb9f28ec026dee919f1123ef685bf [file] [log] [blame]
#include <command.h>
#include <malloc.h>
#include <common.h>
#include <linux/mtd/mtd.h>
#include <mtd/pxa3xx_bbm.h>
extern int nand_curr_device;
extern struct mtd_info nand_info[];
extern struct mtd_info onenand_mtd;
extern int pxa3xx_update_bbt(struct mtd_info *mtd, loff_t offs);
int not_updating = 1;
int do_bbt (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct pxa3xx_bbm *bbm;
struct mtd_info *mtd;
int is_nand = 0, ret, block, bbm_type = BBM_NONE;
struct erase_info instr = {
.callback = NULL,
};
ulong addr;
switch (argc) {
case 0:
case 1:
case 2:
default:
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
case 3:
case 4:
case 5:
if (strcmp(argv[2], "nand") == 0) {
is_nand = 1;
mtd = &nand_info[nand_curr_device];
if (nand_curr_device < 0) {
printf ("There is no nand device on current CS\n");
return 0;
}
}
#ifdef CONFIG_CMD_ONENAND
if (strcmp(argv[2], "onenand") == 0) {
is_nand = 2;
if (onenand_mtd.size == 0) {
printf ("There is no onenand device\n");
return 0;
}
mtd = &onenand_mtd;
}
#endif
if (!is_nand)
{
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
bbm = mtd->bbm;
if (strcmp (argv[1], "show") == 0) {
if (bbm)
bbm->is_init = 0;
pxa3xx_scan_bbt(mtd);
}
else if (strcmp(argv[1], "init") == 0) {
if (argc == 3)
bbm_type = BBM_LEGACY;
else {
if (strcmp(argv[3], "new") == 0)
bbm_type = BBM_NEW;
else if (strcmp(argv[3], "old") == 0)
bbm_type = BBM_LEGACY;
if (bbm_type == BBM_NONE) {
printf("You should either select"
" new or old\n");
return 1;
}
}
pxa3xx_bbm_recovery(mtd, bbm_type, NULL, 0, 1);
}
else if (strcmp(argv[1], "recreate") == 0) {
puts("Warning: "
"recreate option will erase all content on your flash!\n"
" "
"are sure of what you are doing!\n"
"Also SHOULD NOTE THAT this only for old BBM scheme!\n"
"\nReally erase this NAND flash for recreate bbt? <y/N>\n");
do {
if (getc() == 'y' && getc() == '\r')
break;
puts("recreate aborted\n");
return -1;
} while (0);
addr = (ulong)simple_strtoul(argv[3], NULL, 16);
block = addr >> mtd->erasesize_shift;
if (block <= 0)
block = 1;
printf("ready to init flash...\n");
bbm->no_sync = 1;
instr.addr = mtd->erasesize * block;
instr.len = mtd->erasesize;
printf("erasing..\n");
while (instr.addr < mtd->size) {
printf("%llx\r", instr.addr);
ret = mtd->_erase(mtd, &instr);
if (ret) {
printf("erase failed at %llx\n", instr.addr);
return -1;
}
instr.addr += mtd->erasesize;
}
printf("\ndone!\n");
bbm->no_sync = 0;
pxa3xx_update_bbt(mtd, 0);
}
else if (strcmp(argv[1], "convert") == 0) {
struct reloc_table *table;
struct reloc_item *item;
int old_bbm_slot;
char *buf;
buf = malloc(mtd->writesize);
old_bbm_slot = page_search(mtd, PXA_BEGIN_SLOT,
(mtd->erasesize >> mtd->writesize_shift) - 1,
ORDER_REVERSE, PXA_RELOC_HEADER, buf, BBM_HALF_MASK);
if (old_bbm_slot < 0) {
printf("Seems there is no old bbm slot on your board!!\n");
printf("Convertion failed!!!\n");
return 1;
}
table = (struct reloc_table *)buf;
item = (struct reloc_item *)&table[1];
pxa3xx_bbm_recovery(mtd, BBM_NEW, item, table->total, 0);
}
else if (strcmp(argv[1], "mark") == 0) {
addr = (ulong)simple_strtoul(argv[3], NULL, 16);
block = addr >> mtd->erasesize_shift;
ret = pxa3xx_block_markbad(mtd, addr);
if (ret == 0) {
printf("block %d successfully marked as bad\n",
block);
return 0;
} else {
printf("block %d NOT marked as bad! ERROR %d\n",
block, ret);
}
}
else {
printf ("Usage:\n%s\n", cmdtp->usage);
return 1;
}
}
return 1;
}
U_BOOT_CMD(
bbt, 4, 1, do_bbt,
"bbt\t- Bad Block Management\n",
"show [nand | onenand]\t- show nand/onenand relocation table\n"
"bbt init [nand | onenand]\t- init relocation table\n"
"bbt recreate [nand | onenand] addr\t- rebuild the bbt by erasing the whole flash after sepecified addr\n"
"bbt convert [nand | onenand]\t- convert the old bbm to new bbm scheme if old existed\n"
"bbt mark [nand | onenand] addr\t- mark bad block\n"
);