Linux-mtd Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] mtd: spinand: Add support for HeYangTek HYF1GQ4UDACAE
@ 2024-06-24  6:12 Maxim Anisimov
  2024-07-01  7:59 ` Miquel Raynal
  0 siblings, 1 reply; 6+ messages in thread
From: Maxim Anisimov @ 2024-06-24  6:12 UTC (permalink / raw)
  Cc: maxim.anisimov.ua, Miquel Raynal, Richard Weinberger,
	Vignesh Raghavendra, Martin Kurbanov, Michael Walle, Mark Brown,
	Chia-Lin Kao (AceLan), linux-kernel, linux-mtd

Add Support HeYangTek HYF1GQ4UDACAE SPI NAND.

Datasheet Link:
- https://www.heyangtek.cn/previewfile.jsp?file=ABUIABA9GAAgwsvRnwYo-eDpsgc

Signed-off-by: Maxim Anisimov <maxim.anisimov.ua@gmail.com>
---
 drivers/mtd/nand/spi/Makefile    |   4 +-
 drivers/mtd/nand/spi/core.c      |   1 +
 drivers/mtd/nand/spi/heyangtek.c | 112 +++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h      |   1 +
 4 files changed, 116 insertions(+), 2 deletions(-)
 create mode 100644 drivers/mtd/nand/spi/heyangtek.c

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 19cc77288ebb..69d95fbdd0ce 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
-spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
+spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o heyangtek.o
+spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.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 e0b6715e5dfe..45795e5f1e49 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -942,6 +942,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&esmt_c8_spinand_manufacturer,
 	&foresee_spinand_manufacturer,
 	&gigadevice_spinand_manufacturer,
+	&heyangtek_spinand_manufacturer,
 	&macronix_spinand_manufacturer,
 	&micron_spinand_manufacturer,
 	&paragon_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/heyangtek.c b/drivers/mtd/nand/spi/heyangtek.c
new file mode 100644
index 000000000000..d4a5dbca40fb
--- /dev/null
+++ b/drivers/mtd/nand/spi/heyangtek.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author:
+ *      Andrey Zolotarev <andrey.zolotarev@keenetic.com> - the main driver logic
+ *      Maxim Anisimov <maxim.anisimov.ua@gmail.com> - adaptation to mainline linux kernel
+ *
+ * Based on:
+ *      https://github.com/keenetic/kernel-49/commit/bacade569fb12bc0ad31ba09bca9b890118fbca7
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_HEYANGTEK		0xC9
+
+#define STATUS_ECC_LIMIT_BITFLIPS	(3 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, 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(true, 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_X4(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+
+static SPINAND_OP_VARIANTS(update_cache_variants,
+		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
+		SPINAND_PROG_LOAD(false, 0, NULL, 0));
+
+static int hyfxgq4uda_ooblayout_ecc(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = section * 16 + 8;
+	region->length = 8;
+
+	return 0;
+}
+
+static int hyfxgq4uda_ooblayout_free(struct mtd_info *mtd, int section,
+				   struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	/* ECC-protected user meta-data */
+	region->offset = section * 16 + 4;
+	region->length = 4;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops hyfxgq4uda_ooblayout = {
+	.ecc = hyfxgq4uda_ooblayout_ecc,
+	.free = hyfxgq4uda_ooblayout_free,
+};
+
+static int hyfxgq4uda_ecc_get_status(struct spinand_device *spinand,
+				     u8 status)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+
+	switch (status & STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	case STATUS_ECC_HAS_BITFLIPS:
+		return nanddev_get_ecc_conf(nand)->strength >> 1;
+
+	case STATUS_ECC_LIMIT_BITFLIPS:
+		return nanddev_get_ecc_conf(nand)->strength;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct spinand_info heyangtek_spinand_table[] = {
+	SPINAND_INFO("HYF1GQ4UDACAE",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x21),
+		     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(&hyfxgq4uda_ooblayout,
+				     hyfxgq4uda_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops heyangtek_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer heyangtek_spinand_manufacturer = {
+	.id = SPINAND_MFR_HEYANGTEK,
+	.name = "HeYangTek",
+	.chips = heyangtek_spinand_table,
+	.nchips = ARRAY_SIZE(heyangtek_spinand_table),
+	.ops = &heyangtek_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 5c19ead60499..06ee35a27e3b 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -265,6 +265,7 @@ extern const struct spinand_manufacturer ato_spinand_manufacturer;
 extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
 extern const struct spinand_manufacturer foresee_spinand_manufacturer;
 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+extern const struct spinand_manufacturer heyangtek_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;
-- 
2.45.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] mtd: spinand: Add support for HeYangTek HYF1GQ4UDACAE
  2024-06-24  6:12 [PATCH] mtd: spinand: Add support for HeYangTek HYF1GQ4UDACAE Maxim Anisimov
@ 2024-07-01  7:59 ` Miquel Raynal
  2024-07-22  6:54   ` Maxim Anisimov
  0 siblings, 1 reply; 6+ messages in thread
From: Miquel Raynal @ 2024-07-01  7:59 UTC (permalink / raw)
  To: Maxim Anisimov
  Cc: Richard Weinberger, Vignesh Raghavendra, Martin Kurbanov,
	Michael Walle, Mark Brown, Chia-Lin Kao (AceLan), linux-kernel,
	linux-mtd

Hi Maxim,

maxim.anisimov.ua@gmail.com wrote on Mon, 24 Jun 2024 09:12:17 +0300:

> Add Support HeYangTek HYF1GQ4UDACAE SPI NAND.
> 
> Datasheet Link:
> - https://www.heyangtek.cn/previewfile.jsp?file=ABUIABA9GAAgwsvRnwYo-eDpsgc

Thanks for the patch! Few comments below.

> Signed-off-by: Maxim Anisimov <maxim.anisimov.ua@gmail.com>
> ---
>  drivers/mtd/nand/spi/Makefile    |   4 +-
>  drivers/mtd/nand/spi/core.c      |   1 +
>  drivers/mtd/nand/spi/heyangtek.c | 112 +++++++++++++++++++++++++++++++
>  include/linux/mtd/spinand.h      |   1 +
>  4 files changed, 116 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/mtd/nand/spi/heyangtek.c
> 
> diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
> index 19cc77288ebb..69d95fbdd0ce 100644
> --- a/drivers/mtd/nand/spi/Makefile
> +++ b/drivers/mtd/nand/spi/Makefile
> @@ -1,4 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0
> -spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
> -spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
> +spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o heyangtek.o
> +spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.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 e0b6715e5dfe..45795e5f1e49 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -942,6 +942,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
>  	&esmt_c8_spinand_manufacturer,
>  	&foresee_spinand_manufacturer,
>  	&gigadevice_spinand_manufacturer,
> +	&heyangtek_spinand_manufacturer,
>  	&macronix_spinand_manufacturer,
>  	&micron_spinand_manufacturer,
>  	&paragon_spinand_manufacturer,
> diff --git a/drivers/mtd/nand/spi/heyangtek.c b/drivers/mtd/nand/spi/heyangtek.c
> new file mode 100644
> index 000000000000..d4a5dbca40fb
> --- /dev/null
> +++ b/drivers/mtd/nand/spi/heyangtek.c
> @@ -0,0 +1,112 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Author:
> + *      Andrey Zolotarev <andrey.zolotarev@keenetic.com> - the main driver logic
> + *      Maxim Anisimov <maxim.anisimov.ua@gmail.com> - adaptation to mainline linux kernel
> + *
> + * Based on:
> + *      https://github.com/keenetic/kernel-49/commit/bacade569fb12bc0ad31ba09bca9b890118fbca7
> + */
> +
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/mtd/spinand.h>
> +
> +#define SPINAND_MFR_HEYANGTEK		0xC9
> +
> +#define STATUS_ECC_LIMIT_BITFLIPS	(3 << 4)
> +
> +static SPINAND_OP_VARIANTS(read_cache_variants,
> +		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, 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(true, 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_X4(true, 0, NULL, 0),
> +		SPINAND_PROG_LOAD(true, 0, NULL, 0));
> +
> +static SPINAND_OP_VARIANTS(update_cache_variants,
> +		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
> +		SPINAND_PROG_LOAD(false, 0, NULL, 0));
> +
> +static int hyfxgq4uda_ooblayout_ecc(struct mtd_info *mtd, int section,
> +				   struct mtd_oob_region *region)
> +{
> +	if (section > 3)
> +		return -ERANGE;
> +
> +	region->offset = section * 16 + 8;
> +	region->length = 8;

This is: 8-15, 24-31, 40-47, 56-62

> +
> +	return 0;
> +}
> +
> +static int hyfxgq4uda_ooblayout_free(struct mtd_info *mtd, int section,
> +				   struct mtd_oob_region *region)
> +{
> +	if (section > 3)
> +		return -ERANGE;
> +
> +	/* ECC-protected user meta-data */
> +	region->offset = section * 16 + 4;
> +	region->length = 4;

This is: 4-7, 20-23, 32-35, 48-51

So what about 2-4, 16-19, 36-39, 52-55, 63-64 ?

> +
> +	return 0;
> +}
> +
> +static const struct mtd_ooblayout_ops hyfxgq4uda_ooblayout = {
> +	.ecc = hyfxgq4uda_ooblayout_ecc,
> +	.free = hyfxgq4uda_ooblayout_free,
> +};
> +
> +static int hyfxgq4uda_ecc_get_status(struct spinand_device *spinand,
> +				     u8 status)
> +{
> +	struct nand_device *nand = spinand_to_nand(spinand);
> +
> +	switch (status & STATUS_ECC_MASK) {
> +	case STATUS_ECC_NO_BITFLIPS:
> +		return 0;
> +
> +	case STATUS_ECC_UNCOR_ERROR:
> +		return -EBADMSG;
> +
> +	case STATUS_ECC_HAS_BITFLIPS:
> +		return nanddev_get_ecc_conf(nand)->strength >> 1;

Maybe an explanation of this line is needed. Is this just guessing or
is this defined in the datasheet?

Also please do not use shifts when you want to divide. Just use / 2
which is easier to understand. Compilers know how to optimize that.

> +
> +	case STATUS_ECC_LIMIT_BITFLIPS:
> +		return nanddev_get_ecc_conf(nand)->strength;
> +
> +	default:
> +		break;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static const struct spinand_info heyangtek_spinand_table[] = {
> +	SPINAND_INFO("HYF1GQ4UDACAE",
> +		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x21),
> +		     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(&hyfxgq4uda_ooblayout,
> +				     hyfxgq4uda_ecc_get_status)),
> +};
> +
> +static const struct spinand_manufacturer_ops heyangtek_spinand_manuf_ops = {
> +};
> +
> +const struct spinand_manufacturer heyangtek_spinand_manufacturer = {
> +	.id = SPINAND_MFR_HEYANGTEK,
> +	.name = "HeYangTek",
> +	.chips = heyangtek_spinand_table,
> +	.nchips = ARRAY_SIZE(heyangtek_spinand_table),
> +	.ops = &heyangtek_spinand_manuf_ops,
> +};
> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
> index 5c19ead60499..06ee35a27e3b 100644
> --- a/include/linux/mtd/spinand.h
> +++ b/include/linux/mtd/spinand.h
> @@ -265,6 +265,7 @@ extern const struct spinand_manufacturer ato_spinand_manufacturer;
>  extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
>  extern const struct spinand_manufacturer foresee_spinand_manufacturer;
>  extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
> +extern const struct spinand_manufacturer heyangtek_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;


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] mtd: spinand: Add support for HeYangTek HYF1GQ4UDACAE
  2024-07-01  7:59 ` Miquel Raynal
