^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * sharpslpart.c - MTD partition parser for NAND flash using the SHARP FTL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * for logical addressing, as used on the PXA models of the SHARP SL Series.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2017 Andrea Adami <andrea.adami@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on SHARP GPL 2.4 sources:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * http://support.ezaurus.com/developer/source/source_dl.asp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * drivers/mtd/nand/sharp_sl_logical.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * linux/include/asm-arm/sharp_nand_logical.h
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Copyright (C) 2002 SHARP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * This program is free software; you can redistribute it and/or modify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * it under the terms of the GNU General Public License as published by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * the Free Software Foundation; either version 2 of the License, or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * (at your option) any later version.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * This program is distributed in the hope that it will be useful,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * but WITHOUT ANY WARRANTY; without even the implied warranty of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * GNU General Public License for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/sizes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* oob structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define NAND_NOOB_LOGADDR_00 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define NAND_NOOB_LOGADDR_01 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define NAND_NOOB_LOGADDR_10 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define NAND_NOOB_LOGADDR_11 11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define NAND_NOOB_LOGADDR_20 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define NAND_NOOB_LOGADDR_21 13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define BLOCK_IS_RESERVED 0xffff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define BLOCK_UNMASK_COMPLEMENT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* factory defaults */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define SHARPSL_NAND_PARTS 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define SHARPSL_FTL_PART_SIZE (7 * SZ_1M)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define SHARPSL_PARTINFO1_LADDR 0x00060000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define SHARPSL_PARTINFO2_LADDR 0x00064000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define BOOT_MAGIC 0x424f4f54
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define FSRO_MAGIC 0x4653524f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define FSRW_MAGIC 0x46535257
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * struct sharpsl_ftl - Sharp FTL Logical Table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * @logmax: number of logical blocks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * @log2phy: the logical-to-physical table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * Structure containing the logical-to-physical translation table
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * used by the SHARP SL FTL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct sharpsl_ftl {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned int logmax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned int *log2phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* verify that the OOB bytes 8 to 15 are free and available for the FTL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static int sharpsl_nand_check_ooblayout(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) u8 freebytes = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) int section = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) while (true) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct mtd_oob_region oobfree = { };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ret = mtd_ooblayout_free(mtd, section++, &oobfree);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (!oobfree.length || oobfree.offset > 15 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) (oobfree.offset + oobfree.length) < 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) i = oobfree.offset >= 8 ? oobfree.offset : 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) for (; i < oobfree.offset + oobfree.length && i < 16; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) freebytes |= BIT(i - 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (freebytes == 0xff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return -ENOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static int sharpsl_nand_read_oob(struct mtd_info *mtd, loff_t offs, u8 *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct mtd_oob_ops ops = { };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) ops.mode = MTD_OPS_PLACE_OOB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ops.ooblen = mtd->oobsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ops.oobbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) ret = mtd_read_oob(mtd, offs, &ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (ret != 0 || mtd->oobsize != ops.oobretlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * The logical block number assigned to a physical block is stored in the OOB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * of the first page, in 3 16-bit copies with the following layout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * 01234567 89abcdef
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * -------- --------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * ECC BB xyxyxy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * When reading we check that the first two copies agree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * In case of error, matching is tried using the following pairs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * Reserved values 0xffff mean the block is kept for wear leveling.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * 01234567 89abcdef
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * -------- --------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * ECC BB xyxy oob[8]==oob[10] && oob[9]==oob[11] -> byte0=8 byte1=9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * ECC BB xyxy oob[10]==oob[12] && oob[11]==oob[13] -> byte0=10 byte1=11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * ECC BB xy xy oob[12]==oob[8] && oob[13]==oob[9] -> byte0=12 byte1=13
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int sharpsl_nand_get_logical_num(u8 *oob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) u16 us;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int good0, good1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (oob[NAND_NOOB_LOGADDR_00] == oob[NAND_NOOB_LOGADDR_10] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) oob[NAND_NOOB_LOGADDR_01] == oob[NAND_NOOB_LOGADDR_11]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) good0 = NAND_NOOB_LOGADDR_00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) good1 = NAND_NOOB_LOGADDR_01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) } else if (oob[NAND_NOOB_LOGADDR_10] == oob[NAND_NOOB_LOGADDR_20] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) oob[NAND_NOOB_LOGADDR_11] == oob[NAND_NOOB_LOGADDR_21]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) good0 = NAND_NOOB_LOGADDR_10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) good1 = NAND_NOOB_LOGADDR_11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) } else if (oob[NAND_NOOB_LOGADDR_20] == oob[NAND_NOOB_LOGADDR_00] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) oob[NAND_NOOB_LOGADDR_21] == oob[NAND_NOOB_LOGADDR_01]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) good0 = NAND_NOOB_LOGADDR_20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) good1 = NAND_NOOB_LOGADDR_21;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) us = oob[good0] | oob[good1] << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* parity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) if (hweight16(us) & BLOCK_UNMASK_COMPLEMENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* reserved */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (us == BLOCK_IS_RESERVED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return BLOCK_IS_RESERVED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return (us >> 1) & GENMASK(9, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static int sharpsl_nand_init_ftl(struct mtd_info *mtd, struct sharpsl_ftl *ftl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) unsigned int block_num, phymax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int i, ret, log_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) loff_t block_adr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) u8 *oob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) oob = kzalloc(mtd->oobsize, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (!oob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) phymax = mtd_div_by_eb(SHARPSL_FTL_PART_SIZE, mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* FTL reserves 5% of the blocks + 1 spare */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) ftl->logmax = ((phymax * 95) / 100) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) ftl->log2phy = kmalloc_array(ftl->logmax, sizeof(*ftl->log2phy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) if (!ftl->log2phy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) /* initialize ftl->log2phy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) for (i = 0; i < ftl->logmax; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) ftl->log2phy[i] = UINT_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* create physical-logical table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (block_num = 0; block_num < phymax; block_num++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) block_adr = (loff_t)block_num * mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (mtd_block_isbad(mtd, block_adr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (sharpsl_nand_read_oob(mtd, block_adr, oob))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /* get logical block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) log_num = sharpsl_nand_get_logical_num(oob);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) /* cut-off errors and skip the out-of-range values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (log_num > 0 && log_num < ftl->logmax) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (ftl->log2phy[log_num] == UINT_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ftl->log2phy[log_num] = block_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) pr_info("Sharp SL FTL: %d blocks used (%d logical, %d reserved)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) phymax, ftl->logmax, phymax - ftl->logmax);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) kfree(oob);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) static void sharpsl_nand_cleanup_ftl(struct sharpsl_ftl *ftl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) kfree(ftl->log2phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static int sharpsl_nand_read_laddr(struct mtd_info *mtd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) loff_t from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) void *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) struct sharpsl_ftl *ftl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) unsigned int log_num, final_log_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) unsigned int block_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) loff_t block_adr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) loff_t block_ofs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) size_t retlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) log_num = mtd_div_by_eb((u32)from, mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) final_log_num = mtd_div_by_eb(((u32)from + len - 1), mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (len <= 0 || log_num >= ftl->logmax || final_log_num > log_num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) block_num = ftl->log2phy[log_num];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) block_adr = (loff_t)block_num * mtd->erasesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) block_ofs = mtd_mod_by_eb((u32)from, mtd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) err = mtd_read(mtd, block_adr + block_ofs, len, &retlen, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /* Ignore corrected ECC errors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (mtd_is_bitflip(err))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (!err && retlen != len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) err = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) pr_err("sharpslpart: error, read failed at %#llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) block_adr + block_ofs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) * MTD Partition Parser
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) * Sample values read from SL-C860
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) * # cat /proc/mtd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) * dev: size erasesize name
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * mtd0: 006d0000 00020000 "Filesystem"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * mtd1: 00700000 00004000 "smf"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * mtd2: 03500000 00004000 "root"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * mtd3: 04400000 00004000 "home"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * PARTITIONINFO1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * 0x00060000: 00 00 00 00 00 00 70 00 42 4f 4f 54 00 00 00 00 ......p.BOOT....
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * 0x00060010: 00 00 70 00 00 00 c0 03 46 53 52 4f 00 00 00 00 ..p.....FSRO....
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * 0x00060020: 00 00 c0 03 00 00 00 04 46 53 52 57 00 00 00 00 ........FSRW....
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) struct sharpsl_nand_partinfo {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) __le32 start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) __le32 end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) __be32 magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) u32 reserved;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static int sharpsl_nand_read_partinfo(struct mtd_info *master,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) loff_t from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) size_t len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) struct sharpsl_nand_partinfo *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct sharpsl_ftl *ftl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) ret = sharpsl_nand_read_laddr(master, from, len, buf, ftl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) /* check for magics */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (be32_to_cpu(buf[0].magic) != BOOT_MAGIC ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) be32_to_cpu(buf[1].magic) != FSRO_MAGIC ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) be32_to_cpu(buf[2].magic) != FSRW_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) pr_err("sharpslpart: magic values mismatch\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) /* fixup for hardcoded value 64 MiB (for older models) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) buf[2].end = cpu_to_le32(master->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /* extra sanity check */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (le32_to_cpu(buf[0].end) <= le32_to_cpu(buf[0].start) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) le32_to_cpu(buf[1].start) < le32_to_cpu(buf[0].end) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) le32_to_cpu(buf[1].end) <= le32_to_cpu(buf[1].start) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) le32_to_cpu(buf[2].start) < le32_to_cpu(buf[1].end) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) le32_to_cpu(buf[2].end) <= le32_to_cpu(buf[2].start)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) pr_err("sharpslpart: partition sizes mismatch\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static int sharpsl_parse_mtd_partitions(struct mtd_info *master,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) const struct mtd_partition **pparts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) struct mtd_part_parser_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct sharpsl_ftl ftl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) struct sharpsl_nand_partinfo buf[SHARPSL_NAND_PARTS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) struct mtd_partition *sharpsl_nand_parts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) /* check that OOB bytes 8 to 15 used by the FTL are actually free */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) err = sharpsl_nand_check_ooblayout(master);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /* init logical mgmt (FTL) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) err = sharpsl_nand_init_ftl(master, &ftl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) /* read and validate first partition table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) pr_info("sharpslpart: try reading first partition table\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) err = sharpsl_nand_read_partinfo(master,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) SHARPSL_PARTINFO1_LADDR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) sizeof(buf), buf, &ftl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) /* fallback: read second partition table */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) pr_warn("sharpslpart: first partition table is invalid, retry using the second\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) err = sharpsl_nand_read_partinfo(master,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) SHARPSL_PARTINFO2_LADDR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) sizeof(buf), buf, &ftl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) /* cleanup logical mgmt (FTL) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) sharpsl_nand_cleanup_ftl(&ftl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) pr_err("sharpslpart: both partition tables are invalid\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) sharpsl_nand_parts = kcalloc(SHARPSL_NAND_PARTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) sizeof(*sharpsl_nand_parts),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (!sharpsl_nand_parts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) /* original names */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) sharpsl_nand_parts[0].name = "smf";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) sharpsl_nand_parts[0].offset = le32_to_cpu(buf[0].start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) sharpsl_nand_parts[0].size = le32_to_cpu(buf[0].end) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) le32_to_cpu(buf[0].start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) sharpsl_nand_parts[1].name = "root";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) sharpsl_nand_parts[1].offset = le32_to_cpu(buf[1].start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) sharpsl_nand_parts[1].size = le32_to_cpu(buf[1].end) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) le32_to_cpu(buf[1].start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) sharpsl_nand_parts[2].name = "home";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) sharpsl_nand_parts[2].offset = le32_to_cpu(buf[2].start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) sharpsl_nand_parts[2].size = le32_to_cpu(buf[2].end) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) le32_to_cpu(buf[2].start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) *pparts = sharpsl_nand_parts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return SHARPSL_NAND_PARTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static struct mtd_part_parser sharpsl_mtd_parser = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) .parse_fn = sharpsl_parse_mtd_partitions,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) .name = "sharpslpart",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) module_mtd_part_parser(sharpsl_mtd_parser);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) MODULE_AUTHOR("Andrea Adami <andrea.adami@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) MODULE_DESCRIPTION("MTD partitioning for NAND flash on Sharp SL Series");