1*a430fa06SMiquel Raynal // SPDX-License-Identifier: GPL-2.0 2*a430fa06SMiquel Raynal /* 3*a430fa06SMiquel Raynal * drivers/mtd/nand/raw/nand_util.c 4*a430fa06SMiquel Raynal * 5*a430fa06SMiquel Raynal * Copyright (C) 2006 by Weiss-Electronic GmbH. 6*a430fa06SMiquel Raynal * All rights reserved. 7*a430fa06SMiquel Raynal * 8*a430fa06SMiquel Raynal * @author: Guido Classen <clagix@gmail.com> 9*a430fa06SMiquel Raynal * @descr: NAND Flash support 10*a430fa06SMiquel Raynal * @references: borrowed heavily from Linux mtd-utils code: 11*a430fa06SMiquel Raynal * flash_eraseall.c by Arcom Control System Ltd 12*a430fa06SMiquel Raynal * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com) 13*a430fa06SMiquel Raynal * and Thomas Gleixner (tglx@linutronix.de) 14*a430fa06SMiquel Raynal * 15*a430fa06SMiquel Raynal * Copyright (C) 2008 Nokia Corporation: drop_ffs() function by 16*a430fa06SMiquel Raynal * Artem Bityutskiy <dedekind1@gmail.com> from mtd-utils 17*a430fa06SMiquel Raynal * 18*a430fa06SMiquel Raynal * Copyright 2010 Freescale Semiconductor 19*a430fa06SMiquel Raynal */ 20*a430fa06SMiquel Raynal 21*a430fa06SMiquel Raynal #include <common.h> 22*a430fa06SMiquel Raynal #include <command.h> 23*a430fa06SMiquel Raynal #include <watchdog.h> 24*a430fa06SMiquel Raynal #include <malloc.h> 25*a430fa06SMiquel Raynal #include <memalign.h> 26*a430fa06SMiquel Raynal #include <div64.h> 27*a430fa06SMiquel Raynal 28*a430fa06SMiquel Raynal #include <linux/errno.h> 29*a430fa06SMiquel Raynal #include <linux/mtd/mtd.h> 30*a430fa06SMiquel Raynal #include <nand.h> 31*a430fa06SMiquel Raynal #include <jffs2/jffs2.h> 32*a430fa06SMiquel Raynal 33*a430fa06SMiquel Raynal typedef struct erase_info erase_info_t; 34*a430fa06SMiquel Raynal typedef struct mtd_info mtd_info_t; 35*a430fa06SMiquel Raynal 36*a430fa06SMiquel Raynal /* support only for native endian JFFS2 */ 37*a430fa06SMiquel Raynal #define cpu_to_je16(x) (x) 38*a430fa06SMiquel Raynal #define cpu_to_je32(x) (x) 39*a430fa06SMiquel Raynal 40*a430fa06SMiquel Raynal /** 41*a430fa06SMiquel Raynal * nand_erase_opts: - erase NAND flash with support for various options 42*a430fa06SMiquel Raynal * (jffs2 formatting) 43*a430fa06SMiquel Raynal * 44*a430fa06SMiquel Raynal * @param mtd nand mtd instance to erase 45*a430fa06SMiquel Raynal * @param opts options, @see struct nand_erase_options 46*a430fa06SMiquel Raynal * @return 0 in case of success 47*a430fa06SMiquel Raynal * 48*a430fa06SMiquel Raynal * This code is ported from flash_eraseall.c from Linux mtd utils by 49*a430fa06SMiquel Raynal * Arcom Control System Ltd. 50*a430fa06SMiquel Raynal */ 51*a430fa06SMiquel Raynal int nand_erase_opts(struct mtd_info *mtd, 52*a430fa06SMiquel Raynal const nand_erase_options_t *opts) 53*a430fa06SMiquel Raynal { 54*a430fa06SMiquel Raynal struct jffs2_unknown_node cleanmarker; 55*a430fa06SMiquel Raynal erase_info_t erase; 56*a430fa06SMiquel Raynal unsigned long erase_length, erased_length; /* in blocks */ 57*a430fa06SMiquel Raynal int result; 58*a430fa06SMiquel Raynal int percent_complete = -1; 59*a430fa06SMiquel Raynal const char *mtd_device = mtd->name; 60*a430fa06SMiquel Raynal struct mtd_oob_ops oob_opts; 61*a430fa06SMiquel Raynal struct nand_chip *chip = mtd_to_nand(mtd); 62*a430fa06SMiquel Raynal 63*a430fa06SMiquel Raynal if ((opts->offset & (mtd->erasesize - 1)) != 0) { 64*a430fa06SMiquel Raynal printf("Attempt to erase non block-aligned data\n"); 65*a430fa06SMiquel Raynal return -1; 66*a430fa06SMiquel Raynal } 67*a430fa06SMiquel Raynal 68*a430fa06SMiquel Raynal memset(&erase, 0, sizeof(erase)); 69*a430fa06SMiquel Raynal memset(&oob_opts, 0, sizeof(oob_opts)); 70*a430fa06SMiquel Raynal 71*a430fa06SMiquel Raynal erase.mtd = mtd; 72*a430fa06SMiquel Raynal erase.len = mtd->erasesize; 73*a430fa06SMiquel Raynal erase.addr = opts->offset; 74*a430fa06SMiquel Raynal erase_length = lldiv(opts->length + mtd->erasesize - 1, 75*a430fa06SMiquel Raynal mtd->erasesize); 76*a430fa06SMiquel Raynal 77*a430fa06SMiquel Raynal cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); 78*a430fa06SMiquel Raynal cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); 79*a430fa06SMiquel Raynal cleanmarker.totlen = cpu_to_je32(8); 80*a430fa06SMiquel Raynal 81*a430fa06SMiquel Raynal /* scrub option allows to erase badblock. To prevent internal 82*a430fa06SMiquel Raynal * check from erase() method, set block check method to dummy 83*a430fa06SMiquel Raynal * and disable bad block table while erasing. 84*a430fa06SMiquel Raynal */ 85*a430fa06SMiquel Raynal if (opts->scrub) { 86*a430fa06SMiquel Raynal erase.scrub = opts->scrub; 87*a430fa06SMiquel Raynal /* 88*a430fa06SMiquel Raynal * We don't need the bad block table anymore... 89*a430fa06SMiquel Raynal * after scrub, there are no bad blocks left! 90*a430fa06SMiquel Raynal */ 91*a430fa06SMiquel Raynal if (chip->bbt) { 92*a430fa06SMiquel Raynal kfree(chip->bbt); 93*a430fa06SMiquel Raynal } 94*a430fa06SMiquel Raynal chip->bbt = NULL; 95*a430fa06SMiquel Raynal chip->options &= ~NAND_BBT_SCANNED; 96*a430fa06SMiquel Raynal } 97*a430fa06SMiquel Raynal 98*a430fa06SMiquel Raynal for (erased_length = 0; 99*a430fa06SMiquel Raynal erased_length < erase_length; 100*a430fa06SMiquel Raynal erase.addr += mtd->erasesize) { 101*a430fa06SMiquel Raynal 102*a430fa06SMiquel Raynal WATCHDOG_RESET(); 103*a430fa06SMiquel Raynal 104*a430fa06SMiquel Raynal if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { 105*a430fa06SMiquel Raynal puts("Size of erase exceeds limit\n"); 106*a430fa06SMiquel Raynal return -EFBIG; 107*a430fa06SMiquel Raynal } 108*a430fa06SMiquel Raynal if (!opts->scrub) { 109*a430fa06SMiquel Raynal int ret = mtd_block_isbad(mtd, erase.addr); 110*a430fa06SMiquel Raynal if (ret > 0) { 111*a430fa06SMiquel Raynal if (!opts->quiet) 112*a430fa06SMiquel Raynal printf("\rSkipping bad block at " 113*a430fa06SMiquel Raynal "0x%08llx " 114*a430fa06SMiquel Raynal " \n", 115*a430fa06SMiquel Raynal erase.addr); 116*a430fa06SMiquel Raynal 117*a430fa06SMiquel Raynal if (!opts->spread) 118*a430fa06SMiquel Raynal erased_length++; 119*a430fa06SMiquel Raynal 120*a430fa06SMiquel Raynal continue; 121*a430fa06SMiquel Raynal 122*a430fa06SMiquel Raynal } else if (ret < 0) { 123*a430fa06SMiquel Raynal printf("\n%s: MTD get bad block failed: %d\n", 124*a430fa06SMiquel Raynal mtd_device, 125*a430fa06SMiquel Raynal ret); 126*a430fa06SMiquel Raynal return -1; 127*a430fa06SMiquel Raynal } 128*a430fa06SMiquel Raynal } 129*a430fa06SMiquel Raynal 130*a430fa06SMiquel Raynal erased_length++; 131*a430fa06SMiquel Raynal 132*a430fa06SMiquel Raynal result = mtd_erase(mtd, &erase); 133*a430fa06SMiquel Raynal if (result != 0) { 134*a430fa06SMiquel Raynal printf("\n%s: MTD Erase failure: %d\n", 135*a430fa06SMiquel Raynal mtd_device, result); 136*a430fa06SMiquel Raynal continue; 137*a430fa06SMiquel Raynal } 138*a430fa06SMiquel Raynal 139*a430fa06SMiquel Raynal /* format for JFFS2 ? */ 140*a430fa06SMiquel Raynal if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) { 141*a430fa06SMiquel Raynal struct mtd_oob_ops ops; 142*a430fa06SMiquel Raynal ops.ooblen = 8; 143*a430fa06SMiquel Raynal ops.datbuf = NULL; 144*a430fa06SMiquel Raynal ops.oobbuf = (uint8_t *)&cleanmarker; 145*a430fa06SMiquel Raynal ops.ooboffs = 0; 146*a430fa06SMiquel Raynal ops.mode = MTD_OPS_AUTO_OOB; 147*a430fa06SMiquel Raynal 148*a430fa06SMiquel Raynal result = mtd_write_oob(mtd, erase.addr, &ops); 149*a430fa06SMiquel Raynal if (result != 0) { 150*a430fa06SMiquel Raynal printf("\n%s: MTD writeoob failure: %d\n", 151*a430fa06SMiquel Raynal mtd_device, result); 152*a430fa06SMiquel Raynal continue; 153*a430fa06SMiquel Raynal } 154*a430fa06SMiquel Raynal } 155*a430fa06SMiquel Raynal 156*a430fa06SMiquel Raynal if (!opts->quiet) { 157*a430fa06SMiquel Raynal unsigned long long n = erased_length * 100ULL; 158*a430fa06SMiquel Raynal int percent; 159*a430fa06SMiquel Raynal 160*a430fa06SMiquel Raynal do_div(n, erase_length); 161*a430fa06SMiquel Raynal percent = (int)n; 162*a430fa06SMiquel Raynal 163*a430fa06SMiquel Raynal /* output progress message only at whole percent 164*a430fa06SMiquel Raynal * steps to reduce the number of messages printed 165*a430fa06SMiquel Raynal * on (slow) serial consoles 166*a430fa06SMiquel Raynal */ 167*a430fa06SMiquel Raynal if (percent != percent_complete) { 168*a430fa06SMiquel Raynal percent_complete = percent; 169*a430fa06SMiquel Raynal 170*a430fa06SMiquel Raynal printf("\rErasing at 0x%llx -- %3d%% complete.", 171*a430fa06SMiquel Raynal erase.addr, percent); 172*a430fa06SMiquel Raynal 173*a430fa06SMiquel Raynal if (opts->jffs2 && result == 0) 174*a430fa06SMiquel Raynal printf(" Cleanmarker written at 0x%llx.", 175*a430fa06SMiquel Raynal erase.addr); 176*a430fa06SMiquel Raynal } 177*a430fa06SMiquel Raynal } 178*a430fa06SMiquel Raynal } 179*a430fa06SMiquel Raynal if (!opts->quiet) 180*a430fa06SMiquel Raynal printf("\n"); 181*a430fa06SMiquel Raynal 182*a430fa06SMiquel Raynal return 0; 183*a430fa06SMiquel Raynal } 184*a430fa06SMiquel Raynal 185*a430fa06SMiquel Raynal #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK 186*a430fa06SMiquel Raynal 187*a430fa06SMiquel Raynal #define NAND_CMD_LOCK_TIGHT 0x2c 188*a430fa06SMiquel Raynal #define NAND_CMD_LOCK_STATUS 0x7a 189*a430fa06SMiquel Raynal 190*a430fa06SMiquel Raynal /****************************************************************************** 191*a430fa06SMiquel Raynal * Support for locking / unlocking operations of some NAND devices 192*a430fa06SMiquel Raynal *****************************************************************************/ 193*a430fa06SMiquel Raynal 194*a430fa06SMiquel Raynal /** 195*a430fa06SMiquel Raynal * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT 196*a430fa06SMiquel Raynal * state 197*a430fa06SMiquel Raynal * 198*a430fa06SMiquel Raynal * @param mtd nand mtd instance 199*a430fa06SMiquel Raynal * @param tight bring device in lock tight mode 200*a430fa06SMiquel Raynal * 201*a430fa06SMiquel Raynal * @return 0 on success, -1 in case of error 202*a430fa06SMiquel Raynal * 203*a430fa06SMiquel Raynal * The lock / lock-tight command only applies to the whole chip. To get some 204*a430fa06SMiquel Raynal * parts of the chip lock and others unlocked use the following sequence: 205*a430fa06SMiquel Raynal * 206*a430fa06SMiquel Raynal * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin) 207*a430fa06SMiquel Raynal * - Call nand_unlock() once for each consecutive area to be unlocked 208*a430fa06SMiquel Raynal * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1) 209*a430fa06SMiquel Raynal * 210*a430fa06SMiquel Raynal * If the device is in lock-tight state software can't change the 211*a430fa06SMiquel Raynal * current active lock/unlock state of all pages. nand_lock() / nand_unlock() 212*a430fa06SMiquel Raynal * calls will fail. It is only posible to leave lock-tight state by 213*a430fa06SMiquel Raynal * an hardware signal (low pulse on _WP pin) or by power down. 214*a430fa06SMiquel Raynal */ 215*a430fa06SMiquel Raynal int nand_lock(struct mtd_info *mtd, int tight) 216*a430fa06SMiquel Raynal { 217*a430fa06SMiquel Raynal int ret = 0; 218*a430fa06SMiquel Raynal int status; 219*a430fa06SMiquel Raynal struct nand_chip *chip = mtd_to_nand(mtd); 220*a430fa06SMiquel Raynal 221*a430fa06SMiquel Raynal /* select the NAND device */ 222*a430fa06SMiquel Raynal chip->select_chip(mtd, 0); 223*a430fa06SMiquel Raynal 224*a430fa06SMiquel Raynal /* check the Lock Tight Status */ 225*a430fa06SMiquel Raynal chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, 0); 226*a430fa06SMiquel Raynal if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { 227*a430fa06SMiquel Raynal printf("nand_lock: Device is locked tight!\n"); 228*a430fa06SMiquel Raynal ret = -1; 229*a430fa06SMiquel Raynal goto out; 230*a430fa06SMiquel Raynal } 231*a430fa06SMiquel Raynal 232*a430fa06SMiquel Raynal chip->cmdfunc(mtd, 233*a430fa06SMiquel Raynal (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), 234*a430fa06SMiquel Raynal -1, -1); 235*a430fa06SMiquel Raynal 236*a430fa06SMiquel Raynal /* call wait ready function */ 237*a430fa06SMiquel Raynal status = chip->waitfunc(mtd, chip); 238*a430fa06SMiquel Raynal 239*a430fa06SMiquel Raynal /* see if device thinks it succeeded */ 240*a430fa06SMiquel Raynal if (status & 0x01) { 241*a430fa06SMiquel Raynal ret = -1; 242*a430fa06SMiquel Raynal } 243*a430fa06SMiquel Raynal 244*a430fa06SMiquel Raynal out: 245*a430fa06SMiquel Raynal /* de-select the NAND device */ 246*a430fa06SMiquel Raynal chip->select_chip(mtd, -1); 247*a430fa06SMiquel Raynal return ret; 248*a430fa06SMiquel Raynal } 249*a430fa06SMiquel Raynal 250*a430fa06SMiquel Raynal /** 251*a430fa06SMiquel Raynal * nand_get_lock_status: - query current lock state from one page of NAND 252*a430fa06SMiquel Raynal * flash 253*a430fa06SMiquel Raynal * 254*a430fa06SMiquel Raynal * @param mtd nand mtd instance 255*a430fa06SMiquel Raynal * @param offset page address to query (must be page-aligned!) 256*a430fa06SMiquel Raynal * 257*a430fa06SMiquel Raynal * @return -1 in case of error 258*a430fa06SMiquel Raynal * >0 lock status: 259*a430fa06SMiquel Raynal * bitfield with the following combinations: 260*a430fa06SMiquel Raynal * NAND_LOCK_STATUS_TIGHT: page in tight state 261*a430fa06SMiquel Raynal * NAND_LOCK_STATUS_UNLOCK: page unlocked 262*a430fa06SMiquel Raynal * 263*a430fa06SMiquel Raynal */ 264*a430fa06SMiquel Raynal int nand_get_lock_status(struct mtd_info *mtd, loff_t offset) 265*a430fa06SMiquel Raynal { 266*a430fa06SMiquel Raynal int ret = 0; 267*a430fa06SMiquel Raynal int chipnr; 268*a430fa06SMiquel Raynal int page; 269*a430fa06SMiquel Raynal struct nand_chip *chip = mtd_to_nand(mtd); 270*a430fa06SMiquel Raynal 271*a430fa06SMiquel Raynal /* select the NAND device */ 272*a430fa06SMiquel Raynal chipnr = (int)(offset >> chip->chip_shift); 273*a430fa06SMiquel Raynal chip->select_chip(mtd, chipnr); 274*a430fa06SMiquel Raynal 275*a430fa06SMiquel Raynal 276*a430fa06SMiquel Raynal if ((offset & (mtd->writesize - 1)) != 0) { 277*a430fa06SMiquel Raynal printf("nand_get_lock_status: " 278*a430fa06SMiquel Raynal "Start address must be beginning of " 279*a430fa06SMiquel Raynal "nand page!\n"); 280*a430fa06SMiquel Raynal ret = -1; 281*a430fa06SMiquel Raynal goto out; 282*a430fa06SMiquel Raynal } 283*a430fa06SMiquel Raynal 284*a430fa06SMiquel Raynal /* check the Lock Status */ 285*a430fa06SMiquel Raynal page = (int)(offset >> chip->page_shift); 286*a430fa06SMiquel Raynal chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); 287*a430fa06SMiquel Raynal 288*a430fa06SMiquel Raynal ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT 289*a430fa06SMiquel Raynal | NAND_LOCK_STATUS_UNLOCK); 290*a430fa06SMiquel Raynal 291*a430fa06SMiquel Raynal out: 292*a430fa06SMiquel Raynal /* de-select the NAND device */ 293*a430fa06SMiquel Raynal chip->select_chip(mtd, -1); 294*a430fa06SMiquel Raynal return ret; 295*a430fa06SMiquel Raynal } 296*a430fa06SMiquel Raynal 297*a430fa06SMiquel Raynal /** 298*a430fa06SMiquel Raynal * nand_unlock: - Unlock area of NAND pages 299*a430fa06SMiquel Raynal * only one consecutive area can be unlocked at one time! 300*a430fa06SMiquel Raynal * 301*a430fa06SMiquel Raynal * @param mtd nand mtd instance 302*a430fa06SMiquel Raynal * @param start start byte address 303*a430fa06SMiquel Raynal * @param length number of bytes to unlock (must be a multiple of 304*a430fa06SMiquel Raynal * page size mtd->writesize) 305*a430fa06SMiquel Raynal * @param allexcept if set, unlock everything not selected 306*a430fa06SMiquel Raynal * 307*a430fa06SMiquel Raynal * @return 0 on success, -1 in case of error 308*a430fa06SMiquel Raynal */ 309*a430fa06SMiquel Raynal int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length, 310*a430fa06SMiquel Raynal int allexcept) 311*a430fa06SMiquel Raynal { 312*a430fa06SMiquel Raynal int ret = 0; 313*a430fa06SMiquel Raynal int chipnr; 314*a430fa06SMiquel Raynal int status; 315*a430fa06SMiquel Raynal int page; 316*a430fa06SMiquel Raynal struct nand_chip *chip = mtd_to_nand(mtd); 317*a430fa06SMiquel Raynal 318*a430fa06SMiquel Raynal debug("nand_unlock%s: start: %08llx, length: %zd!\n", 319*a430fa06SMiquel Raynal allexcept ? " (allexcept)" : "", start, length); 320*a430fa06SMiquel Raynal 321*a430fa06SMiquel Raynal /* select the NAND device */ 322*a430fa06SMiquel Raynal chipnr = (int)(start >> chip->chip_shift); 323*a430fa06SMiquel Raynal chip->select_chip(mtd, chipnr); 324*a430fa06SMiquel Raynal 325*a430fa06SMiquel Raynal /* check the WP bit */ 326*a430fa06SMiquel Raynal chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); 327*a430fa06SMiquel Raynal if (!(chip->read_byte(mtd) & NAND_STATUS_WP)) { 328*a430fa06SMiquel Raynal printf("nand_unlock: Device is write protected!\n"); 329*a430fa06SMiquel Raynal ret = -1; 330*a430fa06SMiquel Raynal goto out; 331*a430fa06SMiquel Raynal } 332*a430fa06SMiquel Raynal 333*a430fa06SMiquel Raynal /* check the Lock Tight Status */ 334*a430fa06SMiquel Raynal page = (int)(start >> chip->page_shift); 335*a430fa06SMiquel Raynal chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask); 336*a430fa06SMiquel Raynal if (chip->read_byte(mtd) & NAND_LOCK_STATUS_TIGHT) { 337*a430fa06SMiquel Raynal printf("nand_unlock: Device is locked tight!\n"); 338*a430fa06SMiquel Raynal ret = -1; 339*a430fa06SMiquel Raynal goto out; 340*a430fa06SMiquel Raynal } 341*a430fa06SMiquel Raynal 342*a430fa06SMiquel Raynal if ((start & (mtd->erasesize - 1)) != 0) { 343*a430fa06SMiquel Raynal printf("nand_unlock: Start address must be beginning of " 344*a430fa06SMiquel Raynal "nand block!\n"); 345*a430fa06SMiquel Raynal ret = -1; 346*a430fa06SMiquel Raynal goto out; 347*a430fa06SMiquel Raynal } 348*a430fa06SMiquel Raynal 349*a430fa06SMiquel Raynal if (length == 0 || (length & (mtd->erasesize - 1)) != 0) { 350*a430fa06SMiquel Raynal printf("nand_unlock: Length must be a multiple of nand block " 351*a430fa06SMiquel Raynal "size %08x!\n", mtd->erasesize); 352*a430fa06SMiquel Raynal ret = -1; 353*a430fa06SMiquel Raynal goto out; 354*a430fa06SMiquel Raynal } 355*a430fa06SMiquel Raynal 356*a430fa06SMiquel Raynal /* 357*a430fa06SMiquel Raynal * Set length so that the last address is set to the 358*a430fa06SMiquel Raynal * starting address of the last block 359*a430fa06SMiquel Raynal */ 360*a430fa06SMiquel Raynal length -= mtd->erasesize; 361*a430fa06SMiquel Raynal 362*a430fa06SMiquel Raynal /* submit address of first page to unlock */ 363*a430fa06SMiquel Raynal chip->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & chip->pagemask); 364*a430fa06SMiquel Raynal 365*a430fa06SMiquel Raynal /* submit ADDRESS of LAST page to unlock */ 366*a430fa06SMiquel Raynal page += (int)(length >> chip->page_shift); 367*a430fa06SMiquel Raynal 368*a430fa06SMiquel Raynal /* 369*a430fa06SMiquel Raynal * Page addresses for unlocking are supposed to be block-aligned. 370*a430fa06SMiquel Raynal * At least some NAND chips use the low bit to indicate that the 371*a430fa06SMiquel Raynal * page range should be inverted. 372*a430fa06SMiquel Raynal */ 373*a430fa06SMiquel Raynal if (allexcept) 374*a430fa06SMiquel Raynal page |= 1; 375*a430fa06SMiquel Raynal 376*a430fa06SMiquel Raynal chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask); 377*a430fa06SMiquel Raynal 378*a430fa06SMiquel Raynal /* call wait ready function */ 379*a430fa06SMiquel Raynal status = chip->waitfunc(mtd, chip); 380*a430fa06SMiquel Raynal /* see if device thinks it succeeded */ 381*a430fa06SMiquel Raynal if (status & 0x01) { 382*a430fa06SMiquel Raynal /* there was an error */ 383*a430fa06SMiquel Raynal ret = -1; 384*a430fa06SMiquel Raynal goto out; 385*a430fa06SMiquel Raynal } 386*a430fa06SMiquel Raynal 387*a430fa06SMiquel Raynal out: 388*a430fa06SMiquel Raynal /* de-select the NAND device */ 389*a430fa06SMiquel Raynal chip->select_chip(mtd, -1); 390*a430fa06SMiquel Raynal return ret; 391*a430fa06SMiquel Raynal } 392*a430fa06SMiquel Raynal #endif 393*a430fa06SMiquel Raynal 394*a430fa06SMiquel Raynal /** 395*a430fa06SMiquel Raynal * check_skip_len 396*a430fa06SMiquel Raynal * 397*a430fa06SMiquel Raynal * Check if there are any bad blocks, and whether length including bad 398*a430fa06SMiquel Raynal * blocks fits into device 399*a430fa06SMiquel Raynal * 400*a430fa06SMiquel Raynal * @param mtd nand mtd instance 401*a430fa06SMiquel Raynal * @param offset offset in flash 402*a430fa06SMiquel Raynal * @param length image length 403*a430fa06SMiquel Raynal * @param used length of flash needed for the requested length 404*a430fa06SMiquel Raynal * @return 0 if the image fits and there are no bad blocks 405*a430fa06SMiquel Raynal * 1 if the image fits, but there are bad blocks 406*a430fa06SMiquel Raynal * -1 if the image does not fit 407*a430fa06SMiquel Raynal */ 408*a430fa06SMiquel Raynal static int check_skip_len(struct mtd_info *mtd, loff_t offset, size_t length, 409*a430fa06SMiquel Raynal size_t *used) 410*a430fa06SMiquel Raynal { 411*a430fa06SMiquel Raynal size_t len_excl_bad = 0; 412*a430fa06SMiquel Raynal int ret = 0; 413*a430fa06SMiquel Raynal 414*a430fa06SMiquel Raynal while (len_excl_bad < length) { 415*a430fa06SMiquel Raynal size_t block_len, block_off; 416*a430fa06SMiquel Raynal loff_t block_start; 417*a430fa06SMiquel Raynal 418*a430fa06SMiquel Raynal if (offset >= mtd->size) 419*a430fa06SMiquel Raynal return -1; 420*a430fa06SMiquel Raynal 421*a430fa06SMiquel Raynal block_start = offset & ~(loff_t)(mtd->erasesize - 1); 422*a430fa06SMiquel Raynal block_off = offset & (mtd->erasesize - 1); 423*a430fa06SMiquel Raynal block_len = mtd->erasesize - block_off; 424*a430fa06SMiquel Raynal 425*a430fa06SMiquel Raynal if (!nand_block_isbad(mtd, block_start)) 426*a430fa06SMiquel Raynal len_excl_bad += block_len; 427*a430fa06SMiquel Raynal else 428*a430fa06SMiquel Raynal ret = 1; 429*a430fa06SMiquel Raynal 430*a430fa06SMiquel Raynal offset += block_len; 431*a430fa06SMiquel Raynal *used += block_len; 432*a430fa06SMiquel Raynal } 433*a430fa06SMiquel Raynal 434*a430fa06SMiquel Raynal /* If the length is not a multiple of block_len, adjust. */ 435*a430fa06SMiquel Raynal if (len_excl_bad > length) 436*a430fa06SMiquel Raynal *used -= (len_excl_bad - length); 437*a430fa06SMiquel Raynal 438*a430fa06SMiquel Raynal return ret; 439*a430fa06SMiquel Raynal } 440*a430fa06SMiquel Raynal 441*a430fa06SMiquel Raynal #ifdef CONFIG_CMD_NAND_TRIMFFS 442*a430fa06SMiquel Raynal static size_t drop_ffs(const struct mtd_info *mtd, const u_char *buf, 443*a430fa06SMiquel Raynal const size_t *len) 444*a430fa06SMiquel Raynal { 445*a430fa06SMiquel Raynal size_t l = *len; 446*a430fa06SMiquel Raynal ssize_t i; 447*a430fa06SMiquel Raynal 448*a430fa06SMiquel Raynal for (i = l - 1; i >= 0; i--) 449*a430fa06SMiquel Raynal if (buf[i] != 0xFF) 450*a430fa06SMiquel Raynal break; 451*a430fa06SMiquel Raynal 452*a430fa06SMiquel Raynal /* The resulting length must be aligned to the minimum flash I/O size */ 453*a430fa06SMiquel Raynal l = i + 1; 454*a430fa06SMiquel Raynal l = (l + mtd->writesize - 1) / mtd->writesize; 455*a430fa06SMiquel Raynal l *= mtd->writesize; 456*a430fa06SMiquel Raynal 457*a430fa06SMiquel Raynal /* 458*a430fa06SMiquel Raynal * since the input length may be unaligned, prevent access past the end 459*a430fa06SMiquel Raynal * of the buffer 460*a430fa06SMiquel Raynal */ 461*a430fa06SMiquel Raynal return min(l, *len); 462*a430fa06SMiquel Raynal } 463*a430fa06SMiquel Raynal #endif 464*a430fa06SMiquel Raynal 465*a430fa06SMiquel Raynal /** 466*a430fa06SMiquel Raynal * nand_verify_page_oob: 467*a430fa06SMiquel Raynal * 468*a430fa06SMiquel Raynal * Verify a page of NAND flash, including the OOB. 469*a430fa06SMiquel Raynal * Reads page of NAND and verifies the contents and OOB against the 470*a430fa06SMiquel Raynal * values in ops. 471*a430fa06SMiquel Raynal * 472*a430fa06SMiquel Raynal * @param mtd nand mtd instance 473*a430fa06SMiquel Raynal * @param ops MTD operations, including data to verify 474*a430fa06SMiquel Raynal * @param ofs offset in flash 475*a430fa06SMiquel Raynal * @return 0 in case of success 476*a430fa06SMiquel Raynal */ 477*a430fa06SMiquel Raynal int nand_verify_page_oob(struct mtd_info *mtd, struct mtd_oob_ops *ops, 478*a430fa06SMiquel Raynal loff_t ofs) 479*a430fa06SMiquel Raynal { 480*a430fa06SMiquel Raynal int rval; 481*a430fa06SMiquel Raynal struct mtd_oob_ops vops; 482*a430fa06SMiquel Raynal size_t verlen = mtd->writesize + mtd->oobsize; 483*a430fa06SMiquel Raynal 484*a430fa06SMiquel Raynal memcpy(&vops, ops, sizeof(vops)); 485*a430fa06SMiquel Raynal 486*a430fa06SMiquel Raynal vops.datbuf = memalign(ARCH_DMA_MINALIGN, verlen); 487*a430fa06SMiquel Raynal 488*a430fa06SMiquel Raynal if (!vops.datbuf) 489*a430fa06SMiquel Raynal return -ENOMEM; 490*a430fa06SMiquel Raynal 491*a430fa06SMiquel Raynal vops.oobbuf = vops.datbuf + mtd->writesize; 492*a430fa06SMiquel Raynal 493*a430fa06SMiquel Raynal rval = mtd_read_oob(mtd, ofs, &vops); 494*a430fa06SMiquel Raynal if (!rval) 495*a430fa06SMiquel Raynal rval = memcmp(ops->datbuf, vops.datbuf, vops.len); 496*a430fa06SMiquel Raynal if (!rval) 497*a430fa06SMiquel Raynal rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen); 498*a430fa06SMiquel Raynal 499*a430fa06SMiquel Raynal free(vops.datbuf); 500*a430fa06SMiquel Raynal 501*a430fa06SMiquel Raynal return rval ? -EIO : 0; 502*a430fa06SMiquel Raynal } 503*a430fa06SMiquel Raynal 504*a430fa06SMiquel Raynal /** 505*a430fa06SMiquel Raynal * nand_verify: 506*a430fa06SMiquel Raynal * 507*a430fa06SMiquel Raynal * Verify a region of NAND flash. 508*a430fa06SMiquel Raynal * Reads NAND in page-sized chunks and verifies the contents against 509*a430fa06SMiquel Raynal * the contents of a buffer. The offset into the NAND must be 510*a430fa06SMiquel Raynal * page-aligned, and the function doesn't handle skipping bad blocks. 511*a430fa06SMiquel Raynal * 512*a430fa06SMiquel Raynal * @param mtd nand mtd instance 513*a430fa06SMiquel Raynal * @param ofs offset in flash 514*a430fa06SMiquel Raynal * @param len buffer length 515*a430fa06SMiquel Raynal * @param buf buffer to read from 516*a430fa06SMiquel Raynal * @return 0 in case of success 517*a430fa06SMiquel Raynal */ 518*a430fa06SMiquel Raynal int nand_verify(struct mtd_info *mtd, loff_t ofs, size_t len, u_char *buf) 519*a430fa06SMiquel Raynal { 520*a430fa06SMiquel Raynal int rval = 0; 521*a430fa06SMiquel Raynal size_t verofs; 522*a430fa06SMiquel Raynal size_t verlen = mtd->writesize; 523*a430fa06SMiquel Raynal uint8_t *verbuf = memalign(ARCH_DMA_MINALIGN, verlen); 524*a430fa06SMiquel Raynal 525*a430fa06SMiquel Raynal if (!verbuf) 526*a430fa06SMiquel Raynal return -ENOMEM; 527*a430fa06SMiquel Raynal 528*a430fa06SMiquel Raynal /* Read the NAND back in page-size groups to limit malloc size */ 529*a430fa06SMiquel Raynal for (verofs = ofs; verofs < ofs + len; 530*a430fa06SMiquel Raynal verofs += verlen, buf += verlen) { 531*a430fa06SMiquel Raynal verlen = min(mtd->writesize, (uint32_t)(ofs + len - verofs)); 532*a430fa06SMiquel Raynal rval = nand_read(mtd, verofs, &verlen, verbuf); 533*a430fa06SMiquel Raynal if (!rval || (rval == -EUCLEAN)) 534*a430fa06SMiquel Raynal rval = memcmp(buf, verbuf, verlen); 535*a430fa06SMiquel Raynal 536*a430fa06SMiquel Raynal if (rval) 537*a430fa06SMiquel Raynal break; 538*a430fa06SMiquel Raynal } 539*a430fa06SMiquel Raynal 540*a430fa06SMiquel Raynal free(verbuf); 541*a430fa06SMiquel Raynal 542*a430fa06SMiquel Raynal return rval ? -EIO : 0; 543*a430fa06SMiquel Raynal } 544*a430fa06SMiquel Raynal 545*a430fa06SMiquel Raynal 546*a430fa06SMiquel Raynal 547*a430fa06SMiquel Raynal /** 548*a430fa06SMiquel Raynal * nand_write_skip_bad: 549*a430fa06SMiquel Raynal * 550*a430fa06SMiquel Raynal * Write image to NAND flash. 551*a430fa06SMiquel Raynal * Blocks that are marked bad are skipped and the is written to the next 552*a430fa06SMiquel Raynal * block instead as long as the image is short enough to fit even after 553*a430fa06SMiquel Raynal * skipping the bad blocks. Due to bad blocks we may not be able to 554*a430fa06SMiquel Raynal * perform the requested write. In the case where the write would 555*a430fa06SMiquel Raynal * extend beyond the end of the NAND device, both length and actual (if 556*a430fa06SMiquel Raynal * not NULL) are set to 0. In the case where the write would extend 557*a430fa06SMiquel Raynal * beyond the limit we are passed, length is set to 0 and actual is set 558*a430fa06SMiquel Raynal * to the required length. 559*a430fa06SMiquel Raynal * 560*a430fa06SMiquel Raynal * @param mtd nand mtd instance 561*a430fa06SMiquel Raynal * @param offset offset in flash 562*a430fa06SMiquel Raynal * @param length buffer length 563*a430fa06SMiquel Raynal * @param actual set to size required to write length worth of 564*a430fa06SMiquel Raynal * buffer or 0 on error, if not NULL 565*a430fa06SMiquel Raynal * @param lim maximum size that actual may be in order to not 566*a430fa06SMiquel Raynal * exceed the buffer 567*a430fa06SMiquel Raynal * @param buffer buffer to read from 568*a430fa06SMiquel Raynal * @param flags flags modifying the behaviour of the write to NAND 569*a430fa06SMiquel Raynal * @return 0 in case of success 570*a430fa06SMiquel Raynal */ 571*a430fa06SMiquel Raynal int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, 572*a430fa06SMiquel Raynal size_t *actual, loff_t lim, u_char *buffer, int flags) 573*a430fa06SMiquel Raynal { 574*a430fa06SMiquel Raynal int rval = 0, blocksize; 575*a430fa06SMiquel Raynal size_t left_to_write = *length; 576*a430fa06SMiquel Raynal size_t used_for_write = 0; 577*a430fa06SMiquel Raynal u_char *p_buffer = buffer; 578*a430fa06SMiquel Raynal int need_skip; 579*a430fa06SMiquel Raynal 580*a430fa06SMiquel Raynal if (actual) 581*a430fa06SMiquel Raynal *actual = 0; 582*a430fa06SMiquel Raynal 583*a430fa06SMiquel Raynal blocksize = mtd->erasesize; 584*a430fa06SMiquel Raynal 585*a430fa06SMiquel Raynal /* 586*a430fa06SMiquel Raynal * nand_write() handles unaligned, partial page writes. 587*a430fa06SMiquel Raynal * 588*a430fa06SMiquel Raynal * We allow length to be unaligned, for convenience in 589*a430fa06SMiquel Raynal * using the $filesize variable. 590*a430fa06SMiquel Raynal * 591*a430fa06SMiquel Raynal * However, starting at an unaligned offset makes the 592*a430fa06SMiquel Raynal * semantics of bad block skipping ambiguous (really, 593*a430fa06SMiquel Raynal * you should only start a block skipping access at a 594*a430fa06SMiquel Raynal * partition boundary). So don't try to handle that. 595*a430fa06SMiquel Raynal */ 596*a430fa06SMiquel Raynal if ((offset & (mtd->writesize - 1)) != 0) { 597*a430fa06SMiquel Raynal printf("Attempt to write non page-aligned data\n"); 598*a430fa06SMiquel Raynal *length = 0; 599*a430fa06SMiquel Raynal return -EINVAL; 600*a430fa06SMiquel Raynal } 601*a430fa06SMiquel Raynal 602*a430fa06SMiquel Raynal need_skip = check_skip_len(mtd, offset, *length, &used_for_write); 603*a430fa06SMiquel Raynal 604*a430fa06SMiquel Raynal if (actual) 605*a430fa06SMiquel Raynal *actual = used_for_write; 606*a430fa06SMiquel Raynal 607*a430fa06SMiquel Raynal if (need_skip < 0) { 608*a430fa06SMiquel Raynal printf("Attempt to write outside the flash area\n"); 609*a430fa06SMiquel Raynal *length = 0; 610*a430fa06SMiquel Raynal return -EINVAL; 611*a430fa06SMiquel Raynal } 612*a430fa06SMiquel Raynal 613*a430fa06SMiquel Raynal if (used_for_write > lim) { 614*a430fa06SMiquel Raynal puts("Size of write exceeds partition or device limit\n"); 615*a430fa06SMiquel Raynal *length = 0; 616*a430fa06SMiquel Raynal return -EFBIG; 617*a430fa06SMiquel Raynal } 618*a430fa06SMiquel Raynal 619*a430fa06SMiquel Raynal if (!need_skip && !(flags & WITH_DROP_FFS)) { 620*a430fa06SMiquel Raynal rval = nand_write(mtd, offset, length, buffer); 621*a430fa06SMiquel Raynal 622*a430fa06SMiquel Raynal if ((flags & WITH_WR_VERIFY) && !rval) 623*a430fa06SMiquel Raynal rval = nand_verify(mtd, offset, *length, buffer); 624*a430fa06SMiquel Raynal 625*a430fa06SMiquel Raynal if (rval == 0) 626*a430fa06SMiquel Raynal return 0; 627*a430fa06SMiquel Raynal 628*a430fa06SMiquel Raynal *length = 0; 629*a430fa06SMiquel Raynal printf("NAND write to offset %llx failed %d\n", 630*a430fa06SMiquel Raynal offset, rval); 631*a430fa06SMiquel Raynal return rval; 632*a430fa06SMiquel Raynal } 633*a430fa06SMiquel Raynal 634*a430fa06SMiquel Raynal while (left_to_write > 0) { 635*a430fa06SMiquel Raynal size_t block_offset = offset & (mtd->erasesize - 1); 636*a430fa06SMiquel Raynal size_t write_size, truncated_write_size; 637*a430fa06SMiquel Raynal 638*a430fa06SMiquel Raynal WATCHDOG_RESET(); 639*a430fa06SMiquel Raynal 640*a430fa06SMiquel Raynal if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { 641*a430fa06SMiquel Raynal printf("Skip bad block 0x%08llx\n", 642*a430fa06SMiquel Raynal offset & ~(mtd->erasesize - 1)); 643*a430fa06SMiquel Raynal offset += mtd->erasesize - block_offset; 644*a430fa06SMiquel Raynal continue; 645*a430fa06SMiquel Raynal } 646*a430fa06SMiquel Raynal 647*a430fa06SMiquel Raynal if (left_to_write < (blocksize - block_offset)) 648*a430fa06SMiquel Raynal write_size = left_to_write; 649*a430fa06SMiquel Raynal else 650*a430fa06SMiquel Raynal write_size = blocksize - block_offset; 651*a430fa06SMiquel Raynal 652*a430fa06SMiquel Raynal truncated_write_size = write_size; 653*a430fa06SMiquel Raynal #ifdef CONFIG_CMD_NAND_TRIMFFS 654*a430fa06SMiquel Raynal if (flags & WITH_DROP_FFS) 655*a430fa06SMiquel Raynal truncated_write_size = drop_ffs(mtd, p_buffer, 656*a430fa06SMiquel Raynal &write_size); 657*a430fa06SMiquel Raynal #endif 658*a430fa06SMiquel Raynal 659*a430fa06SMiquel Raynal rval = nand_write(mtd, offset, &truncated_write_size, 660*a430fa06SMiquel Raynal p_buffer); 661*a430fa06SMiquel Raynal 662*a430fa06SMiquel Raynal if ((flags & WITH_WR_VERIFY) && !rval) 663*a430fa06SMiquel Raynal rval = nand_verify(mtd, offset, 664*a430fa06SMiquel Raynal truncated_write_size, p_buffer); 665*a430fa06SMiquel Raynal 666*a430fa06SMiquel Raynal offset += write_size; 667*a430fa06SMiquel Raynal p_buffer += write_size; 668*a430fa06SMiquel Raynal 669*a430fa06SMiquel Raynal if (rval != 0) { 670*a430fa06SMiquel Raynal printf("NAND write to offset %llx failed %d\n", 671*a430fa06SMiquel Raynal offset, rval); 672*a430fa06SMiquel Raynal *length -= left_to_write; 673*a430fa06SMiquel Raynal return rval; 674*a430fa06SMiquel Raynal } 675*a430fa06SMiquel Raynal 676*a430fa06SMiquel Raynal left_to_write -= write_size; 677*a430fa06SMiquel Raynal } 678*a430fa06SMiquel Raynal 679*a430fa06SMiquel Raynal return 0; 680*a430fa06SMiquel Raynal } 681*a430fa06SMiquel Raynal 682*a430fa06SMiquel Raynal /** 683*a430fa06SMiquel Raynal * nand_read_skip_bad: 684*a430fa06SMiquel Raynal * 685*a430fa06SMiquel Raynal * Read image from NAND flash. 686*a430fa06SMiquel Raynal * Blocks that are marked bad are skipped and the next block is read 687*a430fa06SMiquel Raynal * instead as long as the image is short enough to fit even after 688*a430fa06SMiquel Raynal * skipping the bad blocks. Due to bad blocks we may not be able to 689*a430fa06SMiquel Raynal * perform the requested read. In the case where the read would extend 690*a430fa06SMiquel Raynal * beyond the end of the NAND device, both length and actual (if not 691*a430fa06SMiquel Raynal * NULL) are set to 0. In the case where the read would extend beyond 692*a430fa06SMiquel Raynal * the limit we are passed, length is set to 0 and actual is set to the 693*a430fa06SMiquel Raynal * required length. 694*a430fa06SMiquel Raynal * 695*a430fa06SMiquel Raynal * @param mtd nand mtd instance 696*a430fa06SMiquel Raynal * @param offset offset in flash 697*a430fa06SMiquel Raynal * @param length buffer length, on return holds number of read bytes 698*a430fa06SMiquel Raynal * @param actual set to size required to read length worth of buffer or 0 699*a430fa06SMiquel Raynal * on error, if not NULL 700*a430fa06SMiquel Raynal * @param lim maximum size that actual may be in order to not exceed the 701*a430fa06SMiquel Raynal * buffer 702*a430fa06SMiquel Raynal * @param buffer buffer to write to 703*a430fa06SMiquel Raynal * @return 0 in case of success 704*a430fa06SMiquel Raynal */ 705*a430fa06SMiquel Raynal int nand_read_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, 706*a430fa06SMiquel Raynal size_t *actual, loff_t lim, u_char *buffer) 707*a430fa06SMiquel Raynal { 708*a430fa06SMiquel Raynal int rval; 709*a430fa06SMiquel Raynal size_t left_to_read = *length; 710*a430fa06SMiquel Raynal size_t used_for_read = 0; 711*a430fa06SMiquel Raynal u_char *p_buffer = buffer; 712*a430fa06SMiquel Raynal int need_skip; 713*a430fa06SMiquel Raynal 714*a430fa06SMiquel Raynal if ((offset & (mtd->writesize - 1)) != 0) { 715*a430fa06SMiquel Raynal printf("Attempt to read non page-aligned data\n"); 716*a430fa06SMiquel Raynal *length = 0; 717*a430fa06SMiquel Raynal if (actual) 718*a430fa06SMiquel Raynal *actual = 0; 719*a430fa06SMiquel Raynal return -EINVAL; 720*a430fa06SMiquel Raynal } 721*a430fa06SMiquel Raynal 722*a430fa06SMiquel Raynal need_skip = check_skip_len(mtd, offset, *length, &used_for_read); 723*a430fa06SMiquel Raynal 724*a430fa06SMiquel Raynal if (actual) 725*a430fa06SMiquel Raynal *actual = used_for_read; 726*a430fa06SMiquel Raynal 727*a430fa06SMiquel Raynal if (need_skip < 0) { 728*a430fa06SMiquel Raynal printf("Attempt to read outside the flash area\n"); 729*a430fa06SMiquel Raynal *length = 0; 730*a430fa06SMiquel Raynal return -EINVAL; 731*a430fa06SMiquel Raynal } 732*a430fa06SMiquel Raynal 733*a430fa06SMiquel Raynal if (used_for_read > lim) { 734*a430fa06SMiquel Raynal puts("Size of read exceeds partition or device limit\n"); 735*a430fa06SMiquel Raynal *length = 0; 736*a430fa06SMiquel Raynal return -EFBIG; 737*a430fa06SMiquel Raynal } 738*a430fa06SMiquel Raynal 739*a430fa06SMiquel Raynal if (!need_skip) { 740*a430fa06SMiquel Raynal rval = nand_read(mtd, offset, length, buffer); 741*a430fa06SMiquel Raynal if (!rval || rval == -EUCLEAN) 742*a430fa06SMiquel Raynal return 0; 743*a430fa06SMiquel Raynal 744*a430fa06SMiquel Raynal *length = 0; 745*a430fa06SMiquel Raynal printf("NAND read from offset %llx failed %d\n", 746*a430fa06SMiquel Raynal offset, rval); 747*a430fa06SMiquel Raynal return rval; 748*a430fa06SMiquel Raynal } 749*a430fa06SMiquel Raynal 750*a430fa06SMiquel Raynal while (left_to_read > 0) { 751*a430fa06SMiquel Raynal size_t block_offset = offset & (mtd->erasesize - 1); 752*a430fa06SMiquel Raynal size_t read_length; 753*a430fa06SMiquel Raynal 754*a430fa06SMiquel Raynal WATCHDOG_RESET(); 755*a430fa06SMiquel Raynal 756*a430fa06SMiquel Raynal if (nand_block_isbad(mtd, offset & ~(mtd->erasesize - 1))) { 757*a430fa06SMiquel Raynal printf("Skipping bad block 0x%08llx\n", 758*a430fa06SMiquel Raynal offset & ~(mtd->erasesize - 1)); 759*a430fa06SMiquel Raynal offset += mtd->erasesize - block_offset; 760*a430fa06SMiquel Raynal continue; 761*a430fa06SMiquel Raynal } 762*a430fa06SMiquel Raynal 763*a430fa06SMiquel Raynal if (left_to_read < (mtd->erasesize - block_offset)) 764*a430fa06SMiquel Raynal read_length = left_to_read; 765*a430fa06SMiquel Raynal else 766*a430fa06SMiquel Raynal read_length = mtd->erasesize - block_offset; 767*a430fa06SMiquel Raynal 768*a430fa06SMiquel Raynal rval = nand_read(mtd, offset, &read_length, p_buffer); 769*a430fa06SMiquel Raynal if (rval && rval != -EUCLEAN) { 770*a430fa06SMiquel Raynal printf("NAND read from offset %llx failed %d\n", 771*a430fa06SMiquel Raynal offset, rval); 772*a430fa06SMiquel Raynal *length -= left_to_read; 773*a430fa06SMiquel Raynal return rval; 774*a430fa06SMiquel Raynal } 775*a430fa06SMiquel Raynal 776*a430fa06SMiquel Raynal left_to_read -= read_length; 777*a430fa06SMiquel Raynal offset += read_length; 778*a430fa06SMiquel Raynal p_buffer += read_length; 779*a430fa06SMiquel Raynal } 780*a430fa06SMiquel Raynal 781*a430fa06SMiquel Raynal return 0; 782*a430fa06SMiquel Raynal } 783*a430fa06SMiquel Raynal 784*a430fa06SMiquel Raynal #ifdef CONFIG_CMD_NAND_TORTURE 785*a430fa06SMiquel Raynal 786*a430fa06SMiquel Raynal /** 787*a430fa06SMiquel Raynal * check_pattern: 788*a430fa06SMiquel Raynal * 789*a430fa06SMiquel Raynal * Check if buffer contains only a certain byte pattern. 790*a430fa06SMiquel Raynal * 791*a430fa06SMiquel Raynal * @param buf buffer to check 792*a430fa06SMiquel Raynal * @param patt the pattern to check 793*a430fa06SMiquel Raynal * @param size buffer size in bytes 794*a430fa06SMiquel Raynal * @return 1 if there are only patt bytes in buf 795*a430fa06SMiquel Raynal * 0 if something else was found 796*a430fa06SMiquel Raynal */ 797*a430fa06SMiquel Raynal static int check_pattern(const u_char *buf, u_char patt, int size) 798*a430fa06SMiquel Raynal { 799*a430fa06SMiquel Raynal int i; 800*a430fa06SMiquel Raynal 801*a430fa06SMiquel Raynal for (i = 0; i < size; i++) 802*a430fa06SMiquel Raynal if (buf[i] != patt) 803*a430fa06SMiquel Raynal return 0; 804*a430fa06SMiquel Raynal return 1; 805*a430fa06SMiquel Raynal } 806*a430fa06SMiquel Raynal 807*a430fa06SMiquel Raynal /** 808*a430fa06SMiquel Raynal * nand_torture: 809*a430fa06SMiquel Raynal * 810*a430fa06SMiquel Raynal * Torture a block of NAND flash. 811*a430fa06SMiquel Raynal * This is useful to determine if a block that caused a write error is still 812*a430fa06SMiquel Raynal * good or should be marked as bad. 813*a430fa06SMiquel Raynal * 814*a430fa06SMiquel Raynal * @param mtd nand mtd instance 815*a430fa06SMiquel Raynal * @param offset offset in flash 816*a430fa06SMiquel Raynal * @return 0 if the block is still good 817*a430fa06SMiquel Raynal */ 818*a430fa06SMiquel Raynal int nand_torture(struct mtd_info *mtd, loff_t offset) 819*a430fa06SMiquel Raynal { 820*a430fa06SMiquel Raynal u_char patterns[] = {0xa5, 0x5a, 0x00}; 821*a430fa06SMiquel Raynal struct erase_info instr = { 822*a430fa06SMiquel Raynal .mtd = mtd, 823*a430fa06SMiquel Raynal .addr = offset, 824*a430fa06SMiquel Raynal .len = mtd->erasesize, 825*a430fa06SMiquel Raynal }; 826*a430fa06SMiquel Raynal size_t retlen; 827*a430fa06SMiquel Raynal int err, ret = -1, i, patt_count; 828*a430fa06SMiquel Raynal u_char *buf; 829*a430fa06SMiquel Raynal 830*a430fa06SMiquel Raynal if ((offset & (mtd->erasesize - 1)) != 0) { 831*a430fa06SMiquel Raynal puts("Attempt to torture a block at a non block-aligned offset\n"); 832*a430fa06SMiquel Raynal return -EINVAL; 833*a430fa06SMiquel Raynal } 834*a430fa06SMiquel Raynal 835*a430fa06SMiquel Raynal if (offset + mtd->erasesize > mtd->size) { 836*a430fa06SMiquel Raynal puts("Attempt to torture a block outside the flash area\n"); 837*a430fa06SMiquel Raynal return -EINVAL; 838*a430fa06SMiquel Raynal } 839*a430fa06SMiquel Raynal 840*a430fa06SMiquel Raynal patt_count = ARRAY_SIZE(patterns); 841*a430fa06SMiquel Raynal 842*a430fa06SMiquel Raynal buf = malloc_cache_aligned(mtd->erasesize); 843*a430fa06SMiquel Raynal if (buf == NULL) { 844*a430fa06SMiquel Raynal puts("Out of memory for erase block buffer\n"); 845*a430fa06SMiquel Raynal return -ENOMEM; 846*a430fa06SMiquel Raynal } 847*a430fa06SMiquel Raynal 848*a430fa06SMiquel Raynal for (i = 0; i < patt_count; i++) { 849*a430fa06SMiquel Raynal err = mtd_erase(mtd, &instr); 850*a430fa06SMiquel Raynal if (err) { 851*a430fa06SMiquel Raynal printf("%s: erase() failed for block at 0x%llx: %d\n", 852*a430fa06SMiquel Raynal mtd->name, instr.addr, err); 853*a430fa06SMiquel Raynal goto out; 854*a430fa06SMiquel Raynal } 855*a430fa06SMiquel Raynal 856*a430fa06SMiquel Raynal /* Make sure the block contains only 0xff bytes */ 857*a430fa06SMiquel Raynal err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); 858*a430fa06SMiquel Raynal if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { 859*a430fa06SMiquel Raynal printf("%s: read() failed for block at 0x%llx: %d\n", 860*a430fa06SMiquel Raynal mtd->name, instr.addr, err); 861*a430fa06SMiquel Raynal goto out; 862*a430fa06SMiquel Raynal } 863*a430fa06SMiquel Raynal 864*a430fa06SMiquel Raynal err = check_pattern(buf, 0xff, mtd->erasesize); 865*a430fa06SMiquel Raynal if (!err) { 866*a430fa06SMiquel Raynal printf("Erased block at 0x%llx, but a non-0xff byte was found\n", 867*a430fa06SMiquel Raynal offset); 868*a430fa06SMiquel Raynal ret = -EIO; 869*a430fa06SMiquel Raynal goto out; 870*a430fa06SMiquel Raynal } 871*a430fa06SMiquel Raynal 872*a430fa06SMiquel Raynal /* Write a pattern and check it */ 873*a430fa06SMiquel Raynal memset(buf, patterns[i], mtd->erasesize); 874*a430fa06SMiquel Raynal err = mtd_write(mtd, offset, mtd->erasesize, &retlen, buf); 875*a430fa06SMiquel Raynal if (err || retlen != mtd->erasesize) { 876*a430fa06SMiquel Raynal printf("%s: write() failed for block at 0x%llx: %d\n", 877*a430fa06SMiquel Raynal mtd->name, instr.addr, err); 878*a430fa06SMiquel Raynal goto out; 879*a430fa06SMiquel Raynal } 880*a430fa06SMiquel Raynal 881*a430fa06SMiquel Raynal err = mtd_read(mtd, offset, mtd->erasesize, &retlen, buf); 882*a430fa06SMiquel Raynal if ((err && err != -EUCLEAN) || retlen != mtd->erasesize) { 883*a430fa06SMiquel Raynal printf("%s: read() failed for block at 0x%llx: %d\n", 884*a430fa06SMiquel Raynal mtd->name, instr.addr, err); 885*a430fa06SMiquel Raynal goto out; 886*a430fa06SMiquel Raynal } 887*a430fa06SMiquel Raynal 888*a430fa06SMiquel Raynal err = check_pattern(buf, patterns[i], mtd->erasesize); 889*a430fa06SMiquel Raynal if (!err) { 890*a430fa06SMiquel Raynal printf("Pattern 0x%.2x checking failed for block at " 891*a430fa06SMiquel Raynal "0x%llx\n", patterns[i], offset); 892*a430fa06SMiquel Raynal ret = -EIO; 893*a430fa06SMiquel Raynal goto out; 894*a430fa06SMiquel Raynal } 895*a430fa06SMiquel Raynal } 896*a430fa06SMiquel Raynal 897*a430fa06SMiquel Raynal ret = 0; 898*a430fa06SMiquel Raynal 899*a430fa06SMiquel Raynal out: 900*a430fa06SMiquel Raynal free(buf); 901*a430fa06SMiquel Raynal return ret; 902*a430fa06SMiquel Raynal } 903*a430fa06SMiquel Raynal 904*a430fa06SMiquel Raynal #endif 905