/* * cherry picked from mtd-utils * * Copyright (C) 2000 Arcom Control System Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "u_boot.h" int target_endian = __BYTE_ORDER; int mtd_erase_all(const char *mtd_device, int jffs2) { int fd; struct mtd_info_user meminfo; struct erase_info_user erase; int clmpos = 0; int clmlen = 8; int isNAND; int bbtest = 1; struct jffs2_unknown_node cleanmarker; if ((fd = open(mtd_device, O_RDWR)) < 0) { error("%s: %s", mtd_device, strerror(errno)); close(fd); return false; } if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { error("%s: unable to get MTD device info", mtd_device); close(fd); return false; } erase.length = meminfo.erasesize; isNAND = meminfo.type == MTD_NANDFLASH ? 1 : 0; if (jffs2) { cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); if (!isNAND) cleanmarker.totlen = cpu_to_je32(sizeof(struct jffs2_unknown_node)); else { struct nand_oobinfo oobinfo; if (ioctl(fd, MEMGETOOBSEL, &oobinfo) != 0) { error("%s: unable to get NAND oobinfo", mtd_device); close(fd); return false; } /* Check for autoplacement */ if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) { /* Get the position of the free bytes */ if (!oobinfo.oobfree[0][1]) { error("Eeep. Autoplacement selected and no empty space in oob"); close(fd); return false; } clmpos = oobinfo.oobfree[0][0]; clmlen = oobinfo.oobfree[0][1]; if (clmlen > 8) clmlen = 8; } else { /* Legacy mode */ switch (meminfo.oobsize) { case 8: clmpos = 6; clmlen = 2; break; case 16: clmpos = 8; clmlen = 8; break; case 64: clmpos = 16; clmlen = 8; break; } } cleanmarker.totlen = cpu_to_je32(8); } cleanmarker.hdr_crc= cpu_to_je32(crc32(0, (unsigned char *) &cleanmarker, sizeof(struct jffs2_unknown_node) - 4)); } for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) { if (bbtest) { loff_t offset = erase.start; int ret = ioctl(fd, MEMGETBADBLOCK, &offset); if (ret > 0) { dbg("Skipping bad block at 0x%08x", erase.start); continue; } else if (ret < 0) { if (errno == EOPNOTSUPP) { bbtest = 0; if (isNAND) { error("%s: Bad block check not available", mtd_device); close(fd); return false; } } else { error("%s: MTD get bad block failed: %s", mtd_device, strerror(errno)); close(fd); return false; } } } if (ioctl(fd, MEMERASE, &erase) != 0) { error("%s: MTD Erase failure: %s", mtd_device, strerror(errno)); continue; } /* format for JFFS2 ? */ if (!jffs2) continue; /* write cleanmarker */ if (isNAND) { struct mtd_oob_buf oob; oob.ptr = (unsigned char *) &cleanmarker; oob.start = erase.start + clmpos; oob.length = clmlen; if (ioctl(fd, MEMWRITEOOB, &oob) != 0) { error("%s: MTD writeoob failure: %s", mtd_device, strerror(errno)); continue; } } else { if (lseek(fd, erase.start, SEEK_SET) < 0) { error("%s: MTD lseek failure: %s", mtd_device, strerror(errno)); continue; } if (write(fd, &cleanmarker, sizeof(cleanmarker)) != sizeof(cleanmarker)) { error("%s: MTD write failure: %s", mtd_device, strerror(errno)); continue; } } dbg("Cleanmarker written at %x.", erase.start); } close(fd); return true; }