diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c index f417955f7d1c..be5db9f9502b 100644 --- a/drivers/mtd/nand/spi/fmsh.c +++ b/drivers/mtd/nand/spi/fmsh.c @@ -9,6 +9,16 @@ #include #include +#define FM25G01B_STATUS_ECC_MASK (7 << 4) + #define FM25G01B_STATUS_ECC_NO_BITFLIPS (0 << 4) + #define FM25G01B_STATUS_ECC_1_3_BITFLIPS (1 << 4) + #define FM25G01B_STATUS_ECC_4_BITFLIPS (2 << 4) + #define FM25G01B_STATUS_ECC_5_BITFLIPS (3 << 4) + #define FM25G01B_STATUS_ECC_6_BITFLIPS (4 << 4) + #define FM25G01B_STATUS_ECC_7_BITFLIPS (5 << 4) + #define FM25G01B_STATUS_ECC_8_BITFLIPS (6 << 4) + #define FM25G01B_STATUS_ECC_UNCOR_ERROR (7 << 4) + #define FM25S01BI3_STATUS_ECC_MASK (7 << 4) #define FM25S01BI3_STATUS_ECC_NO_BITFLIPS (0 << 4) #define FM25S01BI3_STATUS_ECC_1_3_BITFLIPS (1 << 4) @@ -34,6 +44,66 @@ static SPINAND_OP_VARIANTS(update_cache_variants, SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); +static int fm25g01b_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 fm25g01b_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + /* reserve 2 bytes for the BBM */ + region->offset = 2; + region->length = 62; + + return 0; +} + +static int fm25g01b_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + switch (status & FM25G01B_STATUS_ECC_MASK) { + case FM25G01B_STATUS_ECC_NO_BITFLIPS: + return 0; + + case FM25G01B_STATUS_ECC_1_3_BITFLIPS: + return 3; + + case FM25G01B_STATUS_ECC_4_BITFLIPS: + return 4; + + case FM25G01B_STATUS_ECC_5_BITFLIPS: + return 5; + + case FM25G01B_STATUS_ECC_6_BITFLIPS: + return 6; + + case FM25G01B_STATUS_ECC_7_BITFLIPS: + return 7; + + case FM25G01B_STATUS_ECC_8_BITFLIPS: + return 8; + + case FM25G01B_STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + default: + break; + } + + return -EINVAL; +} + static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { @@ -102,6 +172,11 @@ static int fm25s01bi3_ooblayout_free(struct mtd_info *mtd, int section, return 0; } +static const struct mtd_ooblayout_ops fm25g01b_ooblayout = { + .ecc = fm25g01b_ooblayout_ecc, + .free = fm25g01b_ooblayout_free, +}; + static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { .ecc = fm25s01a_ooblayout_ecc, .free = fm25s01a_ooblayout_free, @@ -113,6 +188,26 @@ static const struct mtd_ooblayout_ops fm25s01bi3_ooblayout = { }; static const struct spinand_info fmsh_spinand_table[] = { + SPINAND_INFO("FM25G01B", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xd1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1), + NAND_ECCREQ(8, 528), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fm25g01b_ooblayout, + fm25g01b_ecc_get_status)), + SPINAND_INFO("FM25G02B", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xd2), + NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1), + NAND_ECCREQ(8, 528), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&fm25g01b_ooblayout, + fm25g01b_ecc_get_status)), SPINAND_INFO("FM25S01A", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),