@ 2024-07-22  6:54   ` Maxim Anisimov
  2024-08-23 15:47     ` Miquel Raynal
  0 siblings, 1 reply; 6+ messages in thread
From: Maxim Anisimov @ 2024-07-22  6:54 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Richard Weinberger, Vignesh Raghavendra, Martin Kurbanov,
	Michael Walle, Mark Brown, Chia-Lin Kao (AceLan), linux-kernel,
	linux-mtd

Hi Miquel,

Sorry for late answer. I was on vocation. To be honest, I don't 
understand very well how this works. One of the OpenWrt developers asked 
me to send this patch to Linux upstream. Related OpenWrt pull request is 
here https://github.com/openwrt/openwrt/pull/15551 . Originally this 
patch code was taken from the device manufacturer's repository 
https://github.com/keenetic/kernel-49/commit/bacade569fb12bc0ad31ba09bca9b890118fbca7 
. I pointed to this in the source code. From my side I only adapted the 
code for successful compilation on the Linux upstream. It's difficult 
for me to answer your questions because I don't understand how the spi 
nand framework works. I can make corrections in the patch but with 
outside help. Thanks!

> Hi Maxim,
>
> maxim.anisimov.ua@gmail.com wrote on Mon, 24 Jun 2024 09:12:17 +0300:
>
>> Add Support HeYangTek HYF1GQ4UDACAE SPI NAND.
>>
>> Datasheet Link:
>> - https://www.heyangtek.cn/previewfile.jsp?file=ABUIABA9GAAgwsvRnwYo-eDpsgc
> Thanks for the patch! Few comments below.
>
>> Signed-off-by: Maxim Anisimov <maxim.anisimov.ua@gmail.com>
>> ---
>>   drivers/mtd/nand/spi/Makefile    |   4 +-
>>   drivers/mtd/nand/spi/core.c      |   1 +
>>   drivers/mtd/nand/spi/heyangtek.c | 112 +++++++++++++++++++++++++++++++
>>   include/linux/mtd/spinand.h      |   1 +
>>   4 files changed, 116 insertions(+), 2 deletions(-)
>>   create mode 100644 drivers/mtd/nand/spi/heyangtek.c
>>
>> diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
>> index 19cc77288ebb..69d95fbdd0ce 100644
>> --- a/drivers/mtd/nand/spi/Makefile
>> +++ b/drivers/mtd/nand/spi/Makefile
>> @@ -1,4 +1,4 @@
>>   # SPDX-License-Identifier: GPL-2.0
>> -spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o
>> -spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
>> +spinand-objs := core.o alliancememory.o ato.o esmt.o foresee.o gigadevice.o heyangtek.o
>> +spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.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 e0b6715e5dfe..45795e5f1e49 100644
>> --- a/drivers/mtd/nand/spi/core.c
>> +++ b/drivers/mtd/nand/spi/core.c
>> @@ -942,6 +942,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
>>   	&esmt_c8_spinand_manufacturer,
>>   	&foresee_spinand_manufacturer,
>>   	&gigadevice_spinand_manufacturer,
>> +	&heyangtek_spinand_manufacturer,
>>   	&macronix_spinand_manufacturer,
>>   	&micron_spinand_manufacturer,
>>   	&paragon_spinand_manufacturer,
>> diff --git a/drivers/mtd/nand/spi/heyangtek.c b/drivers/mtd/nand/spi/heyangtek.c
>> new file mode 100644
>> index 000000000000..d4a5dbca40fb
>> --- /dev/null
>> +++ b/drivers/mtd/nand/spi/heyangtek.c
>> @@ -0,0 +1,112 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Author:
>> + *      Andrey Zolotarev <andrey.zolotarev@keenetic.com> - the main driver logic
>> + *      Maxim Anisimov <maxim.anisimov.ua@gmail.com> - adaptation to mainline linux kernel
>> + *
>> + * Based on:
>> + *      https://github.com/keenetic/kernel-49/commit/bacade569fb12bc0ad31ba09bca9b890118fbca7
>> + */
>> +
>> +#include <linux/device.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mtd/spinand.h>
>> +
>> +#define SPINAND_MFR_HEYANGTEK		0xC9
>> +
>> +#define STATUS_ECC_LIMIT_BITFLIPS	(3 << 4)
>> +
>> +static SPINAND_OP_VARIANTS(read_cache_variants,
>> +		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, 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(true, 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_X4(true, 0, NULL, 0),
>> +		SPINAND_PROG_LOAD(true, 0, NULL, 0));
>> +
>> +static SPINAND_OP_VARIANTS(update_cache_variants,
>> +		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
>> +		SPINAND_PROG_LOAD(false, 0, NULL, 0));
>> +
>> +static int hyfxgq4uda_ooblayout_ecc(struct mtd_info *mtd, int section,
>> +				   struct mtd_oob_region *region)
>> +{
>> +	if (section > 3)
>> +		return -ERANGE;
>> +
>> +	region->offset = section * 16 + 8;
>> +	region->length = 8;
> This is: 8-15, 24-31, 40-47, 56-62
>
>> +
>> +	return 0;
>> +}
>> +
>> +static int hyfxgq4uda_ooblayout_free(struct mtd_info *mtd, int section,
>> +				   struct mtd_oob_region *region)
>> +{
>> +	if (section > 3)
>> +		return -ERANGE;
>> +
>> +	/* ECC-protected user meta-data */
>> +	region->offset = section * 16 + 4;
>> +	region->length = 4;
> This is: 4-7, 20-23, 32-35, 48-51
>
> So what about 2-4, 16-19, 36-39, 52-55, 63-64 ?
>
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct mtd_ooblayout_ops hyfxgq4uda_ooblayout = {
>> +	.ecc = hyfxgq4uda_ooblayout_ecc,
>> +	.free = hyfxgq4uda_ooblayout_free,
>> +};
>> +
>> +static int hyfxgq4uda_ecc_get_status(struct spinand_device *spinand,
>> +				     u8 status)
>> +{
>> +	struct nand_device *nand = spinand_to_nand(spinand);
>> +
>> +	switch (status & STATUS_ECC_MASK) {
>> +	case STATUS_ECC_NO_BITFLIPS:
>> +		return 0;
>> +
>> +	case STATUS_ECC_UNCOR_ERROR:
>> +		return -EBADMSG;
>> +
>> +	case STATUS_ECC_HAS_BITFLIPS:
>> +		return nanddev_get_ecc_conf(nand)->strength >> 1;
> Maybe an explanation of this line is needed. Is this just guessing or
> is this defined in the datasheet?
>
> Also please do not use shifts when you want to divide. Just use / 2
> which is easier to understand. Compilers know how to optimize that.
>
>> +
>> +	case STATUS_ECC_LIMIT_BITFLIPS:
>> +		return nanddev_get_ecc_conf(nand)->strength;
>> +
>> +	default:
>> +		break;
>> +	}
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static const struct spinand_info heyangtek_spinand_table[] = {
>> +	SPINAND_INFO("HYF1GQ4UDACAE",
>> +		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x21),
>> +		     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(&hyfxgq4uda_ooblayout,
>> +				     hyfxgq4uda_ecc_get_status)),
>> +};
>> +
>> +static const struct spinand_manufacturer_ops heyangtek_spinand_manuf_ops = {
>> +};
>> +
>> +const struct spinand_manufacturer heyangtek_spinand_manufacturer = {
>> +	.id = SPINAND_MFR_HEYANGTEK,
>> +	.name = "HeYangTek",
>> +	.chips = heyangtek_spinand_table,
>> +	.nchips = ARRAY_SIZE(heyangtek_spinand_table),
>> +	.ops = &heyangtek_spinand_manuf_ops,
>> +};
>> diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
>> index 5c19ead60499..06ee35a27e3b 100644
>> --- a/include/linux/mtd/spinand.h
>> +++ b/include/linux/mtd/spinand.h
>> @@ -265,6 +265,7 @@ extern const struct spinand_manufacturer ato_spinand_manufacturer;
>>   extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
>>   extern const struct spinand_manufacturer foresee_spinand_manufacturer;
>>   extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
>> +extern const struct spinand_manufacturer heyangtek_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;
>
> Thanks,
> Miquèl

Thanks,

Maxim


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] mtd: spinand: Add support for HeYangTek HYF1GQ4UDACAE
  2024-07-22  6:54   ` Maxim Anisimov
@ 2024-08-23 15:47     ` Miquel Raynal
  0 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2024-08-23 15:47 UTC (permalink / raw)
  To: Maxim Anisimov
  Cc: Richard Weinberger, Vignesh Raghavendra, Martin Kurbanov,
	Michael Walle, Mark Brown, Chia-Lin Kao (AceLan), linux-kernel,
	linux-mtd

Hi Maxim,

maxim.anisimov.ua@gmail.com wrote on Mon, 22 Jul 2024 09:54:55 +0300:

> Hi Miquel,
> 
> Sorry for late answer. I was on vocation. To be honest, I don't understand very well how this works. One of the OpenWrt developers asked me to send this patch to Linux upstream. Related OpenWrt pull request is here https://github.com/openwrt/openwrt/pull/15551 . Originally this patch code was taken from the device manufacturer's repository https://github.com/keenetic/kernel-49/commit/bacade569fb12bc0ad31ba09bca9b890118fbca7 . I pointed to this in the source code. From my side I only adapted the code for successful compilation on the Linux upstream. It's difficult for me to answer your questions because I don't understand how the spi nand framework works. I can make corrections in the patch but with outside help. Thanks!

I'm sorry I cannot write the changes for you, but I can explain my
point below.

> >> +static int hyfxgq4uda_ooblayout_ecc(struct mtd_info *mtd, int section,
> >> +				   struct mtd_oob_region *region)
> >> +{
> >> +	if (section > 3)
> >> +		return -ERANGE;
> >> +
> >> +	region->offset = section * 16 + 8;
> >> +	region->length = 8;  
> > This is: 8-15, 24-31, 40-47, 56-62
> >  
> >> +
> >> +	return 0;
> >> +}
> >> +
> >> +static int hyfxgq4uda_ooblayout_free(struct mtd_info *mtd, int section,
> >> +				   struct mtd_oob_region *region)
> >> +{
> >> +	if (section > 3)
> >> +		return -ERANGE;
> >> +
> >> +	/* ECC-protected user meta-data */
> >> +	region->offset = section * 16 + 4;
> >> +	region->length = 4;  
> > This is: 4-7, 20-23, 32-35, 48-51
> >
> > So what about 2-4, 16-19, 36-39, 52-55, 63-64 ?

The OOB area is a specific area where we store:
- the bad block marker: it is at offset 0 and 1 and must be excluded
  from both functions.
- ECC bytes, so data for the correction engine: the amount depend on
  the strength of your correction and the position depends on the
  hardware. If this is not told in the datasheet explicitly you can
  play with flash_erase/nandwrite/nanddump: you can write a known
  pattern to an OOB area with the ECC engine enabled and you'll see
  what bytes have been smashed by the ECC engine.
- the rest is user data (typically jffs2 metadata).

In the current implementation, some bytes are just undefined, which is
not expected.

> >  
> >> +
> >> +	return 0;
> >> +}

...

> >> +static int hyfxgq4uda_ecc_get_status(struct spinand_device *spinand,
> >> +				     u8 status)
> >> +{
> >> +	struct nand_device *nand = spinand_to_nand(spinand);
> >> +
> >> +	switch (status & STATUS_ECC_MASK) {
> >> +	case STATUS_ECC_NO_BITFLIPS:
> >> +		return 0;
> >> +
> >> +	case STATUS_ECC_UNCOR_ERROR:
> >> +		return -EBADMSG;
> >> +
> >> +	case STATUS_ECC_HAS_BITFLIPS:
> >> +		return nanddev_get_ecc_conf(nand)->strength >> 1;  
> > Maybe an explanation of this line is needed. Is this just guessing or
> > is this defined in the datasheet?

The datasheet should tell you what this bit means. If it means some
bits have been corrected up to half of the strength capability, then
this is fine. But please make sure this is right by using nandbiterrs
-i from the mtd-utils test suite.

> > Also please do not use shifts when you want to divide. Just use / 2
> > which is easier to understand. Compilers know how to optimize that.

This is self explanatory.

Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] mtd: spinand: add support for HeYangTek HYF1GQ4UDACAE
@ 2026-06-16 13:28 Aleksei Sviridkin
  2026-06-29 14:48 ` Miquel Raynal
  0 siblings, 1 reply; 6+ messages in thread
From: Aleksei Sviridkin @ 2026-06-16 13:28 UTC (permalink / raw)
  To: Miquel Raynal, Vignesh Raghavendra
  Cc: Richard Weinberger, Maxim Anisimov, linux-mtd, linux-kernel,
	Aleksei Sviridkin

The HeYangTek HYF1GQ4UDACAE is a 1 Gbit (128 MiB) SLC SPI-NAND with
2048 + 64 byte pages and on-die 4-bit / 512-byte ECC; its JEDEC
manufacturer ID is 0xc9. The die is GD5F1GQ4-compatible, so the OOB
layout is taken from the in-tree gd5fxgq4xa. The die exposes only a
coarse 2-bit ECC status with no fine-grained bitflip-count register, so
the status is decoded into a representative number of corrected bitflips.

It is found, among others, on some Keenetic KN-3411 (Buddy 6) units.

Datasheet:
https://www.heyangtek.cn/previewfile.jsp?file=ABUIABA9GAAgwsvRnwYo-eDpsgc

Signed-off-by: Aleksei Sviridkin <f@lex.la>
---
This revives Maxim Anisimov's 2024 submission [1], which stalled on the
review feedback. Changes since then:

 - The OOB layout no longer leaves undefined bytes: it is taken verbatim
   from the in-tree gd5fxgq4xa, which the die is compatible with (BBM in
   byte 0, ECC parity in bytes 8..15 of each 16-byte section, the rest
   exposed as free).
 - The ECC status decoding is documented and uses '/' instead of a
   shift. The die exposes only the coarse 2-bit status with no register
   for the exact bitflip count, so the below-threshold code reports
   strength/2 and the refresh-recommended code reports the full strength.
 - The datasheet link is added to the commit message.

Tested on a Keenetic KN-3411 (Buddy 6): the chip is detected and a UBIFS
rootfs mounts and runs on it. nandbiterrs is not applicable here -- this
is an on-die-ECC part with NOP=1, so the in-place raw page reprogram that
nandbiterrs relies on corrupts the page independently of this driver.

[1] https://lore.kernel.org/linux-mtd/20240624061246.5292-1-maxim.anisimov.ua@gmail.com/

 drivers/mtd/nand/spi/Makefile    |   2 +-
 drivers/mtd/nand/spi/core.c      |   1 +
 drivers/mtd/nand/spi/heyangtek.c | 132 +++++++++++++++++++++++++++++++
 include/linux/mtd/spinand.h      |   1 +
 4 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/nand/spi/heyangtek.c

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index a47bd22cd..b5ccb4486 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
 spinand-objs := core.o otp.o
-spinand-objs += alliancememory.o ato.o dosilicon.o esmt.o fmsh.o foresee.o gigadevice.o
+spinand-objs += alliancememory.o ato.o dosilicon.o esmt.o fmsh.o foresee.o gigadevice.o heyangtek.o
 spinand-objs += macronix.o micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.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 0b076790b..0cdd4a62e 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1336,6 +1336,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
 	&fmsh_spinand_manufacturer,
 	&foresee_spinand_manufacturer,
 	&gigadevice_spinand_manufacturer,
+	&heyangtek_spinand_manufacturer,
 	&macronix_spinand_manufacturer,
 	&micron_spinand_manufacturer,
 	&paragon_spinand_manufacturer,
diff --git a/drivers/mtd/nand/spi/heyangtek.c b/drivers/mtd/nand/spi/heyangtek.c
new file mode 100644
index 000000000..7fc50fd3d
--- /dev/null
+++ b/drivers/mtd/nand/spi/heyangtek.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Authors:
+ *	Andrey Zolotarev <andrey.zolotarev@keenetic.com> - the main driver logic
+ *	Aleksei Sviridkin <f@lex.la> - adaptation to the mainline Linux kernel
+ *
+ * Based on:
+ *	https://github.com/keenetic/kernel-49/commit/bacade569fb12bc0ad31ba09bca9b890118fbca7
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mtd/spinand.h>
+
+#define SPINAND_MFR_HEYANGTEK			0xc9
+
+#define HYF1GQ4_STATUS_ECC_LIMIT_BITFLIPS	(3 << 4)
+
+static SPINAND_OP_VARIANTS(read_cache_variants,
+		SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
+		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
+
+static SPINAND_OP_VARIANTS(write_cache_variants,
+		SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
+		SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
+
+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));
+
+/*
+ * HYF1GQ4UDACAE is a GD5F1GQ4-compatible die, so the OOB layout is taken
+ * from gd5fxgq4xa: the on-die ECC parity occupies bytes 8..15 of each
+ * 16-byte section, the bad block marker sits in byte 0 and the remaining
+ * bytes are exposed as free.
+ */
+static int hyf1gq4_ooblayout_ecc(struct mtd_info *mtd, int section,
+				 struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	region->offset = (16 * section) + 8;
+	region->length = 8;
+
+	return 0;
+}
+
+static int hyf1gq4_ooblayout_free(struct mtd_info *mtd, int section,
+				  struct mtd_oob_region *region)
+{
+	if (section > 3)
+		return -ERANGE;
+
+	if (section) {
+		region->offset = 16 * section;
+		region->length = 8;
+	} else {
+		/* section 0 has one byte reserved for the bad block marker */
+		region->offset = 1;
+		region->length = 7;
+	}
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops hyf1gq4_ooblayout = {
+	.ecc = hyf1gq4_ooblayout_ecc,
+	.free = hyf1gq4_ooblayout_free,
+};
+
+static int hyf1gq4_ecc_get_status(struct spinand_device *spinand, u8 status)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+
+	switch (status & STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	case STATUS_ECC_HAS_BITFLIPS:
+		/*
+		 * The die exposes only a coarse 2-bit ECC status and has no
+		 * register for the exact bitflip count. This code means
+		 * "corrected, below the refresh threshold", so report half of
+		 * the ECC strength as a representative value.
+		 */
+		return nanddev_get_ecc_conf(nand)->strength / 2;
+
+	case HYF1GQ4_STATUS_ECC_LIMIT_BITFLIPS:
+		/*
+		 * "Corrected, refresh recommended": report the full ECC
+		 * strength so the upper layers relocate the data.
+		 */
+		return nanddev_get_ecc_conf(nand)->strength;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct spinand_info heyangtek_spinand_table[] = {
+	SPINAND_INFO("HYF1GQ4UDACAE",
+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x21),
+		     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(&hyf1gq4_ooblayout,
+				     hyf1gq4_ecc_get_status)),
+};
+
+static const struct spinand_manufacturer_ops heyangtek_spinand_manuf_ops = {
+};
+
+const struct spinand_manufacturer heyangtek_spinand_manufacturer = {
+	.id = SPINAND_MFR_HEYANGTEK,
+	.name = "HeYangTek",
+	.chips = heyangtek_spinand_table,
+	.nchips = ARRAY_SIZE(heyangtek_spinand_table),
+	.ops = &heyangtek_spinand_manuf_ops,
+};
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 782984ba3..48357e6ff 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -437,6 +437,7 @@ extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
 extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
 extern const struct spinand_manufacturer foresee_spinand_manufacturer;
 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
+extern const struct spinand_manufacturer heyangtek_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;
-- 
2.39.5


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] mtd: spinand: add support for HeYangTek HYF1GQ4UDACAE
  2026-06-16 13:28 [PATCH] mtd: spinand: add " Aleksei Sviridkin
@ 2026-06-29 14:48 ` Miquel Raynal
  0 siblings, 0 replies; 6+ messages in thread
From: Miquel Raynal @ 2026-06-29 14:48 UTC (permalink / raw)
  To: Vignesh Raghavendra, Aleksei Sviridkin
  Cc: Richard Weinberger, Maxim Anisimov, linux-mtd, linux-kernel

On Tue, 16 Jun 2026 16:28:44 +0300, Aleksei Sviridkin wrote:
> The HeYangTek HYF1GQ4UDACAE is a 1 Gbit (128 MiB) SLC SPI-NAND with
> 2048 + 64 byte pages and on-die 4-bit / 512-byte ECC; its JEDEC
> manufacturer ID is 0xc9. The die is GD5F1GQ4-compatible, so the OOB
> layout is taken from the in-tree gd5fxgq4xa. The die exposes only a
> coarse 2-bit ECC status with no fine-grained bitflip-count register, so
> the status is decoded into a representative number of corrected bitflips.
> 
> [...]

Applied to nand/next, thanks!

[1/1] mtd: spinand: add support for HeYangTek HYF1GQ4UDACAE
      commit: a8374683868634012ac873d628fa581fcc452e9c

Patche(s) should be available on mtd/linux.git and will be
part of the next PR (provided that no robot complains by then).

Kind regards,
Miquèl


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-06-29 14:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-24  6:12 [PATCH] mtd: spinand: Add support for HeYangTek HYF1GQ4UDACAE Maxim Anisimov
2024-07-01  7:59 ` Miquel Raynal
2024-07-22  6:54   ` Maxim Anisimov
2024-08-23 15:47     ` Miquel Raynal
  -- strict thread matches above, loose matches on Subject: below --
2026-06-16 13:28 [PATCH] mtd: spinand: add " Aleksei Sviridkin
2026-06-29 14:48 ` Miquel Raynal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox