diff options
Diffstat (limited to 'drivers/mtd/nand/spi/fmsh.c')
| -rw-r--r-- | drivers/mtd/nand/spi/fmsh.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c index c2b9a8c113cb..f417955f7d1c 100644 --- a/drivers/mtd/nand/spi/fmsh.c +++ b/drivers/mtd/nand/spi/fmsh.c @@ -9,6 +9,13 @@ #include <linux/kernel.h> #include <linux/mtd/spinand.h> +#define FM25S01BI3_STATUS_ECC_MASK (7 << 4) + #define FM25S01BI3_STATUS_ECC_NO_BITFLIPS (0 << 4) + #define FM25S01BI3_STATUS_ECC_1_3_BITFLIPS (1 << 4) + #define FM25S01BI3_STATUS_ECC_UNCOR_ERROR (2 << 4) + #define FM25S01BI3_STATUS_ECC_4_6_BITFLIPS (3 << 4) + #define FM25S01BI3_STATUS_ECC_7_8_BITFLIPS (5 << 4) + #define SPINAND_MFR_FMSH 0xA1 static SPINAND_OP_VARIANTS(read_cache_variants, @@ -45,11 +52,66 @@ static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section, return 0; } +static int fm25s01bi3_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + switch (status & FM25S01BI3_STATUS_ECC_MASK) { + case FM25S01BI3_STATUS_ECC_NO_BITFLIPS: + return 0; + + case FM25S01BI3_STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + case FM25S01BI3_STATUS_ECC_1_3_BITFLIPS: + return 3; + + case FM25S01BI3_STATUS_ECC_4_6_BITFLIPS: + return 6; + + case FM25S01BI3_STATUS_ECC_7_8_BITFLIPS: + return 8; + + default: + break; + } + + return -EINVAL; +} + +static int fm25s01bi3_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 64; + region->length = 64; + + return 0; +} + +static int fm25s01bi3_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = (16 * section) + 4; + region->length = 12; + + return 0; +} + static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { .ecc = fm25s01a_ooblayout_ecc, .free = fm25s01a_ooblayout_free, }; +static const struct mtd_ooblayout_ops fm25s01bi3_ooblayout = { + .ecc = fm25s01bi3_ooblayout_ecc, + .free = fm25s01bi3_ooblayout_free, +}; + static const struct spinand_info fmsh_spinand_table[] = { SPINAND_INFO("FM25S01A", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), @@ -60,6 +122,16 @@ static const struct spinand_info fmsh_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), + SPINAND_INFO("FM25S01BI3", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xd4), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fm25s01bi3_ooblayout, + fm25s01bi3_ecc_get_status)), }; static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { |
