diff mbox series

[v3] mtd: spinand: add support for Foresee FS35ND0*G parts

Message ID 20210811084924.52293-1-daniel@0x0f.com (mailing list archive)
State New, archived
Headers show
Series [v3] mtd: spinand: add support for Foresee FS35ND0*G parts | expand

Commit Message

Daniel Palmer Aug. 11, 2021, 8:49 a.m. UTC
Add support for the various Foresee FS35ND0*G parts manufactured by Longsys.

Signed-off-by: Daniel Palmer <daniel@0x0f.com>

Link: https://datasheet.lcsc.com/szlcsc/2008121142_FORESEE-FS35ND01G-S1Y2QWFI000_C719495.pdf
---
 Changes since v2:
 - Originally I only had the 1Gbit version of this chip, now I have the 2Gbit and 4Gbit
   variations so I've added support for those too. There is no datasheet for the bigger
   chips but they are documented in a flashing tool from an SoC vendor so I took the parameters
   from there.
 - Previous versions of this patch only had single io read cache variants. My SPI flash driver
   now supports dual and quad io for reading so I added and tested those modes too.
   My driver/hardware only supports single io for writing so those are still left out.
 - Implemented proper logic for checking the ECC status.
 - Combined with the previous patch for 1-filling the OOB in the page buffer before writing
   I have been using this for a few months now without anything getting broken.
 
 drivers/mtd/nand/spi/Makefile  |   2 +-
 drivers/mtd/nand/spi/core.c    |   1 +
 drivers/mtd/nand/spi/longsys.c | 134 +++++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h    |   1 +
 4 files changed, 137 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/nand/spi/longsys.c

Comments

Miquel Raynal Aug. 16, 2021, 8:11 a.m. UTC | #1
Hi Daniel,

Daniel Palmer <daniel@0x0f.com> wrote on Wed, 11 Aug 2021 17:49:24
+0900:

> Add support for the various Foresee FS35ND0*G parts manufactured by Longsys.
> 
> Signed-off-by: Daniel Palmer <daniel@0x0f.com>
> 
> Link: https://datasheet.lcsc.com/szlcsc/2008121142_FORESEE-FS35ND01G-S1Y2QWFI000_C719495.pdf
> ---
>  Changes since v2:
>  - Originally I only had the 1Gbit version of this chip, now I have the 2Gbit and 4Gbit
>    variations so I've added support for those too. There is no datasheet for the bigger
>    chips but they are documented in a flashing tool from an SoC vendor so I took the parameters
>    from there.
>  - Previous versions of this patch only had single io read cache variants. My SPI flash driver
>    now supports dual and quad io for reading so I added and tested those modes too.
>    My driver/hardware only supports single io for writing so those are still left out.
>  - Implemented proper logic for checking the ECC status.
>  - Combined with the previous patch for 1-filling the OOB in the page buffer before writing
>    I have been using this for a few months now without anything getting broken.
>  
>  drivers/mtd/nand/spi/Makefile  |   2 +-
>  drivers/mtd/nand/spi/core.c    |   1 +
>  drivers/mtd/nand/spi/longsys.c | 134 +++++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h    |   1 +
>  4 files changed, 137 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/mtd/nand/spi/longsys.c
> 
> diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
> index 9662b9c1d5a9..1d6819022e43 100644
> --- a/drivers/mtd/nand/spi/Makefile
> +++ b/drivers/mtd/nand/spi/Makefile
> @@ -1,3 +1,3 @@
>  # SPDX-License-Identifier: GPL-2.0
> -spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
> +spinand-objs := core.o gigadevice.o longsys.o macronix.o micron.o paragon.o toshiba.o winbond.o
>  obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index 446ba8d43fbc..48f635d5c1ff 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -895,6 +895,7 @@ static const struct nand_ops spinand_ops = {
>  
>  static const struct spinand_manufacturer *spinand_manufacturers[] = {
>  	&gigadevice_spinand_manufacturer,
> +	&longsys_spinand_manufacturer,
>  	&macronix_spinand_manufacturer,
>  	&micron_spinand_manufacturer,
>  	&paragon_spinand_manufacturer,
> diff --git a/drivers/mtd/nand/spi/longsys.c b/drivers/mtd/nand/spi/longsys.c
> new file mode 100644
> index 000000000000..ee38f8728262
> --- /dev/null
> +++ b/drivers/mtd/nand/spi/longsys.c
> @@ -0,0 +1,134 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020 Daniel Palmer <daniel@thingy.jp>
> + *
> + */
> +
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/mtd/spinand.h>
> +
> +#define SPINAND_MFR_LONGSYS			0xCD
> +#define FS35ND01G_S1Y2_STATUS_ECC_0_3_BITFLIPS	(0 << 4)
> +#define FS35ND01G_S1Y2_STATUS_ECC_4_BITFLIPS	(1 << 4)
> +#define FS35ND01G_S1Y2_STATUS_ECC_UNCORRECTABLE	(2 << 4)
> +
> +static SPINAND_OP_VARIANTS(read_cache_variants,
> +		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
> +		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
> +		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
> +		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
> +		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
> +
> +static SPINAND_OP_VARIANTS(write_cache_variants,
> +		SPINAND_PROG_LOAD(true, 0, NULL, 0));
> +
> +static SPINAND_OP_VARIANTS(update_cache_variants,
> +		SPINAND_PROG_LOAD(false, 0, NULL, 0));
> +
> +static int fs35nd01g_s1y2_ooblayout_ecc(struct mtd_info *mtd, int section,
> +					struct mtd_oob_region *region)
> +{
> +	if (section > 3)
> +		return -ERANGE;
> +
> +	/* ECC is not user accessible */
> +	region->offset = 0;
> +	region->length = 0;

Can't you just return -ERANGE directly? (maybe not).
If you can't then just return -ERANGE on if (section), no need for two
additional calls.

> +
> +	return 0;
> +}
> +
> +static int fs35nd01g_s1y2_ooblayout_free(struct mtd_info *mtd, int section,
> +				    struct mtd_oob_region *region)
> +{
> +	if (section > 3)
> +		return -ERANGE;
> +
> +	/*
> +	 * No ECC data is stored in the accessible OOB so the full 16 bytes
> +	 * of each spare region is available to the user. Apparently also
> +	 * covered by the internal ECC.
> +	 */
> +	if (section) {
> +		region->offset = 16 * section;
> +		region->length = 16;
> +	} else {
> +		/* First byte in spare0 area is used for bad block marker */
> +		region->offset = 1;

So far we reserved two bytes for BBM while we know for now we only use
one.

> +		region->length = 15;
> +	}

You can just return

	if (section)
		return -ERANGE;

	offset = 2;
	length = (4 * 16) - offset;

	return 0;


> +
> +	return 0;
> +}
> +
> +static const struct mtd_ooblayout_ops fs35nd01g_s1y2_ooblayout = {
> +	.ecc = fs35nd01g_s1y2_ooblayout_ecc,
> +	.free = fs35nd01g_s1y2_ooblayout_free,
> +};
> +
> +static int fs35nd01g_s1y2_ecc_get_status(struct spinand_device *spinand,
> +					u8 status)
> +{
> +	switch (status & STATUS_ECC_MASK) {
> +	case FS35ND01G_S1Y2_STATUS_ECC_0_3_BITFLIPS:
> +		return 3;
> +	/*
> +	 * The datasheet says *successful* with 4 bits flipped.
> +	 * nandbiterrs always complains that the read reported
> +	 * successful but the data is incorrect.
> +	 */
> +	case FS35ND01G_S1Y2_STATUS_ECC_4_BITFLIPS:
> +		return 4;

This is a real issue. Can you use the nandflipbits tool from the
mtd-utils package (you should take a recent version of the package) and
try to observe what happens when you insert a 4th bitflip in a section?

I generally believe the tool more than the datasheet :)

> +	case FS35ND01G_S1Y2_STATUS_ECC_UNCORRECTABLE:
> +		return -EBADMSG;
> +	default:
> +		break;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct spinand_info longsys_spinand_table[] = {
> +	SPINAND_INFO("FS35ND01G-S1Y2",
> +		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEA, 0x11),
> +		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
> +		     NAND_ECCREQ(4, 512),
> +		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
> +					      &write_cache_variants,
> +					      &update_cache_variants),
> +		     SPINAND_HAS_QE_BIT,
> +		     SPINAND_ECCINFO(&fs35nd01g_s1y2_ooblayout,
> +				     fs35nd01g_s1y2_ecc_get_status)),
> +	SPINAND_INFO("FS35ND02G-S3Y2",
> +		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB, 0x11),
> +		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
> +		     NAND_ECCREQ(4, 512),
> +		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
> +					      &write_cache_variants,
> +					      &update_cache_variants),
> +		     SPINAND_HAS_QE_BIT,
> +		     SPINAND_ECCINFO(&fs35nd01g_s1y2_ooblayout,
> +				     fs35nd01g_s1y2_ecc_get_status)),
> +	SPINAND_INFO("FS35ND04G-S2Y2",
> +		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEC, 0x11),
> +		     NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1),
> +		     NAND_ECCREQ(4, 512),
> +		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
> +					      &write_cache_variants,
> +					      &update_cache_variants),
> +		     SPINAND_HAS_QE_BIT,
> +		     SPINAND_ECCINFO(&fs35nd01g_s1y2_ooblayout,
> +				     fs35nd01g_s1y2_ecc_get_status)),
> +};
> +
> +static const struct spinand_manufacturer_ops longsys_spinand_manuf_ops = {
> +};
> +
> +const struct spinand_manufacturer longsys_spinand_manufacturer = {
> +	.id = SPINAND_MFR_LONGSYS,
> +	.name = "Longsys",
> +	.chips = longsys_spinand_table,
> +	.nchips = ARRAY_SIZE(longsys_spinand_table),
> +	.ops = &longsys_spinand_manuf_ops,
> +};
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 6988956b8492..f6c38528bb03 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -261,6 +261,7 @@ struct spinand_manufacturer {
>  
>  /* SPI NAND manufacturers */
>  extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
> +extern const struct spinand_manufacturer longsys_spinand_manufacturer;
>  extern const struct spinand_manufacturer macronix_spinand_manufacturer;
>  extern const struct spinand_manufacturer micron_spinand_manufacturer;
>  extern const struct spinand_manufacturer paragon_spinand_manufacturer;

Otherwise LGTM.

Thanks,
Miquèl
Daniel Palmer Aug. 23, 2021, 2:19 p.m. UTC | #2
Hi Miquel,

> > +     /*
> > +      * The datasheet says *successful* with 4 bits flipped.
> > +      * nandbiterrs always complains that the read reported
> > +      * successful but the data is incorrect.
> > +      */
> > +     case FS35ND01G_S1Y2_STATUS_ECC_4_BITFLIPS:
> > +             return 4;
>
> This is a real issue. Can you use the nandflipbits tool from the
> mtd-utils package (you should take a recent version of the package) and
> try to observe what happens when you insert a 4th bitflip in a section?
>
> I generally believe the tool more than the datasheet :)

Maybe I'm using it incorrectly but I can't get a 4 bit flipped
situation to happen.

I erased the paged so it's all 0xFF:

# flash_erase /dev/mtd0 0x8000000 1
Erasing 128 Kibyte @ 8000000 -- 100 % complete
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0
ECC failed: 0
ECC corrected: 6234
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|

Then used nandflipbits to flip a bunch of bits in the first byte and
then a few other bytes:

# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0
ECC failed: 0
ECC corrected: 6246
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: eb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ef ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ef ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|

Anyhow,
I think we should probably return -EBADMSG if the 4 bit flips status
appears as nandbiterrs always complains that the data is wrong.

Cheers,

Daniel
Miquel Raynal Aug. 23, 2021, 2:21 p.m. UTC | #3
Hi Daniel,

Daniel Palmer <daniel@0x0f.com> wrote on Mon, 23 Aug 2021 23:19:02
+0900:

> Hi Miquel,
> 
> > > +     /*
> > > +      * The datasheet says *successful* with 4 bits flipped.
> > > +      * nandbiterrs always complains that the read reported
> > > +      * successful but the data is incorrect.
> > > +      */
> > > +     case FS35ND01G_S1Y2_STATUS_ECC_4_BITFLIPS:
> > > +             return 4;  
> >
> > This is a real issue. Can you use the nandflipbits tool from the
> > mtd-utils package (you should take a recent version of the package) and
> > try to observe what happens when you insert a 4th bitflip in a section?
> >
> > I generally believe the tool more than the datasheet :)  
> 
> Maybe I'm using it incorrectly but I can't get a 4 bit flipped
> situation to happen.
> 
> I erased the paged so it's all 0xFF:
> 
> # flash_erase /dev/mtd0 0x8000000 1
> Erasing 128 Kibyte @ 8000000 -- 100 % complete
> # nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0
> ECC failed: 0
> ECC corrected: 6234
> Number of bad blocks: 0
> Number of bbt blocks: 0
> Block size 131072, page size 2048, OOB size 64
> Dumping data starting at 0x08000000 and ending at 0x08000001...
> ECC: 3 corrected bitflip(s) at offset 0x08000000
> 0x08000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 
> Then used nandflipbits to flip a bunch of bits in the first byte and
> then a few other bytes:
> 
> # nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0
> ECC failed: 0
> ECC corrected: 6246
> Number of bad blocks: 0
> Number of bbt blocks: 0
> Block size 131072, page size 2048, OOB size 64
> Dumping data starting at 0x08000000 and ending at 0x08000001...
> ECC: 3 corrected bitflip(s) at offset 0x08000000
> 0x08000000: f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000010: eb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000020: ef ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000060: ef ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 
> Anyhow,
> I think we should probably return -EBADMSG if the 4 bit flips status
> appears as nandbiterrs always complains that the data is wrong.

I am not sure to follow, above the software says "3 corrected bf" while
I thought the problem was when getting 4 bf, but the dump show many
more. Can you show me how it behaves:
* erase (like you did)
* insert {1, 2, 3, 4, 5} bf and show the dump each time?

Thanks,
Miquèl
Daniel Palmer Aug. 23, 2021, 2:54 p.m. UTC | #4
Hi Miquel,

On Mon, 23 Aug 2021 at 23:21, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> I am not sure to follow, above the software says "3 corrected bf" while

Due to the status being "between 0 and 3 bitflips" I think it'll
basically report 3 most of the time.
As a refresher we seem to have a status for 0 - 3 flips but ok, 4 bit
flips but ok, and >4 flips no go.
In most cases (0 - 3) the driver is reporting 3.

> I thought the problem was when getting 4 bf, but the dump show many
> more. Can you show me how it behaves:
> * erase (like you did)
> * insert {1, 2, 3, 4, 5} bf and show the dump each time?

Here's a complete log of erasing the page then flipping all the bits
in the first byte.

# flash_erase /dev/mtd0 0x8000000 1
Erasing 128 Kibyte @ 8000000 -- 100 % complete
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6249
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 0@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6252
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: fe ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 1@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6255
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: fc ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 2@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6258
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: f8 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 3@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6261
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 4@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6264
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: e0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 5@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6267
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: c0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 6@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6270
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: 80 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandflipbits /dev/mtd0 7@0x8000000
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6273
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
#

For completeness logs of what nandbiterrs does:

# flash_erase /dev/mtd0 0x8000000 1
Erasing 128 Kibyte @ 8000000 -- 100 % complete
# nandbiterrs -i ^C 1024 /dev/mtd0
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6478
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandbiterrs -i -b 1024 /dev/mtd0
incremental biterrors test
Read reported 3 corrected bit errors
Successfully corrected 0 bit errors per subpage
Inserted biterror @ 0/5
Read reported 4 corrected bit errors
ECC failure, invalid data despite read success
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6488
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 4 corrected bitflip(s) at offset 0x08000000
0x08000000: 05 a5 65 e5 05 85 45 c5 b5 35 f5 75 95 15 d5 55  |..e...E..5.u...U|
0x08000010: 6d ed 2d ad 4d cd 0d 8d fd 7d bd 3d dd 5d 9d 1d  |m.-.M....}.=.]..|
0x08000020: 81 01 c1 41 a1 21 e1 61 11 91 51 d1 31 b1 71 f1  |...A.!.a..Q.1.q.|
0x08000030: c9 49 89 09 e9 69 a9 29 59 d9 19 99 79 f9 39 b9  |.I...i.)Y...y.9.|
0x08000040: 77 d7 37 b7 57 d7 17 97 e7 67 a7 27 c7 47 87 07  |w.7.W....g.'.G..|
0x08000050: 3f bf 7f ff 1f 9f 5f df af 2f ef 6f 8f 0f cf 4f  |?....._../.o...O|
0x08000060: d3 53 93 13 f3 73 b3 33 43 c3 03 83 63 e3 23 a3  |.S...s.3C...c.#.|
0x08000070: 9b 1b db 5b bb 3b fb 7b 0b 8b 4b cb 2b ab 6b eb  |...[.;.{..K.+.k.|
0x08000080: 0c 8c 4c cc 2c ac 6c ec 9c 1c dc 5c bc 3c fc 7c  |..L.,.l....\.<.||
0x08000090: 44 c4 04 84 64 e4 24 a4 d4 54 94 14 f4 74 b4 34  |D...d.$..T...t.4|
#

# flash_erase /dev/mtd0 0x8000000 1
Erasing 128 Kibyte @ 8000000 -- 100 % complete
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 0
ECC corrected: 6492
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
# nandbiterrs -o -b 1024 /dev/mtd0
overwrite biterrors test
Read reported 3 corrected bit errors
Read reported 4 corrected bit errors
Failed to recover 1 bitflips
Bit error histogram (873 operations total):
Page reads with   0 corrected bit errors: 0
Page reads with   1 corrected bit errors: 0
Page reads with   2 corrected bit errors: 0
Page reads with   3 corrected bit errors: 785
# nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
ECC failed: 1
ECC corrected: 9202
Number of bad blocks: 0
Number of bbt blocks: 0
Block size 131072, page size 2048, OOB size 64
Dumping data starting at 0x08000000 and ending at 0x08000001...
ECC: 3 corrected bitflip(s) at offset 0x08000000
0x08000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|

Cheers,

Daniel
Miquel Raynal Aug. 23, 2021, 3:03 p.m. UTC | #5
Hi Daniel,

Daniel Palmer <daniel@0x0f.com> wrote on Mon, 23 Aug 2021 23:54:20
+0900:

> Hi Miquel,
> 
> On Mon, 23 Aug 2021 at 23:21, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > I am not sure to follow, above the software says "3 corrected bf" while  
> 
> Due to the status being "between 0 and 3 bitflips" I think it'll
> basically report 3 most of the time.
> As a refresher we seem to have a status for 0 - 3 flips but ok, 4 bit
> flips but ok, and >4 flips no go.
> In most cases (0 - 3) the driver is reporting 3.
> 
> > I thought the problem was when getting 4 bf, but the dump show many
> > more. Can you show me how it behaves:
> > * erase (like you did)
> > * insert {1, 2, 3, 4, 5} bf and show the dump each time?  
> 
> Here's a complete log of erasing the page then flipping all the bits
> in the first byte.
> 
> # flash_erase /dev/mtd0 0x8000000 1
> Erasing 128 Kibyte @ 8000000 -- 100 % complete
> # nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
> ECC failed: 0
> ECC corrected: 6249
> Number of bad blocks: 0
> Number of bbt blocks: 0
> Block size 131072, page size 2048, OOB size 64
> Dumping data starting at 0x08000000 and ending at 0x08000001...
> ECC: 3 corrected bitflip(s) at offset 0x08000000
> 0x08000000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> # nandflipbits /dev/mtd0 0@0x8000000
> # nanddump --bb=dumpbad -s 0x8000000 -l 1 -c -p /dev/mtd0 | head -n 10
> ECC failed: 0
> ECC corrected: 6252
> Number of bad blocks: 0
> Number of bbt blocks: 0
> Block size 131072, page size 2048, OOB size 64
> Dumping data starting at 0x08000000 and ending at 0x08000001...
> ECC: 3 corrected bitflip(s) at offset 0x08000000
> 0x08000000: fe ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|

How is this result possible? You are dumping with the ECC engine
enabled, it reports 3 bf (meaning that it is actually running, at least
the software really thinks there is an on-die engine enabled) but the
data has not been corrected. I expect the first byte to be 0xFF after
correction. Only with -n (raw dump) we should see this.

> 0x08000010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000060: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
> 0x08000090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|

Thanks,
Miquèl
Daniel Palmer Aug. 23, 2021, 4:16 p.m. UTC | #6
Hi Miquel,

Thank you for your patience on this..

On Tue, 24 Aug 2021 at 00:03, Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > ECC: 3 corrected bitflip(s) at offset 0x08000000
> > 0x08000000: fe ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  |................|
>
> How is this result possible? You are dumping with the ECC engine
> enabled, it reports 3 bf (meaning that it is actually running, at least
> the software really thinks there is an on-die engine enabled) but the
> data has not been corrected. I expect the first byte to be 0xFF after
> correction. Only with -n (raw dump) we should see this.

I did a bit of searching to see if a newer/more detailed datasheet has
come about and found some vendor code I hadn't seen before:

https://github.com/100askTeam/NezaD1_u-boot-2018/blob/1f8b282626f0b9f29f96c57d6b1a5d728e523893/drivers/mtd/awnand/spinand/physic/core.c#L46

This says the ECC enable bit is non-standard and in a register that
isn't documented at all in the datasheet.

I guess the spi nand core isn't able to actually control the ECC on
these chips at the moment and flipping the bits is updating the ECC
too.
Or the ECC isn't enabled at all.

I couldn't see an easy way of overriding which register gets updated
so I haven't tried it yet.

Cheers,

Daniel
diff mbox series

Patch

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 9662b9c1d5a9..1d6819022e43 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,3 +1,3 @@ 
 # SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
+spinand-objs := core.o gigadevice.o longsys.o macronix.o micron.o paragon.o toshiba.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 446ba8d43fbc..48f635d5c1ff 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -895,6 +895,7 @@  static const struct nand_ops spinand_ops = {
 
 static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&gigadevice_spinand_manufacturer,
+	&longsys_spinand_manufacturer,
 	&macronix_spinand_manufacturer,
 	&micron_spinand_manufacturer,
 	&paragon_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/longsys.c b/drivers/mtd/nand/spi/longsys.c
new file mode 100644
index 000000000000..ee38f8728262
--- /dev/null
+++ b/drivers/mtd/nand/spi/longsys.c
@@ -0,0 +1,134 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 Daniel Palmer <daniel@thingy.jp>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_LONGSYS			0xCD
+#define FS35ND01G_S1Y2_STATUS_ECC_0_3_BITFLIPS	(0 << 4)
+#define FS35ND01G_S1Y2_STATUS_ECC_4_BITFLIPS	(1 << 4)
+#define FS35ND01G_S1Y2_STATUS_ECC_UNCORRECTABLE	(2 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int fs35nd01g_s1y2_ooblayout_ecc(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	/* ECC is not user accessible */
+	region->offset = 0;
+	region->length = 0;
+
+	return 0;
+}
+
+static int fs35nd01g_s1y2_ooblayout_free(struct mtd_info *mtd, int section,
+				    struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	/*
+	 * No ECC data is stored in the accessible OOB so the full 16 bytes
+	 * of each spare region is available to the user. Apparently also
+	 * covered by the internal ECC.
+	 */
+	if (section) {
+		region->offset = 16 * section;
+		region->length = 16;
+	} else {
+		/* First byte in spare0 area is used for bad block marker */
+		region->offset = 1;
+		region->length = 15;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops fs35nd01g_s1y2_ooblayout = {
+	.ecc = fs35nd01g_s1y2_ooblayout_ecc,
+	.free = fs35nd01g_s1y2_ooblayout_free,
+};
+
+static int fs35nd01g_s1y2_ecc_get_status(struct spinand_device *spinand,
+					u8 status)
+{
+	switch (status & STATUS_ECC_MASK) {
+	case FS35ND01G_S1Y2_STATUS_ECC_0_3_BITFLIPS:
+		return 3;
+	/*
+	 * The datasheet says *successful* with 4 bits flipped.
+	 * nandbiterrs always complains that the read reported
+	 * successful but the data is incorrect.
+	 */
+	case FS35ND01G_S1Y2_STATUS_ECC_4_BITFLIPS:
+		return 4;
+	case FS35ND01G_S1Y2_STATUS_ECC_UNCORRECTABLE:
+		return -EBADMSG;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct spinand_info longsys_spinand_table[] = {
+	SPINAND_INFO("FS35ND01G-S1Y2",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEA, 0x11),
+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&fs35nd01g_s1y2_ooblayout,
+				     fs35nd01g_s1y2_ecc_get_status)),
+	SPINAND_INFO("FS35ND02G-S3Y2",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB, 0x11),
+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&fs35nd01g_s1y2_ooblayout,
+				     fs35nd01g_s1y2_ecc_get_status)),
+	SPINAND_INFO("FS35ND04G-S2Y2",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEC, 0x11),
+		     NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1),
+		     NAND_ECCREQ(4, 512),
+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+					      &write_cache_variants,
+					      &update_cache_variants),
+		     SPINAND_HAS_QE_BIT,
+		     SPINAND_ECCINFO(&fs35nd01g_s1y2_ooblayout,
+				     fs35nd01g_s1y2_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops longsys_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer longsys_spinand_manufacturer = {
+	.id = SPINAND_MFR_LONGSYS,
+	.name = "Longsys",
+	.chips = longsys_spinand_table,
+	.nchips = ARRAY_SIZE(longsys_spinand_table),
+	.ops = &longsys_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 6988956b8492..f6c38528bb03 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -261,6 +261,7 @@  struct spinand_manufacturer {
 
 /* SPI NAND manufacturers */
 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+extern const struct spinand_manufacturer longsys_spinand_manufacturer;
 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
 extern const struct spinand_manufacturer micron_spinand_manufacturer;
 extern const struct spinand_manufacturer paragon_spinand_manufacturer;