1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * U-Boot command for OneNAND support 3*2e192b24SSimon Glass * 4*2e192b24SSimon Glass * Copyright (C) 2005-2008 Samsung Electronics 5*2e192b24SSimon Glass * Kyungmin Park <kyungmin.park@samsung.com> 6*2e192b24SSimon Glass * 7*2e192b24SSimon Glass * This program is free software; you can redistribute it and/or modify 8*2e192b24SSimon Glass * it under the terms of the GNU General Public License version 2 as 9*2e192b24SSimon Glass * published by the Free Software Foundation. 10*2e192b24SSimon Glass */ 11*2e192b24SSimon Glass 12*2e192b24SSimon Glass #include <common.h> 13*2e192b24SSimon Glass #include <command.h> 14*2e192b24SSimon Glass #include <malloc.h> 15*2e192b24SSimon Glass 16*2e192b24SSimon Glass #include <linux/compat.h> 17*2e192b24SSimon Glass #include <linux/mtd/mtd.h> 18*2e192b24SSimon Glass #include <linux/mtd/onenand.h> 19*2e192b24SSimon Glass 20*2e192b24SSimon Glass #include <asm/io.h> 21*2e192b24SSimon Glass 22*2e192b24SSimon Glass static struct mtd_info *mtd; 23*2e192b24SSimon Glass 24*2e192b24SSimon Glass static loff_t next_ofs; 25*2e192b24SSimon Glass static loff_t skip_ofs; 26*2e192b24SSimon Glass 27*2e192b24SSimon Glass static int arg_off_size_onenand(int argc, char * const argv[], ulong *off, 28*2e192b24SSimon Glass size_t *size) 29*2e192b24SSimon Glass { 30*2e192b24SSimon Glass if (argc >= 1) { 31*2e192b24SSimon Glass if (!(str2long(argv[0], off))) { 32*2e192b24SSimon Glass printf("'%s' is not a number\n", argv[0]); 33*2e192b24SSimon Glass return -1; 34*2e192b24SSimon Glass } 35*2e192b24SSimon Glass } else { 36*2e192b24SSimon Glass *off = 0; 37*2e192b24SSimon Glass } 38*2e192b24SSimon Glass 39*2e192b24SSimon Glass if (argc >= 2) { 40*2e192b24SSimon Glass if (!(str2long(argv[1], (ulong *)size))) { 41*2e192b24SSimon Glass printf("'%s' is not a number\n", argv[1]); 42*2e192b24SSimon Glass return -1; 43*2e192b24SSimon Glass } 44*2e192b24SSimon Glass } else { 45*2e192b24SSimon Glass *size = mtd->size - *off; 46*2e192b24SSimon Glass } 47*2e192b24SSimon Glass 48*2e192b24SSimon Glass if ((*off + *size) > mtd->size) { 49*2e192b24SSimon Glass printf("total chip size (0x%llx) exceeded!\n", mtd->size); 50*2e192b24SSimon Glass return -1; 51*2e192b24SSimon Glass } 52*2e192b24SSimon Glass 53*2e192b24SSimon Glass if (*size == mtd->size) 54*2e192b24SSimon Glass puts("whole chip\n"); 55*2e192b24SSimon Glass else 56*2e192b24SSimon Glass printf("offset 0x%lx, size 0x%x\n", *off, *size); 57*2e192b24SSimon Glass 58*2e192b24SSimon Glass return 0; 59*2e192b24SSimon Glass } 60*2e192b24SSimon Glass 61*2e192b24SSimon Glass static int onenand_block_read(loff_t from, size_t len, 62*2e192b24SSimon Glass size_t *retlen, u_char *buf, int oob) 63*2e192b24SSimon Glass { 64*2e192b24SSimon Glass struct onenand_chip *this = mtd->priv; 65*2e192b24SSimon Glass int blocks = (int) len >> this->erase_shift; 66*2e192b24SSimon Glass int blocksize = (1 << this->erase_shift); 67*2e192b24SSimon Glass loff_t ofs = from; 68*2e192b24SSimon Glass struct mtd_oob_ops ops = { 69*2e192b24SSimon Glass .retlen = 0, 70*2e192b24SSimon Glass }; 71*2e192b24SSimon Glass int ret; 72*2e192b24SSimon Glass 73*2e192b24SSimon Glass if (oob) 74*2e192b24SSimon Glass ops.ooblen = blocksize; 75*2e192b24SSimon Glass else 76*2e192b24SSimon Glass ops.len = blocksize; 77*2e192b24SSimon Glass 78*2e192b24SSimon Glass while (blocks) { 79*2e192b24SSimon Glass ret = mtd_block_isbad(mtd, ofs); 80*2e192b24SSimon Glass if (ret) { 81*2e192b24SSimon Glass printk("Bad blocks %d at 0x%x\n", 82*2e192b24SSimon Glass (u32)(ofs >> this->erase_shift), (u32)ofs); 83*2e192b24SSimon Glass ofs += blocksize; 84*2e192b24SSimon Glass continue; 85*2e192b24SSimon Glass } 86*2e192b24SSimon Glass 87*2e192b24SSimon Glass if (oob) 88*2e192b24SSimon Glass ops.oobbuf = buf; 89*2e192b24SSimon Glass else 90*2e192b24SSimon Glass ops.datbuf = buf; 91*2e192b24SSimon Glass 92*2e192b24SSimon Glass ops.retlen = 0; 93*2e192b24SSimon Glass ret = mtd_read_oob(mtd, ofs, &ops); 94*2e192b24SSimon Glass if (ret) { 95*2e192b24SSimon Glass printk("Read failed 0x%x, %d\n", (u32)ofs, ret); 96*2e192b24SSimon Glass ofs += blocksize; 97*2e192b24SSimon Glass continue; 98*2e192b24SSimon Glass } 99*2e192b24SSimon Glass ofs += blocksize; 100*2e192b24SSimon Glass buf += blocksize; 101*2e192b24SSimon Glass blocks--; 102*2e192b24SSimon Glass *retlen += ops.retlen; 103*2e192b24SSimon Glass } 104*2e192b24SSimon Glass 105*2e192b24SSimon Glass return 0; 106*2e192b24SSimon Glass } 107*2e192b24SSimon Glass 108*2e192b24SSimon Glass static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf, 109*2e192b24SSimon Glass size_t *retlen) 110*2e192b24SSimon Glass { 111*2e192b24SSimon Glass struct mtd_oob_ops ops = { 112*2e192b24SSimon Glass .len = mtd->writesize, 113*2e192b24SSimon Glass .ooblen = mtd->oobsize, 114*2e192b24SSimon Glass .mode = MTD_OPS_AUTO_OOB, 115*2e192b24SSimon Glass }; 116*2e192b24SSimon Glass int page, ret = 0; 117*2e192b24SSimon Glass for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) { 118*2e192b24SSimon Glass ops.datbuf = (u_char *)buf; 119*2e192b24SSimon Glass buf += mtd->writesize; 120*2e192b24SSimon Glass ops.oobbuf = (u_char *)buf; 121*2e192b24SSimon Glass buf += mtd->oobsize; 122*2e192b24SSimon Glass ret = mtd_write_oob(mtd, to, &ops); 123*2e192b24SSimon Glass if (ret) 124*2e192b24SSimon Glass break; 125*2e192b24SSimon Glass to += mtd->writesize; 126*2e192b24SSimon Glass } 127*2e192b24SSimon Glass 128*2e192b24SSimon Glass *retlen = (ret) ? 0 : mtd->erasesize; 129*2e192b24SSimon Glass return ret; 130*2e192b24SSimon Glass } 131*2e192b24SSimon Glass 132*2e192b24SSimon Glass static int onenand_block_write(loff_t to, size_t len, 133*2e192b24SSimon Glass size_t *retlen, const u_char * buf, int withoob) 134*2e192b24SSimon Glass { 135*2e192b24SSimon Glass struct onenand_chip *this = mtd->priv; 136*2e192b24SSimon Glass int blocks = len >> this->erase_shift; 137*2e192b24SSimon Glass int blocksize = (1 << this->erase_shift); 138*2e192b24SSimon Glass loff_t ofs; 139*2e192b24SSimon Glass size_t _retlen = 0; 140*2e192b24SSimon Glass int ret; 141*2e192b24SSimon Glass 142*2e192b24SSimon Glass if (to == next_ofs) { 143*2e192b24SSimon Glass next_ofs = to + len; 144*2e192b24SSimon Glass to += skip_ofs; 145*2e192b24SSimon Glass } else { 146*2e192b24SSimon Glass next_ofs = to + len; 147*2e192b24SSimon Glass skip_ofs = 0; 148*2e192b24SSimon Glass } 149*2e192b24SSimon Glass ofs = to; 150*2e192b24SSimon Glass 151*2e192b24SSimon Glass while (blocks) { 152*2e192b24SSimon Glass ret = mtd_block_isbad(mtd, ofs); 153*2e192b24SSimon Glass if (ret) { 154*2e192b24SSimon Glass printk("Bad blocks %d at 0x%x\n", 155*2e192b24SSimon Glass (u32)(ofs >> this->erase_shift), (u32)ofs); 156*2e192b24SSimon Glass skip_ofs += blocksize; 157*2e192b24SSimon Glass goto next; 158*2e192b24SSimon Glass } 159*2e192b24SSimon Glass 160*2e192b24SSimon Glass if (!withoob) 161*2e192b24SSimon Glass ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf); 162*2e192b24SSimon Glass else 163*2e192b24SSimon Glass ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen); 164*2e192b24SSimon Glass if (ret) { 165*2e192b24SSimon Glass printk("Write failed 0x%x, %d", (u32)ofs, ret); 166*2e192b24SSimon Glass skip_ofs += blocksize; 167*2e192b24SSimon Glass goto next; 168*2e192b24SSimon Glass } 169*2e192b24SSimon Glass 170*2e192b24SSimon Glass buf += blocksize; 171*2e192b24SSimon Glass blocks--; 172*2e192b24SSimon Glass *retlen += _retlen; 173*2e192b24SSimon Glass next: 174*2e192b24SSimon Glass ofs += blocksize; 175*2e192b24SSimon Glass } 176*2e192b24SSimon Glass 177*2e192b24SSimon Glass return 0; 178*2e192b24SSimon Glass } 179*2e192b24SSimon Glass 180*2e192b24SSimon Glass static int onenand_block_erase(u32 start, u32 size, int force) 181*2e192b24SSimon Glass { 182*2e192b24SSimon Glass struct onenand_chip *this = mtd->priv; 183*2e192b24SSimon Glass struct erase_info instr = { 184*2e192b24SSimon Glass .callback = NULL, 185*2e192b24SSimon Glass }; 186*2e192b24SSimon Glass loff_t ofs; 187*2e192b24SSimon Glass int ret; 188*2e192b24SSimon Glass int blocksize = 1 << this->erase_shift; 189*2e192b24SSimon Glass 190*2e192b24SSimon Glass for (ofs = start; ofs < (start + size); ofs += blocksize) { 191*2e192b24SSimon Glass ret = mtd_block_isbad(mtd, ofs); 192*2e192b24SSimon Glass if (ret && !force) { 193*2e192b24SSimon Glass printf("Skip erase bad block %d at 0x%x\n", 194*2e192b24SSimon Glass (u32)(ofs >> this->erase_shift), (u32)ofs); 195*2e192b24SSimon Glass continue; 196*2e192b24SSimon Glass } 197*2e192b24SSimon Glass 198*2e192b24SSimon Glass instr.addr = ofs; 199*2e192b24SSimon Glass instr.len = blocksize; 200*2e192b24SSimon Glass instr.priv = force; 201*2e192b24SSimon Glass instr.mtd = mtd; 202*2e192b24SSimon Glass ret = mtd_erase(mtd, &instr); 203*2e192b24SSimon Glass if (ret) { 204*2e192b24SSimon Glass printf("erase failed block %d at 0x%x\n", 205*2e192b24SSimon Glass (u32)(ofs >> this->erase_shift), (u32)ofs); 206*2e192b24SSimon Glass continue; 207*2e192b24SSimon Glass } 208*2e192b24SSimon Glass } 209*2e192b24SSimon Glass 210*2e192b24SSimon Glass return 0; 211*2e192b24SSimon Glass } 212*2e192b24SSimon Glass 213*2e192b24SSimon Glass static int onenand_block_test(u32 start, u32 size) 214*2e192b24SSimon Glass { 215*2e192b24SSimon Glass struct onenand_chip *this = mtd->priv; 216*2e192b24SSimon Glass struct erase_info instr = { 217*2e192b24SSimon Glass .callback = NULL, 218*2e192b24SSimon Glass .priv = 0, 219*2e192b24SSimon Glass }; 220*2e192b24SSimon Glass 221*2e192b24SSimon Glass int blocks; 222*2e192b24SSimon Glass loff_t ofs; 223*2e192b24SSimon Glass int blocksize = 1 << this->erase_shift; 224*2e192b24SSimon Glass int start_block, end_block; 225*2e192b24SSimon Glass size_t retlen; 226*2e192b24SSimon Glass u_char *buf; 227*2e192b24SSimon Glass u_char *verify_buf; 228*2e192b24SSimon Glass int ret; 229*2e192b24SSimon Glass 230*2e192b24SSimon Glass buf = malloc(blocksize); 231*2e192b24SSimon Glass if (!buf) { 232*2e192b24SSimon Glass printf("Not enough malloc space available!\n"); 233*2e192b24SSimon Glass return -1; 234*2e192b24SSimon Glass } 235*2e192b24SSimon Glass 236*2e192b24SSimon Glass verify_buf = malloc(blocksize); 237*2e192b24SSimon Glass if (!verify_buf) { 238*2e192b24SSimon Glass printf("Not enough malloc space available!\n"); 239*2e192b24SSimon Glass return -1; 240*2e192b24SSimon Glass } 241*2e192b24SSimon Glass 242*2e192b24SSimon Glass start_block = start >> this->erase_shift; 243*2e192b24SSimon Glass end_block = (start + size) >> this->erase_shift; 244*2e192b24SSimon Glass 245*2e192b24SSimon Glass /* Protect boot-loader from badblock testing */ 246*2e192b24SSimon Glass if (start_block < 2) 247*2e192b24SSimon Glass start_block = 2; 248*2e192b24SSimon Glass 249*2e192b24SSimon Glass if (end_block > (mtd->size >> this->erase_shift)) 250*2e192b24SSimon Glass end_block = mtd->size >> this->erase_shift; 251*2e192b24SSimon Glass 252*2e192b24SSimon Glass blocks = start_block; 253*2e192b24SSimon Glass ofs = start; 254*2e192b24SSimon Glass while (blocks < end_block) { 255*2e192b24SSimon Glass printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs); 256*2e192b24SSimon Glass 257*2e192b24SSimon Glass ret = mtd_block_isbad(mtd, ofs); 258*2e192b24SSimon Glass if (ret) { 259*2e192b24SSimon Glass printf("Skip erase bad block %d at 0x%x\n", 260*2e192b24SSimon Glass (u32)(ofs >> this->erase_shift), (u32)ofs); 261*2e192b24SSimon Glass goto next; 262*2e192b24SSimon Glass } 263*2e192b24SSimon Glass 264*2e192b24SSimon Glass instr.addr = ofs; 265*2e192b24SSimon Glass instr.len = blocksize; 266*2e192b24SSimon Glass ret = mtd_erase(mtd, &instr); 267*2e192b24SSimon Glass if (ret) { 268*2e192b24SSimon Glass printk("Erase failed 0x%x, %d\n", (u32)ofs, ret); 269*2e192b24SSimon Glass goto next; 270*2e192b24SSimon Glass } 271*2e192b24SSimon Glass 272*2e192b24SSimon Glass ret = mtd_write(mtd, ofs, blocksize, &retlen, buf); 273*2e192b24SSimon Glass if (ret) { 274*2e192b24SSimon Glass printk("Write failed 0x%x, %d\n", (u32)ofs, ret); 275*2e192b24SSimon Glass goto next; 276*2e192b24SSimon Glass } 277*2e192b24SSimon Glass 278*2e192b24SSimon Glass ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf); 279*2e192b24SSimon Glass if (ret) { 280*2e192b24SSimon Glass printk("Read failed 0x%x, %d\n", (u32)ofs, ret); 281*2e192b24SSimon Glass goto next; 282*2e192b24SSimon Glass } 283*2e192b24SSimon Glass 284*2e192b24SSimon Glass if (memcmp(buf, verify_buf, blocksize)) 285*2e192b24SSimon Glass printk("\nRead/Write test failed at 0x%x\n", (u32)ofs); 286*2e192b24SSimon Glass 287*2e192b24SSimon Glass next: 288*2e192b24SSimon Glass ofs += blocksize; 289*2e192b24SSimon Glass blocks++; 290*2e192b24SSimon Glass } 291*2e192b24SSimon Glass printf("...Done\n"); 292*2e192b24SSimon Glass 293*2e192b24SSimon Glass free(buf); 294*2e192b24SSimon Glass free(verify_buf); 295*2e192b24SSimon Glass 296*2e192b24SSimon Glass return 0; 297*2e192b24SSimon Glass } 298*2e192b24SSimon Glass 299*2e192b24SSimon Glass static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob) 300*2e192b24SSimon Glass { 301*2e192b24SSimon Glass int i; 302*2e192b24SSimon Glass u_char *datbuf, *oobbuf, *p; 303*2e192b24SSimon Glass struct mtd_oob_ops ops; 304*2e192b24SSimon Glass loff_t addr; 305*2e192b24SSimon Glass 306*2e192b24SSimon Glass datbuf = malloc(mtd->writesize + mtd->oobsize); 307*2e192b24SSimon Glass oobbuf = malloc(mtd->oobsize); 308*2e192b24SSimon Glass if (!datbuf || !oobbuf) { 309*2e192b24SSimon Glass puts("No memory for page buffer\n"); 310*2e192b24SSimon Glass return 1; 311*2e192b24SSimon Glass } 312*2e192b24SSimon Glass off &= ~(mtd->writesize - 1); 313*2e192b24SSimon Glass addr = (loff_t) off; 314*2e192b24SSimon Glass memset(&ops, 0, sizeof(ops)); 315*2e192b24SSimon Glass ops.datbuf = datbuf; 316*2e192b24SSimon Glass ops.oobbuf = oobbuf; 317*2e192b24SSimon Glass ops.len = mtd->writesize; 318*2e192b24SSimon Glass ops.ooblen = mtd->oobsize; 319*2e192b24SSimon Glass ops.retlen = 0; 320*2e192b24SSimon Glass i = mtd_read_oob(mtd, addr, &ops); 321*2e192b24SSimon Glass if (i < 0) { 322*2e192b24SSimon Glass printf("Error (%d) reading page %08lx\n", i, off); 323*2e192b24SSimon Glass free(datbuf); 324*2e192b24SSimon Glass free(oobbuf); 325*2e192b24SSimon Glass return 1; 326*2e192b24SSimon Glass } 327*2e192b24SSimon Glass printf("Page %08lx dump:\n", off); 328*2e192b24SSimon Glass i = mtd->writesize >> 4; 329*2e192b24SSimon Glass p = datbuf; 330*2e192b24SSimon Glass 331*2e192b24SSimon Glass while (i--) { 332*2e192b24SSimon Glass if (!only_oob) 333*2e192b24SSimon Glass printf("\t%02x %02x %02x %02x %02x %02x %02x %02x" 334*2e192b24SSimon Glass " %02x %02x %02x %02x %02x %02x %02x %02x\n", 335*2e192b24SSimon Glass p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 336*2e192b24SSimon Glass p[8], p[9], p[10], p[11], p[12], p[13], p[14], 337*2e192b24SSimon Glass p[15]); 338*2e192b24SSimon Glass p += 16; 339*2e192b24SSimon Glass } 340*2e192b24SSimon Glass puts("OOB:\n"); 341*2e192b24SSimon Glass i = mtd->oobsize >> 3; 342*2e192b24SSimon Glass p = oobbuf; 343*2e192b24SSimon Glass 344*2e192b24SSimon Glass while (i--) { 345*2e192b24SSimon Glass printf("\t%02x %02x %02x %02x %02x %02x %02x %02x\n", 346*2e192b24SSimon Glass p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 347*2e192b24SSimon Glass p += 8; 348*2e192b24SSimon Glass } 349*2e192b24SSimon Glass free(datbuf); 350*2e192b24SSimon Glass free(oobbuf); 351*2e192b24SSimon Glass 352*2e192b24SSimon Glass return 0; 353*2e192b24SSimon Glass } 354*2e192b24SSimon Glass 355*2e192b24SSimon Glass static int do_onenand_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 356*2e192b24SSimon Glass { 357*2e192b24SSimon Glass printf("%s\n", mtd->name); 358*2e192b24SSimon Glass return 0; 359*2e192b24SSimon Glass } 360*2e192b24SSimon Glass 361*2e192b24SSimon Glass static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 362*2e192b24SSimon Glass { 363*2e192b24SSimon Glass ulong ofs; 364*2e192b24SSimon Glass 365*2e192b24SSimon Glass mtd = &onenand_mtd; 366*2e192b24SSimon Glass /* Currently only one OneNAND device is supported */ 367*2e192b24SSimon Glass printf("\nDevice %d bad blocks:\n", 0); 368*2e192b24SSimon Glass for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) { 369*2e192b24SSimon Glass if (mtd_block_isbad(mtd, ofs)) 370*2e192b24SSimon Glass printf(" %08x\n", (u32)ofs); 371*2e192b24SSimon Glass } 372*2e192b24SSimon Glass 373*2e192b24SSimon Glass return 0; 374*2e192b24SSimon Glass } 375*2e192b24SSimon Glass 376*2e192b24SSimon Glass static int do_onenand_read(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 377*2e192b24SSimon Glass { 378*2e192b24SSimon Glass char *s; 379*2e192b24SSimon Glass int oob = 0; 380*2e192b24SSimon Glass ulong addr, ofs; 381*2e192b24SSimon Glass size_t len; 382*2e192b24SSimon Glass int ret = 0; 383*2e192b24SSimon Glass size_t retlen = 0; 384*2e192b24SSimon Glass 385*2e192b24SSimon Glass if (argc < 3) 386*2e192b24SSimon Glass return CMD_RET_USAGE; 387*2e192b24SSimon Glass 388*2e192b24SSimon Glass s = strchr(argv[0], '.'); 389*2e192b24SSimon Glass if ((s != NULL) && (!strcmp(s, ".oob"))) 390*2e192b24SSimon Glass oob = 1; 391*2e192b24SSimon Glass 392*2e192b24SSimon Glass addr = (ulong)simple_strtoul(argv[1], NULL, 16); 393*2e192b24SSimon Glass 394*2e192b24SSimon Glass printf("\nOneNAND read: "); 395*2e192b24SSimon Glass if (arg_off_size_onenand(argc - 2, argv + 2, &ofs, &len) != 0) 396*2e192b24SSimon Glass return 1; 397*2e192b24SSimon Glass 398*2e192b24SSimon Glass ret = onenand_block_read(ofs, len, &retlen, (u8 *)addr, oob); 399*2e192b24SSimon Glass 400*2e192b24SSimon Glass printf(" %d bytes read: %s\n", retlen, ret ? "ERROR" : "OK"); 401*2e192b24SSimon Glass 402*2e192b24SSimon Glass return ret == 0 ? 0 : 1; 403*2e192b24SSimon Glass } 404*2e192b24SSimon Glass 405*2e192b24SSimon Glass static int do_onenand_write(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 406*2e192b24SSimon Glass { 407*2e192b24SSimon Glass ulong addr, ofs; 408*2e192b24SSimon Glass size_t len; 409*2e192b24SSimon Glass int ret = 0, withoob = 0; 410*2e192b24SSimon Glass size_t retlen = 0; 411*2e192b24SSimon Glass 412*2e192b24SSimon Glass if (argc < 3) 413*2e192b24SSimon Glass return CMD_RET_USAGE; 414*2e192b24SSimon Glass 415*2e192b24SSimon Glass if (strncmp(argv[0] + 6, "yaffs", 5) == 0) 416*2e192b24SSimon Glass withoob = 1; 417*2e192b24SSimon Glass 418*2e192b24SSimon Glass addr = (ulong)simple_strtoul(argv[1], NULL, 16); 419*2e192b24SSimon Glass 420*2e192b24SSimon Glass printf("\nOneNAND write: "); 421*2e192b24SSimon Glass if (arg_off_size_onenand(argc - 2, argv + 2, &ofs, &len) != 0) 422*2e192b24SSimon Glass return 1; 423*2e192b24SSimon Glass 424*2e192b24SSimon Glass ret = onenand_block_write(ofs, len, &retlen, (u8 *)addr, withoob); 425*2e192b24SSimon Glass 426*2e192b24SSimon Glass printf(" %d bytes written: %s\n", retlen, ret ? "ERROR" : "OK"); 427*2e192b24SSimon Glass 428*2e192b24SSimon Glass return ret == 0 ? 0 : 1; 429*2e192b24SSimon Glass } 430*2e192b24SSimon Glass 431*2e192b24SSimon Glass static int do_onenand_erase(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 432*2e192b24SSimon Glass { 433*2e192b24SSimon Glass ulong ofs; 434*2e192b24SSimon Glass int ret = 0; 435*2e192b24SSimon Glass size_t len; 436*2e192b24SSimon Glass int force; 437*2e192b24SSimon Glass 438*2e192b24SSimon Glass /* 439*2e192b24SSimon Glass * Syntax is: 440*2e192b24SSimon Glass * 0 1 2 3 4 441*2e192b24SSimon Glass * onenand erase [force] [off size] 442*2e192b24SSimon Glass */ 443*2e192b24SSimon Glass argc--; 444*2e192b24SSimon Glass argv++; 445*2e192b24SSimon Glass if (argc) 446*2e192b24SSimon Glass { 447*2e192b24SSimon Glass if (!strcmp("force", argv[0])) 448*2e192b24SSimon Glass { 449*2e192b24SSimon Glass force = 1; 450*2e192b24SSimon Glass argc--; 451*2e192b24SSimon Glass argv++; 452*2e192b24SSimon Glass } 453*2e192b24SSimon Glass } 454*2e192b24SSimon Glass printf("\nOneNAND erase: "); 455*2e192b24SSimon Glass 456*2e192b24SSimon Glass /* skip first two or three arguments, look for offset and size */ 457*2e192b24SSimon Glass if (arg_off_size_onenand(argc, argv, &ofs, &len) != 0) 458*2e192b24SSimon Glass return 1; 459*2e192b24SSimon Glass 460*2e192b24SSimon Glass ret = onenand_block_erase(ofs, len, force); 461*2e192b24SSimon Glass 462*2e192b24SSimon Glass printf("%s\n", ret ? "ERROR" : "OK"); 463*2e192b24SSimon Glass 464*2e192b24SSimon Glass return ret == 0 ? 0 : 1; 465*2e192b24SSimon Glass } 466*2e192b24SSimon Glass 467*2e192b24SSimon Glass static int do_onenand_test(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 468*2e192b24SSimon Glass { 469*2e192b24SSimon Glass ulong ofs; 470*2e192b24SSimon Glass int ret = 0; 471*2e192b24SSimon Glass size_t len; 472*2e192b24SSimon Glass 473*2e192b24SSimon Glass /* 474*2e192b24SSimon Glass * Syntax is: 475*2e192b24SSimon Glass * 0 1 2 3 4 476*2e192b24SSimon Glass * onenand test [force] [off size] 477*2e192b24SSimon Glass */ 478*2e192b24SSimon Glass 479*2e192b24SSimon Glass printf("\nOneNAND test: "); 480*2e192b24SSimon Glass 481*2e192b24SSimon Glass /* skip first two or three arguments, look for offset and size */ 482*2e192b24SSimon Glass if (arg_off_size_onenand(argc - 1, argv + 1, &ofs, &len) != 0) 483*2e192b24SSimon Glass return 1; 484*2e192b24SSimon Glass 485*2e192b24SSimon Glass ret = onenand_block_test(ofs, len); 486*2e192b24SSimon Glass 487*2e192b24SSimon Glass printf("%s\n", ret ? "ERROR" : "OK"); 488*2e192b24SSimon Glass 489*2e192b24SSimon Glass return ret == 0 ? 0 : 1; 490*2e192b24SSimon Glass } 491*2e192b24SSimon Glass 492*2e192b24SSimon Glass static int do_onenand_dump(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 493*2e192b24SSimon Glass { 494*2e192b24SSimon Glass ulong ofs; 495*2e192b24SSimon Glass int ret = 0; 496*2e192b24SSimon Glass char *s; 497*2e192b24SSimon Glass 498*2e192b24SSimon Glass if (argc < 2) 499*2e192b24SSimon Glass return CMD_RET_USAGE; 500*2e192b24SSimon Glass 501*2e192b24SSimon Glass s = strchr(argv[0], '.'); 502*2e192b24SSimon Glass ofs = (int)simple_strtoul(argv[1], NULL, 16); 503*2e192b24SSimon Glass 504*2e192b24SSimon Glass if (s != NULL && strcmp(s, ".oob") == 0) 505*2e192b24SSimon Glass ret = onenand_dump(mtd, ofs, 1); 506*2e192b24SSimon Glass else 507*2e192b24SSimon Glass ret = onenand_dump(mtd, ofs, 0); 508*2e192b24SSimon Glass 509*2e192b24SSimon Glass return ret == 0 ? 1 : 0; 510*2e192b24SSimon Glass } 511*2e192b24SSimon Glass 512*2e192b24SSimon Glass static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 513*2e192b24SSimon Glass { 514*2e192b24SSimon Glass int ret = 0; 515*2e192b24SSimon Glass ulong addr; 516*2e192b24SSimon Glass 517*2e192b24SSimon Glass argc -= 2; 518*2e192b24SSimon Glass argv += 2; 519*2e192b24SSimon Glass 520*2e192b24SSimon Glass if (argc <= 0) 521*2e192b24SSimon Glass return CMD_RET_USAGE; 522*2e192b24SSimon Glass 523*2e192b24SSimon Glass while (argc > 0) { 524*2e192b24SSimon Glass addr = simple_strtoul(*argv, NULL, 16); 525*2e192b24SSimon Glass 526*2e192b24SSimon Glass if (mtd_block_markbad(mtd, addr)) { 527*2e192b24SSimon Glass printf("block 0x%08lx NOT marked " 528*2e192b24SSimon Glass "as bad! ERROR %d\n", 529*2e192b24SSimon Glass addr, ret); 530*2e192b24SSimon Glass ret = 1; 531*2e192b24SSimon Glass } else { 532*2e192b24SSimon Glass printf("block 0x%08lx successfully " 533*2e192b24SSimon Glass "marked as bad\n", 534*2e192b24SSimon Glass addr); 535*2e192b24SSimon Glass } 536*2e192b24SSimon Glass --argc; 537*2e192b24SSimon Glass ++argv; 538*2e192b24SSimon Glass } 539*2e192b24SSimon Glass return ret; 540*2e192b24SSimon Glass } 541*2e192b24SSimon Glass 542*2e192b24SSimon Glass static cmd_tbl_t cmd_onenand_sub[] = { 543*2e192b24SSimon Glass U_BOOT_CMD_MKENT(info, 1, 0, do_onenand_info, "", ""), 544*2e192b24SSimon Glass U_BOOT_CMD_MKENT(bad, 1, 0, do_onenand_bad, "", ""), 545*2e192b24SSimon Glass U_BOOT_CMD_MKENT(read, 4, 0, do_onenand_read, "", ""), 546*2e192b24SSimon Glass U_BOOT_CMD_MKENT(write, 4, 0, do_onenand_write, "", ""), 547*2e192b24SSimon Glass U_BOOT_CMD_MKENT(write.yaffs, 4, 0, do_onenand_write, "", ""), 548*2e192b24SSimon Glass U_BOOT_CMD_MKENT(erase, 3, 0, do_onenand_erase, "", ""), 549*2e192b24SSimon Glass U_BOOT_CMD_MKENT(test, 3, 0, do_onenand_test, "", ""), 550*2e192b24SSimon Glass U_BOOT_CMD_MKENT(dump, 2, 0, do_onenand_dump, "", ""), 551*2e192b24SSimon Glass U_BOOT_CMD_MKENT(markbad, CONFIG_SYS_MAXARGS, 0, do_onenand_markbad, "", ""), 552*2e192b24SSimon Glass }; 553*2e192b24SSimon Glass 554*2e192b24SSimon Glass #ifdef CONFIG_NEEDS_MANUAL_RELOC 555*2e192b24SSimon Glass void onenand_reloc(void) { 556*2e192b24SSimon Glass fixup_cmdtable(cmd_onenand_sub, ARRAY_SIZE(cmd_onenand_sub)); 557*2e192b24SSimon Glass } 558*2e192b24SSimon Glass #endif 559*2e192b24SSimon Glass 560*2e192b24SSimon Glass static int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) 561*2e192b24SSimon Glass { 562*2e192b24SSimon Glass cmd_tbl_t *c; 563*2e192b24SSimon Glass 564*2e192b24SSimon Glass if (argc < 2) 565*2e192b24SSimon Glass return CMD_RET_USAGE; 566*2e192b24SSimon Glass 567*2e192b24SSimon Glass mtd = &onenand_mtd; 568*2e192b24SSimon Glass 569*2e192b24SSimon Glass /* Strip off leading 'onenand' command argument */ 570*2e192b24SSimon Glass argc--; 571*2e192b24SSimon Glass argv++; 572*2e192b24SSimon Glass 573*2e192b24SSimon Glass c = find_cmd_tbl(argv[0], &cmd_onenand_sub[0], ARRAY_SIZE(cmd_onenand_sub)); 574*2e192b24SSimon Glass 575*2e192b24SSimon Glass if (c) 576*2e192b24SSimon Glass return c->cmd(cmdtp, flag, argc, argv); 577*2e192b24SSimon Glass else 578*2e192b24SSimon Glass return CMD_RET_USAGE; 579*2e192b24SSimon Glass } 580*2e192b24SSimon Glass 581*2e192b24SSimon Glass U_BOOT_CMD( 582*2e192b24SSimon Glass onenand, CONFIG_SYS_MAXARGS, 1, do_onenand, 583*2e192b24SSimon Glass "OneNAND sub-system", 584*2e192b24SSimon Glass "info - show available OneNAND devices\n" 585*2e192b24SSimon Glass "onenand bad - show bad blocks\n" 586*2e192b24SSimon Glass "onenand read[.oob] addr off size\n" 587*2e192b24SSimon Glass "onenand write[.yaffs] addr off size\n" 588*2e192b24SSimon Glass " read/write 'size' bytes starting at offset 'off'\n" 589*2e192b24SSimon Glass " to/from memory address 'addr', skipping bad blocks.\n" 590*2e192b24SSimon Glass "onenand erase [force] [off size] - erase 'size' bytes from\n" 591*2e192b24SSimon Glass "onenand test [off size] - test 'size' bytes from\n" 592*2e192b24SSimon Glass " offset 'off' (entire device if not specified)\n" 593*2e192b24SSimon Glass "onenand dump[.oob] off - dump page\n" 594*2e192b24SSimon Glass "onenand markbad off [...] - mark bad block(s) at offset (UNSAFE)" 595*2e192b24SSimon Glass ); 596