* [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support
@ 2024-10-20 13:27 Sky Huang
2024-10-20 13:27 ` [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page Sky Huang
` (5 more replies)
0 siblings, 6 replies; 13+ messages in thread
From: Sky Huang @ 2024-10-20 13:27 UTC (permalink / raw)
To: Matthias Brugger, Miquel Raynal, AngeloGioacchino Del Regno,
Richard Weinberger, Vignesh Raghavendra, Daniel Golle,
Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel,
linux-mtd, linux-arm-kernel, linux-mediatek
Cc: Steven Liu, Sky Huang
From: "Sky Huang" <skylake.huang@mediatek.com>
Hi, this is Qi-Ze Huang(Sky Huang) from MediaTek. On our router platforms
chips, we have to quality lots of SPI-NAND devices and are eager for
a standard so that we don't need to maintain trivial flash ID table
anymore. I also noticed a talk in 2019 Embedded Linux Conference,
Memory Technology Devices: what's new, which mentioned "ONFI for
SPI-NANDs? Maybe, maybe not".
So earlier this year, I proposed a bold idea, CASN page (Common Attributes
for SPI-NAND). I worked together with top 3 SPI-NAND market share flash
vendors and other vendors to integrate CASN page on their SPI-NAND devices
including but not limited to:
[ESMT]
F50L1G41LB
F50L2G41KA
[Etron]
EM73C044VCF-H
EM73D044VCO-H
EM73E044VCE-H
EM73F044VCA-H
[GigaDevice]
GD5F1GM7UE
GD5F1GQ5UEYIG
GD5F2GM7UE
GD5F2GQ5UEYIG
GD5F4GM8UE
GD5F4GQ6UEYIG
[Macronix (MXIC)]
MX35LF1GE4ABZ4IG
[Winbond]
W25N01GV
W25N01KV
W25N02KV
W25N04KV
A document of CASN is hosted on github(https://github.com/mtk-openwrt/
doc/blob/main/CASN%20Page%20Introduction.pdf) So I'll try to keep it
simple here.
With CASN page, we don't need to maintain SPI-NAND flash ID table anymore.
Currently, it's integrated in 3.3V SPI-NANDs of small density and it's not
JEDEC standard yet. But it should be able to handle 1.8V and can be easily
integrated by flash vendors.
I believe this idea and implementation have room for improvement. Hope to
hear you open source community's comments soon.
Signed-off-by: Sky Huang <skylake.huang@mediatek.com>
---
Sky Huang (4):
mtd: nand: Create param.c to do CRC check and bitwise majority for
Parameter & CASN page
include: mtd: Add CASN page definition and related structs.
include: mtd: spinand: Add CASN page related macros and flags.
mtd: nand: spi: Add CASN page support
drivers/mtd/nand/Makefile | 2 +-
drivers/mtd/nand/param.c | 52 +++
drivers/mtd/nand/raw/nand_onfi.c | 43 +-
drivers/mtd/nand/spi/core.c | 741 ++++++++++++++++++++++++++++++-
include/linux/mtd/casn.h | 191 ++++++++
include/linux/mtd/param.h | 20 +
include/linux/mtd/spinand.h | 100 ++++-
7 files changed, 1094 insertions(+), 55 deletions(-)
create mode 100644 drivers/mtd/nand/param.c
create mode 100644 include/linux/mtd/casn.h
create mode 100644 include/linux/mtd/param.h
--
2.45.2
^ permalink raw reply [flat|nested] 13+ messages in thread* [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page 2024-10-20 13:27 [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support Sky Huang @ 2024-10-20 13:27 ` Sky Huang 2024-11-18 10:55 ` Miquel Raynal 2024-10-20 13:27 ` [RFC PATCH nand/next 2/4] include: mtd: Add CASN page definition and related structs Sky Huang ` (4 subsequent siblings) 5 siblings, 1 reply; 13+ messages in thread From: Sky Huang @ 2024-10-20 13:27 UTC (permalink / raw) To: Matthias Brugger, Miquel Raynal, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek Cc: Steven Liu, Sky.Huang From: "Sky.Huang" <skylake.huang@mediatek.com> Create drivers/mtd/nand/param.c so ONFI parameter page & CASN page can both use nanddev_crc16() and nanddev_bit_wise_majority() directly like this: * For ONFI Parameter page: onfi_crc16() -> nanddev_crc16() * For CASN page: nanddev_crc16() nanddev_bit_wise_majority() is same as nand_bit_wise_majority(). nanddev_crc16() is same as onfi_crc16(). But there are lots of onfi_crc16() call, so keep onfi_crc16() there and hook it to nanddev_crc16(). Signed-off-by: Sky Huang <skylake.huang@mediatek.com> --- drivers/mtd/nand/Makefile | 2 +- drivers/mtd/nand/param.c | 52 ++++++++++++++++++++++++++++++++ drivers/mtd/nand/raw/nand_onfi.c | 43 ++------------------------ include/linux/mtd/param.h | 20 ++++++++++++ 4 files changed, 76 insertions(+), 41 deletions(-) create mode 100644 drivers/mtd/nand/param.c create mode 100644 include/linux/mtd/param.h diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 19e1291ac4d5..790bde0148d1 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -nandcore-objs := core.o bbt.o +nandcore-objs := core.o bbt.o param.o obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o obj-$(CONFIG_MTD_NAND_ECC_MEDIATEK) += ecc-mtk.o diff --git a/drivers/mtd/nand/param.c b/drivers/mtd/nand/param.c new file mode 100644 index 000000000000..f67b9fe633d9 --- /dev/null +++ b/drivers/mtd/nand/param.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 - Mediatek + * + * Author: Sky Huang <SkyLake.Huang@mediatek.com> + */ + +#include <linux/mtd/param.h> + +u16 nanddev_crc16(u16 crc, u8 const *p, size_t len) +{ + int i; + + while (len--) { + crc ^= *p++ << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); + } + + return crc; +} + +/* + * Recover data with bit-wise majority + */ +void nanddev_bit_wise_majority(const void **srcbufs, + unsigned int nsrcbufs, + void *dstbuf, + unsigned int bufsize) +{ + int i, j, k; + + for (i = 0; i < bufsize; i++) { + u8 val = 0; + + for (j = 0; j < 8; j++) { + unsigned int cnt = 0; + + for (k = 0; k < nsrcbufs; k++) { + const u8 *srcbuf = srcbufs[k]; + + if (srcbuf[i] & BIT(j)) + cnt++; + } + + if (cnt > nsrcbufs / 2) + val |= BIT(j); + } + + ((u8 *)dstbuf)[i] = val; + } +} diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 861975e44b55..5d330dd53e8f 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -12,6 +12,7 @@ * This file contains all ONFI helpers. */ +#include <linux/mtd/param.h> #include <linux/slab.h> #include "internals.h" @@ -20,14 +21,7 @@ u16 onfi_crc16(u16 crc, u8 const *p, size_t len) { - int i; - while (len--) { - crc ^= *p++ << 8; - for (i = 0; i < 8; i++) - crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0); - } - - return crc; + return nanddev_crc16(crc, p, len); } /* Parse the Extended Parameter Page. */ @@ -107,37 +101,6 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip, return ret; } -/* - * Recover data with bit-wise majority - */ -static void nand_bit_wise_majority(const void **srcbufs, - unsigned int nsrcbufs, - void *dstbuf, - unsigned int bufsize) -{ - int i, j, k; - - for (i = 0; i < bufsize; i++) { - u8 val = 0; - - for (j = 0; j < 8; j++) { - unsigned int cnt = 0; - - for (k = 0; k < nsrcbufs; k++) { - const u8 *srcbuf = srcbufs[k]; - - if (srcbuf[i] & BIT(j)) - cnt++; - } - - if (cnt > nsrcbufs / 2) - val |= BIT(j); - } - - ((u8 *)dstbuf)[i] = val; - } -} - /* * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ @@ -200,7 +163,7 @@ int nand_onfi_detect(struct nand_chip *chip) srcbufs[j] = pbuf + j; pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n"); - nand_bit_wise_majority(srcbufs, ONFI_PARAM_PAGES, pbuf, + nanddev_bit_wise_majority(srcbufs, ONFI_PARAM_PAGES, pbuf, sizeof(*pbuf)); crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)pbuf, 254); diff --git a/include/linux/mtd/param.h b/include/linux/mtd/param.h new file mode 100644 index 000000000000..39636f66f1b4 --- /dev/null +++ b/include/linux/mtd/param.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 - Mediatek + * + * Author: Sky Huang <SkyLake.Huang@mediatek.com> + */ + +#ifndef __LINUX_NAND_PARAM +#define __LINUX_NAND_PARAM + +#include <linux/io.h> + +u16 nanddev_crc16(u16 crc, u8 const *p, size_t len); +void nanddev_bit_wise_majority(const void **srcbufs, + unsigned int nsrcbufs, + void *dstbuf, + unsigned int bufsize); + +#endif /* __LINUX_NAND_PARAM */ + -- 2.45.2 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page 2024-10-20 13:27 ` [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page Sky Huang @ 2024-11-18 10:55 ` Miquel Raynal 0 siblings, 0 replies; 13+ messages in thread From: Miquel Raynal @ 2024-11-18 10:55 UTC (permalink / raw) To: Sky Huang Cc: Matthias Brugger, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek, Steven Liu On 20/10/2024 at 21:27:19 +08, Sky Huang <SkyLake.Huang@mediatek.com> wrote: > From: "Sky.Huang" <skylake.huang@mediatek.com> > > Create drivers/mtd/nand/param.c so ONFI parameter page & CASN page > can both use nanddev_crc16() and nanddev_bit_wise_majority() directly > like this: > * For ONFI Parameter page: > onfi_crc16() -> nanddev_crc16() > * For CASN page: nanddev_crc16() > > nanddev_bit_wise_majority() is same as nand_bit_wise_majority(). Please use the same nanddev_ prefix. > nanddev_crc16() is same as onfi_crc16(). But there are lots of > onfi_crc16() call, so keep onfi_crc16() there and hook it to > nanddev_crc16(). > > Signed-off-by: Sky Huang <skylake.huang@mediatek.com> Thanks, Miquèl ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH nand/next 2/4] include: mtd: Add CASN page definition and related structs. 2024-10-20 13:27 [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support Sky Huang 2024-10-20 13:27 ` [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page Sky Huang @ 2024-10-20 13:27 ` Sky Huang 2024-11-18 10:58 ` Miquel Raynal 2024-10-20 13:27 ` [RFC PATCH nand/next 3/4] include: mtd: spinand: Add CASN page related macros and flags Sky Huang ` (3 subsequent siblings) 5 siblings, 1 reply; 13+ messages in thread From: Sky Huang @ 2024-10-20 13:27 UTC (permalink / raw) To: Matthias Brugger, Miquel Raynal, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek Cc: Steven Liu, Sky Huang From: "Sky Huang" <skylake.huang@mediatek.com> This patch adds CASN page definition. You can see corresponding table in CASN page application note referred in cover letter. (https://github.com/mtk-openwrt/doc/blob/ main/CASN%20Page%20Introduction.pdf) Signed-off-by: Sky Huang <skylake.huang@mediatek.com> --- include/linux/mtd/casn.h | 191 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 include/linux/mtd/casn.h diff --git a/include/linux/mtd/casn.h b/include/linux/mtd/casn.h new file mode 100644 index 000000000000..65ebd23c17c1 --- /dev/null +++ b/include/linux/mtd/casn.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 - Mediatek + * + * Author: Sky Huang <SkyLake.Huang@mediatek.com> + */ + +#ifndef __LINUX_MTD_CASN_H +#define __LINUX_MTD_CASN_H + +#define CASN_CRC_BASE 0x4341 +#define CASN_SIGNATURE 0x4341534EU +#define SPINAND_CASN_V1_CRC_OFS (254) +#define CASN_PAGE_V1_COPIES (3) + +#define SDR_READ_1_1_1 BIT(0) +#define SDR_READ_1_1_1_FAST BIT(1) +#define SDR_READ_1_1_2 BIT(2) +#define SDR_READ_1_2_2 BIT(3) +#define SDR_READ_1_1_4 BIT(4) +#define SDR_READ_1_4_4 BIT(5) +#define SDR_READ_1_1_8 BIT(6) +#define SDR_READ_1_8_8 BIT(7) + +#define SDR_WRITE_1_1_1 BIT(0) +#define SDR_WRITE_1_1_4 BIT(1) + +#define SDR_UPDATE_1_1_1 BIT(0) +#define SDR_UPDATE_1_1_4 BIT(1) + +struct op_slice { + u8 cmd_opcode; +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 dummy_nbytes : 4; + u8 addr_nbytes : 4; +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 addr_nbytes : 4; + u8 dummy_nbytes : 4; +#endif +}; + +struct SPINAND_FLAGS { +#if defined(__LITTLE_ENDIAN_BITFIELD) + u8 has_qe_bit : 1; + u8 has_cr_feat_bit : 1; + u8 conti_read_cap : 1; + u8 on_die_ecc : 1; + u8 legacy_ecc_status : 1; + u8 adv_ecc_status : 1; + u8 ecc_parity_readable : 1; + u8 ecc_alg : 1; /* ECC algorithm */ +#elif defined(__BIG_ENDIAN_BITFIELD) + u8 ecc_alg : 1; /* ECC algorithm */ + u8 ecc_parity_readable : 1; + u8 adv_ecc_status : 1; + u8 legacy_ecc_status : 1; + u8 on_die_ecc : 1; + u8 conti_read_cap : 1; + u8 has_cr_feat_bit : 1; + u8 has_qe_bit : 1; +#endif +}; + +struct ADV_ECC_STATUS { + u8 cmd; + u8 addr; + u8 addr_nbytes; + u8 addr_buswidth; + u8 dummy_nbytes; + u8 dummy_buswidth; + u8 status_nbytes; + u16 status_mask; + u8 pre_op; /* pre-process operator */ + u8 pre_mask; /* pre-process mask */ +} __packed; + +struct CASN_OOB { + u8 layout_type; + + /* OOB free layout */ + u8 free_start; + u8 free_length; + u8 bbm_length; + + /* ECC parity layout */ + u8 ecc_parity_start; + u8 ecc_parity_space; + u8 ecc_parity_real_length; +}; + +enum oob_overall { + OOB_DISCRETE = 0, + OOB_CONTINUOUS, +}; + +struct nand_casn { + /* CASN signature must be 4 chars: 'C','A','S','N' */ + union { + u8 sig[4]; + u32 signature; + }; + + u8 version; + char manufacturer[13]; + char model[16]; + + __be32 bits_per_cell; + __be32 bytes_per_page; + __be32 spare_bytes_per_page; + __be32 pages_per_block; + __be32 blocks_per_lun; + __be32 max_bb_per_lun; + __be32 planes_per_lun; + __be32 luns_per_target; + __be32 total_target; + + __be32 ecc_strength; + __be32 ecc_step_size; + + u8 flags; + u8 reserved1; + + __be16 sdr_read_cap; + struct op_slice sdr_read_1_1_1; + struct op_slice sdr_read_1_1_1_fast; + struct op_slice sdr_read_1_1_2; + struct op_slice sdr_read_1_2_2; + struct op_slice sdr_read_1_1_4; + struct op_slice sdr_read_1_4_4; + struct op_slice sdr_read_1_1_8; + struct op_slice sdr_read_1_8_8; + + struct op_slice sdr_cont_read_1_1_1; + struct op_slice sdr_cont_read_1_1_1_fast; + struct op_slice sdr_cont_read_1_1_2; + struct op_slice sdr_cont_read_1_2_2; + struct op_slice sdr_cont_read_1_1_4; + struct op_slice sdr_cont_read_1_4_4; + struct op_slice sdr_cont_read_1_1_8; + struct op_slice sdr_cont_read_1_8_8; + + __be16 ddr_read_cap; + struct op_slice ddr_read_1_1_1; + struct op_slice ddr_read_1_1_1_fast; + struct op_slice ddr_read_1_1_2; + struct op_slice ddr_read_1_2_2; + struct op_slice ddr_read_1_1_4; + struct op_slice ddr_read_1_4_4; + struct op_slice ddr_read_1_1_8; + struct op_slice ddr_read_1_8_8; + + struct op_slice ddr_cont_read_1_1_1; + struct op_slice ddr_cont_read_1_1_1_fast; + struct op_slice ddr_cont_read_1_1_2; + struct op_slice ddr_cont_read_1_2_2; + struct op_slice ddr_cont_read_1_1_4; + struct op_slice ddr_cont_read_1_4_4; + struct op_slice ddr_cont_read_1_1_8; + struct op_slice ddr_cont_read_1_8_8; + + u8 sdr_write_cap; + struct op_slice sdr_write_1_1_1; + struct op_slice sdr_write_1_1_4; + struct op_slice reserved2[6]; + u8 ddr_write_cap; + struct op_slice reserved3[8]; + + u8 sdr_update_cap; + struct op_slice sdr_update_1_1_1; + struct op_slice sdr_update_1_1_4; + struct op_slice reserved4[6]; + u8 ddr_update_cap; + struct op_slice reserved5[8]; + + struct CASN_OOB casn_oob; + + /* Advanced ECC status CMD0 (higher bits) */ + struct ADV_ECC_STATUS ecc_status_high; + /* Advanced ECC status CMD1 (lower bits) */ + struct ADV_ECC_STATUS ecc_status_low; + + u8 advecc_noerr_status; + u8 advecc_uncor_status; + u8 advecc_post_op; + u8 advecc_post_mask; + + u8 reserved6[5]; + __be16 crc; +} __packed; + +#endif /* __LINUX_MTD_CASN_H */ -- 2.45.2 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 2/4] include: mtd: Add CASN page definition and related structs. 2024-10-20 13:27 ` [RFC PATCH nand/next 2/4] include: mtd: Add CASN page definition and related structs Sky Huang @ 2024-11-18 10:58 ` Miquel Raynal 0 siblings, 0 replies; 13+ messages in thread From: Miquel Raynal @ 2024-11-18 10:58 UTC (permalink / raw) To: Sky Huang Cc: Matthias Brugger, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek, Steven Liu On 20/10/2024 at 21:27:20 +08, Sky Huang <SkyLake.Huang@mediatek.com> wrote: > From: "Sky Huang" <skylake.huang@mediatek.com> > > This patch adds CASN page definition. You can see corresponding > table in CASN page application note referred in cover letter. > (https://github.com/mtk-openwrt/doc/blob/ > main/CASN%20Page%20Introduction.pdf) Please don't break URLs. They become no longer clickable. > > + > +struct SPINAND_FLAGS { No upper case struct type please. Thanks, Miquèl ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH nand/next 3/4] include: mtd: spinand: Add CASN page related macros and flags. 2024-10-20 13:27 [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support Sky Huang 2024-10-20 13:27 ` [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page Sky Huang 2024-10-20 13:27 ` [RFC PATCH nand/next 2/4] include: mtd: Add CASN page definition and related structs Sky Huang @ 2024-10-20 13:27 ` Sky Huang 2024-11-18 13:06 ` Miquel Raynal 2024-10-20 13:27 ` [RFC PATCH nand/next 4/4] mtd: nand: spi: Add CASN page support Sky Huang ` (2 subsequent siblings) 5 siblings, 1 reply; 13+ messages in thread From: Sky Huang @ 2024-10-20 13:27 UTC (permalink / raw) To: Matthias Brugger, Miquel Raynal, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek Cc: Steven Liu, Sky Huang From: "Sky Huang" <skylake.huang@mediatek.com> This patch adds SPINAND CASN page manipulation macros for SPI-NAND driver to use. Also, some important flag bits, like SPINAND_SUPR_CR(continuous read), are added to show the SPI-NAND device's capability. Signed-off-by: Sky Huang <skylake.huang@mediatek.com> --- include/linux/mtd/spinand.h | 100 +++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h index 702e5fb13dae..de97994c357b 100644 --- a/include/linux/mtd/spinand.h +++ b/include/linux/mtd/spinand.h @@ -62,6 +62,59 @@ SPI_MEM_OP_NO_DUMMY, \ SPI_MEM_OP_NO_DATA) +/* Macros for CASN */ +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_OP(fast, naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 1)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_X2_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 2)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_DUALIO_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 2), \ + SPI_MEM_OP_DUMMY(ndummy, 2), \ + SPI_MEM_OP_DATA_IN(len, buf, 2)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_X4_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_DUMMY(ndummy, 1), \ + SPI_MEM_OP_DATA_IN(len, buf, 4)) + +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_QUADIO_OP(naddr, addr, ndummy, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 4), \ + SPI_MEM_OP_DUMMY(ndummy, 4), \ + SPI_MEM_OP_DATA_IN(len, buf, 4)) + +#define SPINAND_CASN_PROG_LOAD(reset, naddr, addr, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(len, buf, 1)) + +#define SPINAND_CASN_PROG_LOAD_X4(reset, naddr, addr, buf, len) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \ + SPI_MEM_OP_ADDR(naddr, addr, 1), \ + SPI_MEM_OP_NO_DUMMY, \ + SPI_MEM_OP_DATA_OUT(len, buf, 4)) + +#define SPINAND_CASN_ADVECC_OP(casn_adv_ecc_status, buf) \ + SPI_MEM_OP(SPI_MEM_OP_CMD(casn_adv_ecc_status.cmd, 1), \ + SPI_MEM_OP_ADDR(casn_adv_ecc_status.addr_nbytes, \ + casn_adv_ecc_status.addr, \ + casn_adv_ecc_status.addr_buswidth), \ + SPI_MEM_OP_DUMMY(casn_adv_ecc_status.dummy_nbytes, \ + casn_adv_ecc_status.dummy_buswidth), \ + SPI_MEM_OP_DATA_IN(casn_adv_ecc_status.status_nbytes, buf, 1)) +/* Macros for CASN end */ + #define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len) \ SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \ SPI_MEM_OP_ADDR(2, addr, 1), \ @@ -312,8 +365,11 @@ struct spinand_ecc_info { #define SPINAND_HAS_QE_BIT BIT(0) #define SPINAND_HAS_CR_FEAT_BIT BIT(1) -#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) -#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) +#define SPINAND_SUP_CR BIT(2) +#define SPINAND_SUP_ON_DIE_ECC BIT(3) +#define SPINAND_SUP_LEGACY_ECC_STATUS BIT(4) +#define SPINAND_SUP_ADV_ECC_STATUS BIT(5) +#define SPINAND_ECC_PARITY_READABLE BIT(6) /** * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure @@ -406,6 +462,28 @@ struct spinand_dirmap { struct spi_mem_dirmap_desc *rdesc_ecc; }; +/** + * struct CASN_ADVECC - CASN's advanced ECC description + * @cmd: Command to access SPI-NAND on-chip ECC status registers + * @mask: Mask to access SPI-NAND on-chip ECC status registers. + * ADV_ECC_STATUS->status_nbytes | CASN_ADVECC->mask + * 1 | 0 to 0xff + * 2 | 0 to 0xffff + * @shift: How many bits to shift to get on-chip ECC status + * @pre_op: This comes from CASN page's ADV_ECC_STATUS's pre_op. + * After reading on-chip ECC status, we need to do some math + * operations if this is specified. + * @pre_mask: This comes from CASN page's ADV_ECC_STATUS's pre_mask. + * This is used in companion with pre_op above. + */ +struct CASN_ADVECC { + u8 cmd; + u16 mask; + u8 shift; + u8 pre_op; + u8 pre_mask; +}; + /** * struct spinand_device - SPI NAND device instance * @base: NAND device instance @@ -464,6 +542,23 @@ struct spinand_device { u8 *oobbuf; u8 *scratchbuf; const struct spinand_manufacturer *manufacturer; + + bool use_casn; + struct nand_casn *casn; + struct spi_mem_op *advecc_high_ops; /* ops to read higher part of advanced ECC status*/ + struct spi_mem_op *advecc_low_ops; + struct CASN_OOB *casn_oob; + struct CASN_ADVECC *advecc_high; + struct CASN_ADVECC *advecc_low; + + u8 advecc_low_bitcnt; + u8 advecc_noerr_status; + u8 advecc_uncor_status; + u8 advecc_post_op; + u8 advecc_post_mask; + + size_t (*eccsr_math_op[4])(size_t, size_t); + void *priv; bool cont_read_possible; @@ -539,3 +634,4 @@ int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val); int spinand_select_target(struct spinand_device *spinand, unsigned int target); #endif /* __LINUX_MTD_SPINAND_H */ + -- 2.45.2 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 3/4] include: mtd: spinand: Add CASN page related macros and flags. 2024-10-20 13:27 ` [RFC PATCH nand/next 3/4] include: mtd: spinand: Add CASN page related macros and flags Sky Huang @ 2024-11-18 13:06 ` Miquel Raynal 0 siblings, 0 replies; 13+ messages in thread From: Miquel Raynal @ 2024-11-18 13:06 UTC (permalink / raw) To: Sky Huang Cc: Matthias Brugger, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek, Steven Liu On 20/10/2024 at 21:27:21 +08, Sky Huang <SkyLake.Huang@mediatek.com> wrote: > From: "Sky Huang" <skylake.huang@mediatek.com> > > This patch adds SPINAND CASN page manipulation macros for > SPI-NAND driver to use. Also, some important flag bits, like > SPINAND_SUPR_CR(continuous read), are added to show the > SPI-NAND device's capability. > > Signed-off-by: Sky Huang <skylake.huang@mediatek.com> > --- > include/linux/mtd/spinand.h | 100 +++++++++++++++++++++++++++++++++++- > 1 file changed, 98 insertions(+), 2 deletions(-) > > diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h > index 702e5fb13dae..de97994c357b 100644 > --- a/include/linux/mtd/spinand.h > +++ b/include/linux/mtd/spinand.h > @@ -62,6 +62,59 @@ > SPI_MEM_OP_NO_DUMMY, \ > SPI_MEM_OP_NO_DATA) > > +/* Macros for CASN */ > +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_OP(fast, naddr, addr, ndummy, buf, len) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \ > + SPI_MEM_OP_ADDR(naddr, addr, 1), \ > + SPI_MEM_OP_DUMMY(ndummy, 1), \ > + SPI_MEM_OP_DATA_IN(len, buf, 1)) > + > +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_X2_OP(naddr, addr, ndummy, buf, len) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \ > + SPI_MEM_OP_ADDR(naddr, addr, 1), \ > + SPI_MEM_OP_DUMMY(ndummy, 1), \ > + SPI_MEM_OP_DATA_IN(len, buf, 2)) > + > +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_DUALIO_OP(naddr, addr, ndummy, buf, len) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \ > + SPI_MEM_OP_ADDR(naddr, addr, 2), \ > + SPI_MEM_OP_DUMMY(ndummy, 2), \ > + SPI_MEM_OP_DATA_IN(len, buf, 2)) > + > +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_X4_OP(naddr, addr, ndummy, buf, len) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \ > + SPI_MEM_OP_ADDR(naddr, addr, 1), \ > + SPI_MEM_OP_DUMMY(ndummy, 1), \ > + SPI_MEM_OP_DATA_IN(len, buf, 4)) > + > +#define SPINAND_CASN_PAGE_READ_FROM_CACHE_QUADIO_OP(naddr, addr, ndummy, buf, len) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \ > + SPI_MEM_OP_ADDR(naddr, addr, 4), \ > + SPI_MEM_OP_DUMMY(ndummy, 4), \ > + SPI_MEM_OP_DATA_IN(len, buf, 4)) > + > +#define SPINAND_CASN_PROG_LOAD(reset, naddr, addr, buf, len) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x02 : 0x84, 1), \ > + SPI_MEM_OP_ADDR(naddr, addr, 1), \ > + SPI_MEM_OP_NO_DUMMY, \ > + SPI_MEM_OP_DATA_OUT(len, buf, 1)) > + > +#define SPINAND_CASN_PROG_LOAD_X4(reset, naddr, addr, buf, len) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(reset ? 0x32 : 0x34, 1), \ > + SPI_MEM_OP_ADDR(naddr, addr, 1), \ > + SPI_MEM_OP_NO_DUMMY, \ > + SPI_MEM_OP_DATA_OUT(len, buf, 4)) Why would you need to redefine all these? > + > +#define SPINAND_CASN_ADVECC_OP(casn_adv_ecc_status, buf) \ > + SPI_MEM_OP(SPI_MEM_OP_CMD(casn_adv_ecc_status.cmd, 1), \ > + SPI_MEM_OP_ADDR(casn_adv_ecc_status.addr_nbytes, \ > + casn_adv_ecc_status.addr, \ > + casn_adv_ecc_status.addr_buswidth), \ > + SPI_MEM_OP_DUMMY(casn_adv_ecc_status.dummy_nbytes, \ > + casn_adv_ecc_status.dummy_buswidth), \ > + SPI_MEM_OP_DATA_IN(casn_adv_ecc_status.status_nbytes, buf, 1)) > +/* Macros for CASN end */ > + > #define SPINAND_PAGE_READ_FROM_CACHE_OP(fast, addr, ndummy, buf, len) \ > SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \ > SPI_MEM_OP_ADDR(2, addr, 1), \ > @@ -312,8 +365,11 @@ struct spinand_ecc_info { > > #define SPINAND_HAS_QE_BIT BIT(0) > #define SPINAND_HAS_CR_FEAT_BIT BIT(1) > -#define SPINAND_HAS_PROG_PLANE_SELECT_BIT BIT(2) > -#define SPINAND_HAS_READ_PLANE_SELECT_BIT BIT(3) Why do you remove that? > +#define SPINAND_SUP_CR BIT(2) > +#define SPINAND_SUP_ON_DIE_ECC BIT(3) > +#define SPINAND_SUP_LEGACY_ECC_STATUS BIT(4) > +#define SPINAND_SUP_ADV_ECC_STATUS BIT(5) > +#define SPINAND_ECC_PARITY_READABLE BIT(6) > > /** > * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure > @@ -406,6 +462,28 @@ struct spinand_dirmap { > struct spi_mem_dirmap_desc *rdesc_ecc; > }; > > +/** > + * struct CASN_ADVECC - CASN's advanced ECC description > + * @cmd: Command to access SPI-NAND on-chip ECC status registers > + * @mask: Mask to access SPI-NAND on-chip ECC status registers. > + * ADV_ECC_STATUS->status_nbytes | CASN_ADVECC->mask > + * 1 | 0 to 0xff > + * 2 | 0 to 0xffff > + * @shift: How many bits to shift to get on-chip ECC status > + * @pre_op: This comes from CASN page's ADV_ECC_STATUS's pre_op. > + * After reading on-chip ECC status, we need to do some math > + * operations if this is specified. I'm not sure I understand how you'll encode a math operation there. > + * @pre_mask: This comes from CASN page's ADV_ECC_STATUS's pre_mask. > + * This is used in companion with pre_op above. > + */ > +struct CASN_ADVECC { This is usually changing when continuous reads are enabled, it would need to be handled. > + u8 cmd; > + u16 mask; > + u8 shift; > + u8 pre_op; > + u8 pre_mask; > +}; > + Thanks, Miquèl ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH nand/next 4/4] mtd: nand: spi: Add CASN page support 2024-10-20 13:27 [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support Sky Huang ` (2 preceding siblings ...) 2024-10-20 13:27 ` [RFC PATCH nand/next 3/4] include: mtd: spinand: Add CASN page related macros and flags Sky Huang @ 2024-10-20 13:27 ` Sky Huang 2024-10-28 15:25 ` [RFC PATCH nand/next 0/4] " SkyLake Huang (黃啟澤) 2024-11-18 10:53 ` Miquel Raynal 5 siblings, 0 replies; 13+ messages in thread From: Sky Huang @ 2024-10-20 13:27 UTC (permalink / raw) To: Matthias Brugger, Miquel Raynal, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek Cc: Steven Liu, Sky Huang From: "Sky Huang" <skylake.huang@mediatek.com> This patch implements how CASN page detection works for SPI-NAND and how CASN page interprets ECC information of all SPI-NAND flash vendors. Probe flow will become like this: * If CASN page exists, check its validity. --> If a certain CASN page is valid, we will know the SPI-NAND device's information, including memory organization, flash on-chip ECC engine's design, etc. * If CASN page doesn't exist, switch to reading ID spinand_dump_casn() can be moved to sysfs, debugfs or something else later, I guess. Signed-off-by: Sky Huang <skylake.huang@mediatek.com> --- drivers/mtd/nand/spi/core.c | 741 +++++++++++++++++++++++++++++++++++- 1 file changed, 729 insertions(+), 12 deletions(-) diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 4d76f9f71a0e..7d7408e00b5e 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -9,10 +9,13 @@ #define pr_fmt(fmt) "spi-nand: " fmt +#include <linux/bitfield.h> #include <linux/device.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mtd/casn.h> +#include <linux/mtd/param.h> #include <linux/mtd/spinand.h> #include <linux/of.h> #include <linux/slab.h> @@ -20,6 +23,8 @@ #include <linux/spi/spi.h> #include <linux/spi/spi-mem.h> +extern void sanitize_string(uint8_t *s, size_t len); + static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg, @@ -200,6 +205,63 @@ static int spinand_ecc_enable(struct spinand_device *spinand, enable ? CFG_ECC_ENABLE : 0); } +static size_t eccsr_none_op(size_t val, size_t mask) { return val; } +static size_t eccsr_and_op(size_t val, size_t mask) { return val & mask; } +static size_t eccsr_add_op(size_t val, size_t mask) { return val + mask; } +static size_t eccsr_minus_op(size_t val, size_t mask) { return val - mask; } +static size_t eccsr_mul_op(size_t val, size_t mask) { return val * mask; } + +static void spinand_read_adv_ecc(struct spinand_device *spinand, + struct spi_mem_op *ops, u16 *eccsr, + u16 mask, u8 shift, + u8 pre_op, u8 pre_mask) +{ + u8 *p = spinand->scratchbuf; + + spi_mem_exec_op(spinand->spimem, ops); + + if (likely(mask <= 0xff)) + *eccsr += (*p & mask) >> shift; + else + *eccsr += (((*p << 8) | (*p+1)) & mask) >> shift; + + *eccsr = spinand->eccsr_math_op[pre_op](*eccsr, pre_mask); +} + +static int spinand_casn_get_ecc_status(struct spinand_device *spinand, + u8 status) +{ + struct mtd_info *mtd = spinand_to_mtd(spinand); + struct CASN_ADVECC *ah = spinand->advecc_high; + struct CASN_ADVECC *al = spinand->advecc_low; + u16 eccsr_high = 0; + u16 eccsr_low = 0; + u32 eccsr = 0; + + if (al->cmd) { + spinand_read_adv_ecc(spinand, + spinand->advecc_low_ops, &eccsr_low, + al->mask, al->shift, + al->pre_op, al->pre_mask); + eccsr += eccsr_low; + } + if (ah->cmd) { + spinand_read_adv_ecc(spinand, + spinand->advecc_high_ops, &eccsr_high, + ah->mask, ah->shift, + ah->pre_op, ah->pre_mask); + eccsr += eccsr_high << spinand->advecc_low_bitcnt; + } + + if (eccsr == spinand->advecc_noerr_status) + return 0; + else if (eccsr == spinand->advecc_uncor_status) + return -EBADMSG; + eccsr = spinand->eccsr_math_op[spinand->advecc_post_op](eccsr, spinand->advecc_post_mask); + + return eccsr > mtd->ecc_strength ? mtd->ecc_strength : eccsr; +} + static int spinand_cont_read_enable(struct spinand_device *spinand, bool enable) { @@ -1149,6 +1211,242 @@ static int spinand_manufacturer_match(struct spinand_device *spinand, return -EOPNOTSUPP; } +static int spinand_check_casn_validity(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct device *dev = &spinand->spimem->spi->dev; + + if (be32_to_cpu(casn->bits_per_cell) != 1) { + dev_err(dev, "[CASN] bits-per-cell must be 1\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->bytes_per_page)) { + case 2048: + case 4096: + break; + default: + dev_err(dev, "[CASN] page size must be 2048/4096\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->spare_bytes_per_page)) { + case 64: + case 96: + case 128: + case 256: + break; + default: + dev_err(dev, "[CASN] spare size must be 64/128/256\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->pages_per_block)) { + case 64: + case 128: + break; + default: + dev_err(dev, "[CASN] pages_per_block must be 64/128\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->blocks_per_lun)) { + case 1024: + if (be32_to_cpu(casn->max_bb_per_lun) != 20) { + dev_err(dev, "[CASN] max_bb_per_lun must be 20 when blocks_per_lun is 1024\n"); + return -EINVAL; + } + break; + case 2048: + if (be32_to_cpu(casn->max_bb_per_lun) != 40) { + dev_err(dev, "[CASN] max_bb_per_lun must be 40 when blocks_per_lun is 2048\n"); + return -EINVAL; + } + break; + case 4096: + if (be32_to_cpu(casn->max_bb_per_lun) != 80) { + dev_err(dev, "[CASN] max_bb_per_lun must be 80 when blocks_per_lun is 4096\n"); + return -EINVAL; + } + break; + default: + dev_err(dev, "[CASN] blocks_per_lun must be 1024/2048/4096\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->planes_per_lun)) { + case 1: + case 2: + break; + default: + dev_err(dev, "[CASN] planes_per_lun must be 1/2\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->luns_per_target)) { + case 1: + case 2: + break; + default: + dev_err(dev, "[CASN] luns_per_target must be 1/2\n"); + return -EINVAL; + } + + switch (be32_to_cpu(casn->total_target)) { + case 1: + case 2: + break; + default: + dev_err(dev, "[CASN] ntargets must be 1/2\n"); + return -EINVAL; + } + + if (casn->casn_oob.layout_type != OOB_CONTINUOUS && + casn->casn_oob.layout_type != OOB_DISCRETE) { + dev_err(dev, "[CASN] OOB layout type isn't correct.\n"); + return -EINVAL; + } + + if (casn->ecc_status_high.status_nbytes > 2 || + casn->ecc_status_low.status_nbytes > 2) { + dev_err(dev, "[CASN] ADVECC status nbytes must be no more than 2\n"); + return -EINVAL; + } + + return 0; +} + +static int spinand_check_casn(struct spinand_device *spinand, + struct nand_casn *casn, unsigned int *sel) +{ + struct device *dev = &spinand->spimem->spi->dev; + uint16_t crc = be16_to_cpu(casn->crc); + uint16_t crc_compute; + int ret = 0; + int i; + + /* There are 3 copies of CASN Pages V1. Choose one avabilable copy + * first. If none of the copies is available, try to recover. + */ + for (i = 0; i < CASN_PAGE_V1_COPIES; i++) { + if (be32_to_cpu(casn[i].signature) != CASN_SIGNATURE) { + ret = -EINVAL; + continue; + } + crc_compute = nanddev_crc16(CASN_CRC_BASE, (u8 *)(casn + i), + SPINAND_CASN_V1_CRC_OFS); + dev_dbg(dev, "CASN COPY %d CRC read: 0x%x, compute: 0x%x\n", + i, crc, crc_compute); + if (crc != crc_compute) { + ret = -EBADMSG; + continue; + } + ret = spinand_check_casn_validity(spinand, casn + i); + if (ret < 0) + continue; + *sel = i; + break; + } + + if (i == CASN_PAGE_V1_COPIES && ret == -EBADMSG) { + const void *srcbufs[CASN_PAGE_V1_COPIES]; + int j; + + for (j = 0; j < CASN_PAGE_V1_COPIES; j++) + srcbufs[j] = casn + j; + dev_info(dev, "Couldn't find a valid CASN page, try bitwise majority to recover it\n"); + nanddev_bit_wise_majority(srcbufs, CASN_PAGE_V1_COPIES, casn, + sizeof(*casn)); + crc_compute = nanddev_crc16(CASN_CRC_BASE, (uint8_t *)casn, + SPINAND_CASN_V1_CRC_OFS); + if (crc_compute != crc) { + dev_err(dev, "CASN page recovery failed, aborting\n"); + return -EBADMSG; + } + ret = spinand_check_casn_validity(spinand, casn + i); + if (ret < 0) + return ret; + dev_info(dev, "CASN page recovery succeeded\n"); + *sel = 0; + } + + return ret; +} + +static int spinand_casn_detect(struct spinand_device *spinand, + struct nand_casn *casn, unsigned int *sel) +{ + struct device *dev = &spinand->spimem->spi->dev; + uint8_t casn_offset[3] = {0x0, 0x1, 0x4}; + struct nand_page_io_req req; + struct spi_mem_op op; + struct nand_pos pos; + int check_ret = 0; + uint8_t status; + int final_ret; + int ret = 0; + u8 cfg_reg; + int i; + + ret = spinand_read_reg_op(spinand, REG_CFG, &cfg_reg); + if (ret) + return ret; + + ret = spinand_write_reg_op(spinand, REG_CFG, cfg_reg | BIT(6)); + if (ret) + return ret; + + memset(&pos, 0, sizeof(pos)); + + req = (struct nand_page_io_req){ + .pos = pos, + .dataoffs = 0, + .datalen = 256 * CASN_PAGE_V1_COPIES, + .databuf.in = (u8 *)casn, + .mode = MTD_OPS_AUTO_OOB, + }; + + for (i = 0; i < sizeof(casn_offset)/sizeof(uint8_t); i++) { + req.pos.page = casn_offset[i]; + ret = spinand_load_page_op(spinand, &req); + if (ret) + goto finish; + + ret = spinand_wait(spinand, + SPINAND_READ_INITIAL_DELAY_US, + SPINAND_READ_POLL_DELAY_US, + &status); + if (ret < 0) + goto finish; + + op = (struct spi_mem_op) SPINAND_PAGE_READ_FROM_CACHE_OP( + false, 768, 1, (u8 *)casn, 256 * CASN_PAGE_V1_COPIES); + ret = spi_mem_exec_op(spinand->spimem, &op); + if (ret < 0) + goto finish; + + check_ret = spinand_check_casn(spinand, casn, sel); + if (!check_ret) + break; + } + +finish: + /* We need to restore configuration register. */ + final_ret = spinand_write_reg_op(spinand, REG_CFG, cfg_reg); + if (final_ret) + return final_ret; + + if (check_ret) { + dev_err(dev, "CASN page check failed\n"); + return check_ret; + } + + if (ret) + dev_err(dev, "CASN page read failed\n"); + + return ret; +} + static int spinand_id_detect(struct spinand_device *spinand) { u8 *id = spinand->id.data; @@ -1180,7 +1478,7 @@ static int spinand_id_detect(struct spinand_device *spinand) static int spinand_manufacturer_init(struct spinand_device *spinand) { - if (spinand->manufacturer->ops->init) + if (!spinand->use_casn && spinand->manufacturer->ops->init) return spinand->manufacturer->ops->init(spinand); return 0; @@ -1189,7 +1487,7 @@ static int spinand_manufacturer_init(struct spinand_device *spinand) static void spinand_manufacturer_cleanup(struct spinand_device *spinand) { /* Release manufacturer private data */ - if (spinand->manufacturer->ops->cleanup) + if (!spinand->use_casn && spinand->manufacturer->ops->cleanup) return spinand->manufacturer->ops->cleanup(spinand); } @@ -1293,37 +1591,456 @@ int spinand_match_and_init(struct spinand_device *spinand, return -ENOTSUPP; } +static int spinand_casn_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + int sectionp; + struct CASN_OOB *co = spinand->casn_oob; + + sectionp = spinand->base.memorg.pagesize/mtd->ecc_step_size; + if (section >= sectionp) + return -ERANGE; + + if (co->layout_type == OOB_DISCRETE) { + region->offset = co->ecc_parity_start + + (co->free_length + co->ecc_parity_space) + * section; + } else if (co->layout_type == OOB_CONTINUOUS) { + region->offset = co->ecc_parity_start + co->ecc_parity_space * section; + } + region->length = co->ecc_parity_real_length; + + return 0; +} + +static int spinand_casn_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + int sectionp; + struct CASN_OOB *co = spinand->casn_oob; + + sectionp = spinand->base.memorg.pagesize/mtd->ecc_step_size; + if (section >= sectionp) + return -ERANGE; + + if (!section) { + region->offset = co->free_start + co->bbm_length; + region->length = co->free_length - co->bbm_length; + } else { + if (co->layout_type == OOB_DISCRETE) { + region->offset = co->free_start + + (co->free_length + + co->ecc_parity_space) * section; + } else if (co->layout_type == OOB_CONTINUOUS) { + region->offset = co->free_start + + co->free_length * section; + } + region->length = co->free_length; + } + + return 0; +} + +static const struct mtd_ooblayout_ops spinand_casn_ooblayout = { + .ecc = spinand_casn_ooblayout_ecc, + .free = spinand_casn_ooblayout_free, +}; + +static int spinand_set_read_op_variants(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct spinand_op_variants casn_read_cache_variants; + u16 sdr_read_cap = be16_to_cpu(casn->sdr_read_cap); + struct spi_mem_op *read_ops; + const struct spi_mem_op *op; + int i = 0; + + read_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op) * + hweight16(sdr_read_cap), + GFP_KERNEL); + if (!read_ops) + return -ENOMEM; + + if (FIELD_GET(SDR_READ_1_4_4, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_QUADIO_OP( + casn->sdr_read_1_4_4.addr_nbytes, 0, + casn->sdr_read_1_4_4.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_4, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_X4_OP( + casn->sdr_read_1_1_4.addr_nbytes, 0, + casn->sdr_read_1_1_4.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_2_2, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_DUALIO_OP( + casn->sdr_read_1_2_2.addr_nbytes, 0, + casn->sdr_read_1_2_2.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_2, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_X2_OP( + casn->sdr_read_1_1_2.addr_nbytes, 0, + casn->sdr_read_1_1_2.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_1_FAST, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_OP( + true, casn->sdr_read_1_1_1_fast.addr_nbytes, 0, + casn->sdr_read_1_1_1_fast.dummy_nbytes, NULL, 0 + ); + i++; + } + if (FIELD_GET(SDR_READ_1_1_1, sdr_read_cap)) { + read_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PAGE_READ_FROM_CACHE_OP( + false, casn->sdr_read_1_1_1.addr_nbytes, 0, + casn->sdr_read_1_1_1.dummy_nbytes, NULL, 0 + ); + i++; + } + + casn_read_cache_variants = (struct spinand_op_variants){ + .ops = read_ops, + .nops = hweight16(sdr_read_cap), + }; + + op = spinand_select_op_variant(spinand, &casn_read_cache_variants); + if (!op) { + devm_kfree(&spinand->spimem->spi->dev, read_ops); + return -EOPNOTSUPP; + } + spinand->op_templates.read_cache = op; + + return 0; +} + +static int spinand_set_write_op_variants(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct spinand_op_variants casn_write_cache_variants; + struct spi_mem_op *write_ops; + const struct spi_mem_op *op; + int i = 0; + + write_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op) * + hweight8(casn->sdr_write_cap), + GFP_KERNEL); + if (!write_ops) + return -ENOMEM; + + if (FIELD_GET(SDR_WRITE_1_1_4, casn->sdr_write_cap)) { + write_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD_X4( + true, casn->sdr_write_1_1_4.addr_nbytes, 0, + NULL, 0); + i++; + } + if (FIELD_GET(SDR_WRITE_1_1_1, casn->sdr_write_cap)) { + write_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD( + true, casn->sdr_write_1_1_1.addr_nbytes, 0, + NULL, 0); + i++; + } + + casn_write_cache_variants = (struct spinand_op_variants){ + .ops = write_ops, + .nops = hweight8(casn->sdr_write_cap), + }; + + op = spinand_select_op_variant(spinand, &casn_write_cache_variants); + if (!op) { + devm_kfree(&spinand->spimem->spi->dev, write_ops); + return -EOPNOTSUPP; + } + spinand->op_templates.write_cache = op; + + return 0; +} + +static int spinand_set_update_op_variants(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct spinand_op_variants casn_update_cache_variants; + struct spi_mem_op *update_ops; + const struct spi_mem_op *op; + int i = 0; + + update_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op) * + hweight8(casn->sdr_update_cap), + GFP_KERNEL); + if (!update_ops) + return -ENOMEM; + + if (FIELD_GET(SDR_UPDATE_1_1_4, casn->sdr_update_cap)) { + update_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD_X4( + false, casn->sdr_update_1_1_4.addr_nbytes, 0, + NULL, 0); + i++; + } + if (FIELD_GET(SDR_UPDATE_1_1_1, casn->sdr_update_cap)) { + update_ops[i] = (struct spi_mem_op) + SPINAND_CASN_PROG_LOAD( + false, casn->sdr_update_1_1_1.addr_nbytes, 0, + NULL, 0); + i++; + } + + casn_update_cache_variants = (struct spinand_op_variants){ + .ops = update_ops, + .nops = hweight8(casn->sdr_update_cap), + }; + + op = spinand_select_op_variant(spinand, &casn_update_cache_variants); + if (!op) { + devm_kfree(&spinand->spimem->spi->dev, update_ops); + return -EOPNOTSUPP; + } + spinand->op_templates.update_cache = op; + + return 0; +} + +static int spinand_init_via_casn(struct spinand_device *spinand, + struct nand_casn *casn) +{ + struct nand_device *nand = spinand_to_nand(spinand); + u32 val; + int ret; + int i; + + /* Set members of nand->memorg via CASN. */ + for (i = 0; i < 9; i++) { + val = be32_to_cpu(*(&casn->bits_per_cell + i)); + memcpy((u32 *)&nand->memorg.bits_per_cell + i, &val, sizeof(u32)); + } + nand->ecc.requirements.strength = be32_to_cpu(casn->ecc_strength); + nand->ecc.requirements.step_size = be32_to_cpu(casn->ecc_step_size); + spinand->flags = casn->flags; + + if (spinand->flags & SPINAND_SUP_ADV_ECC_STATUS) { + spinand->eccinfo = (struct spinand_ecc_info) { + &spinand_casn_get_ecc_status, &spinand_casn_ooblayout}; + } else { + spinand->eccinfo = (struct spinand_ecc_info) { + NULL, &spinand_casn_ooblayout }; + } + + spinand->advecc_high_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op), + GFP_KERNEL); + if (!spinand->advecc_high_ops) + return -ENOMEM; + spinand->advecc_low_ops = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct spi_mem_op), + GFP_KERNEL); + if (!spinand->advecc_low_ops) + return -ENOMEM; + spinand->casn_oob = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct CASN_OOB), + GFP_KERNEL); + if (!spinand->casn_oob) + return -ENOMEM; + spinand->advecc_high = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct CASN_ADVECC), + GFP_KERNEL); + if (!spinand->advecc_high) + return -ENOMEM; + spinand->advecc_low = devm_kzalloc(&spinand->spimem->spi->dev, + sizeof(struct CASN_ADVECC), + GFP_KERNEL); + if (!spinand->advecc_low) + return -ENOMEM; + + *spinand->advecc_high_ops = (struct spi_mem_op) + SPINAND_CASN_ADVECC_OP(casn->ecc_status_high, spinand->scratchbuf); + *spinand->advecc_low_ops = (struct spi_mem_op) + SPINAND_CASN_ADVECC_OP(casn->ecc_status_low, spinand->scratchbuf); + + memcpy(spinand->casn_oob, &casn->casn_oob, sizeof(struct CASN_OOB)); + + spinand->advecc_high->cmd = casn->ecc_status_high.cmd; + spinand->advecc_high->mask = be16_to_cpu(casn->ecc_status_high.status_mask); + spinand->advecc_high->shift = spinand->advecc_high->mask ? + ffs(spinand->advecc_high->mask)-1 : 0; + spinand->advecc_high->pre_op = casn->ecc_status_high.pre_op; + spinand->advecc_high->pre_mask = casn->ecc_status_high.pre_mask; + + spinand->advecc_low->cmd = casn->ecc_status_low.cmd; + spinand->advecc_low->mask = be16_to_cpu(casn->ecc_status_low.status_mask); + spinand->advecc_low->shift = spinand->advecc_low->mask ? + ffs(spinand->advecc_low->mask)-1 : 0; + spinand->advecc_low->pre_op = casn->ecc_status_low.pre_op; + spinand->advecc_low->pre_mask = casn->ecc_status_low.pre_mask; + + spinand->advecc_low_bitcnt = hweight16(spinand->advecc_low->mask); + + spinand->advecc_noerr_status = casn->advecc_noerr_status; + spinand->advecc_uncor_status = casn->advecc_uncor_status; + spinand->advecc_post_op = casn->advecc_post_op; + spinand->advecc_post_mask = casn->advecc_post_mask; + spinand->eccsr_math_op[0] = eccsr_none_op; + spinand->eccsr_math_op[1] = eccsr_and_op; + spinand->eccsr_math_op[2] = eccsr_add_op; + spinand->eccsr_math_op[3] = eccsr_minus_op; + spinand->eccsr_math_op[4] = eccsr_mul_op; + + ret = spinand_set_read_op_variants(spinand, casn); + if (ret < 0) + return ret; + ret = spinand_set_write_op_variants(spinand, casn); + if (ret < 0) + return ret; + ret = spinand_set_update_op_variants(spinand, casn); + if (ret < 0) + return ret; + + return 0; +} + +static void spinand_dump_casn(struct spinand_device *spinand, struct nand_casn *casn) +{ + int i; + + dev_dbg(&spinand->spimem->spi->dev, + "---Start dumping full CASN page---\n"); + for (i = 0; i < 64; i++) + pr_debug("0x%08x", *((u32 *)casn + i)); + + pr_debug("** Dump critical fields **\n"); + pr_debug("signature: 0x%04x\n", be32_to_cpu(casn->signature)); + pr_debug("version: v%u.%u\n", casn->version >> 4, casn->version & 0xf); + pr_debug("[Memory Organization]\n"); + pr_debug(" bits_per_cell: %d\n", be32_to_cpu(casn->bits_per_cell)); + pr_debug(" bytes_per_page: %d\n", be32_to_cpu(casn->bytes_per_page)); + pr_debug(" spare_bytes_per_page: %d\n", + be32_to_cpu(casn->spare_bytes_per_page)); + pr_debug(" pages_per_block: %d\n", + be32_to_cpu(casn->pages_per_block)); + pr_debug(" blocks_per_lun: %d\n", be32_to_cpu(casn->blocks_per_lun)); + pr_debug(" max_bb_per_lun: %d\n", be32_to_cpu(casn->max_bb_per_lun)); + pr_debug(" planes_per_lun: %d\n", be32_to_cpu(casn->planes_per_lun)); + pr_debug(" luns_per_target: %d\n", + be32_to_cpu(casn->luns_per_target)); + pr_debug(" total_target: %d\n", be32_to_cpu(casn->total_target)); + pr_debug("[flags]\n"); + pr_debug(" 0. Have QE bit? %s\n", + casn->flags & SPINAND_HAS_QE_BIT ? "Yes" : "No"); + pr_debug(" 1. Have continuous read feature bit? %s\n", + casn->flags & SPINAND_HAS_CR_FEAT_BIT ? "Yes" : "No"); + pr_debug(" 2. Support continuous read? %s\n", + casn->flags & SPINAND_SUP_CR ? "Yes" : "No"); + pr_debug(" 3. Support on-die ECC? %s\n", + casn->flags & SPINAND_SUP_ON_DIE_ECC ? "Yes" : "No"); + pr_debug(" 4. Support legacy ECC status? %s\n", + casn->flags & SPINAND_SUP_LEGACY_ECC_STATUS ? "Yes" : "No"); + pr_debug(" 5. Support advanced ECC status? %s\n", + casn->flags & SPINAND_SUP_ADV_ECC_STATUS ? "Yes" : "No"); + pr_debug(" 6. ECC parity readable? %s\n", + casn->flags & SPINAND_ECC_PARITY_READABLE ? "Yes" : "No"); + pr_debug("[R/W ability]\n"); + pr_debug(" read ability: %x\n", be16_to_cpu(casn->sdr_read_cap)); + pr_debug(" write ability: %x\n", casn->sdr_write_cap); + pr_debug(" update ability: %x\n", casn->sdr_update_cap); + pr_debug("advanced ECC no error state: %x\n", + casn->advecc_noerr_status); + pr_debug("advecced ECC uncorrectable state: %x\n", + casn->advecc_uncor_status); + pr_debug("CRC: 0x%04x\n", be16_to_cpu(casn->crc)); + + dev_dbg(&spinand->spimem->spi->dev, + "---Dumping full CASN page ends here.---\n"); +} + static int spinand_detect(struct spinand_device *spinand) { - struct device *dev = &spinand->spimem->spi->dev; struct nand_device *nand = spinand_to_nand(spinand); + struct device *dev = &spinand->spimem->spi->dev; + struct nand_casn *casn; + char manufacturer[14]; + unsigned int sel = 0; + char model[17]; int ret; ret = spinand_reset_op(spinand); if (ret) return ret; - ret = spinand_id_detect(spinand); - if (ret) { - dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN, - spinand->id.data); - return ret; + spinand->use_casn = false; + casn = kzalloc((sizeof(struct nand_casn) * CASN_PAGE_V1_COPIES), GFP_KERNEL); + if (!casn) + return -ENOMEM; + + ret = spinand_casn_detect(spinand, casn, &sel); + if (!ret) { + spinand->use_casn = true; + strscpy(manufacturer, casn[sel].manufacturer, sizeof(manufacturer)-1); + sanitize_string(manufacturer, sizeof(manufacturer)); + strscpy(model, casn[sel].model, sizeof(model)-1); + sanitize_string(model, sizeof(model)); + + spinand_dump_casn(spinand, casn + sel); + + ret = spinand_init_via_casn(spinand, casn + sel); + if (ret) + dev_err(dev, "Initializing spinand via CASN fails: %d\n", ret); + } + + if (ret < 0) { + dev_warn(dev, "Fallback to read ID\n"); + + ret = spinand_reset_op(spinand); + if (ret) + goto free_casn; + ret = spinand_id_detect(spinand); + if (ret) { + dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN, + spinand->id.data); + goto free_casn; + } } if (nand->memorg.ntargets > 1 && !spinand->select_target) { dev_err(dev, "SPI NANDs with more than one die must implement ->select_target()\n"); - return -EINVAL; + ret = -EINVAL; + goto free_casn; + } + + if (spinand->use_casn) { + dev_info(&spinand->spimem->spi->dev, + "%s %s SPI NAND was found.\n", manufacturer, model); + } else { + dev_info(&spinand->spimem->spi->dev, + "%s SPI NAND was found.\n", spinand->manufacturer->name); } - dev_info(&spinand->spimem->spi->dev, - "%s SPI NAND was found.\n", spinand->manufacturer->name); dev_info(&spinand->spimem->spi->dev, "%llu MiB, block size: %zu KiB, page size: %zu, OOB size: %u\n", nanddev_size(nand) >> 20, nanddev_eraseblock_size(nand) >> 10, nanddev_page_size(nand), nanddev_per_page_oobsize(nand)); - return 0; +free_casn: + kfree(casn); + + return ret; } static int spinand_init_flash(struct spinand_device *spinand) -- 2.45.2 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support 2024-10-20 13:27 [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support Sky Huang ` (3 preceding siblings ...) 2024-10-20 13:27 ` [RFC PATCH nand/next 4/4] mtd: nand: spi: Add CASN page support Sky Huang @ 2024-10-28 15:25 ` SkyLake Huang (黃啟澤) 2024-11-06 15:20 ` Miquel Raynal 2024-11-18 10:53 ` Miquel Raynal 5 siblings, 1 reply; 13+ messages in thread From: SkyLake Huang (黃啟澤) @ 2024-10-28 15:25 UTC (permalink / raw) To: miquel.raynal@bootlin.com, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-mediatek@lists.infradead.org, acelan.kao@canonical.com, chengminglin@mxic.com.tw, mika.westerberg@linux.intel.com, linux-arm-kernel@lists.infradead.org, matthias.bgg@gmail.com, daniel@makrotopia.org, vigneshr@ti.com, AngeloGioacchino Del Regno, richard@nod.at On Sun, 2024-10-20 at 21:27 +0800, Sky Huang wrote: > From: "Sky Huang" <skylake.huang@mediatek.com> > > Hi, this is Qi-Ze Huang(Sky Huang) from MediaTek. On our router > platforms > chips, we have to quality lots of SPI-NAND devices and are eager for > a standard so that we don't need to maintain trivial flash ID table > anymore. I also noticed a talk in 2019 Embedded Linux Conference, > Memory Technology Devices: what's new, which mentioned "ONFI for > SPI-NANDs? Maybe, maybe not". > > So earlier this year, I proposed a bold idea, CASN page (Common > Attributes > for SPI-NAND). I worked together with top 3 SPI-NAND market share > flash > vendors and other vendors to integrate CASN page on their SPI-NAND > devices > including but not limited to: > gentle ping BRs, Sky ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support 2024-10-28 15:25 ` [RFC PATCH nand/next 0/4] " SkyLake Huang (黃啟澤) @ 2024-11-06 15:20 ` Miquel Raynal 0 siblings, 0 replies; 13+ messages in thread From: Miquel Raynal @ 2024-11-06 15:20 UTC (permalink / raw) To: SkyLake Huang Cc: linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-mediatek@lists.infradead.org, acelan.kao@canonical.com, chengminglin@mxic.com.tw, mika.westerberg@linux.intel.com, linux-arm-kernel@lists.infradead.org, matthias.bgg@gmail.com, daniel@makrotopia.org, vigneshr@ti.com, AngeloGioacchino Del Regno, richard@nod.at Hello, On 28/10/2024 at 15:25:59 GMT, SkyLake Huang (黃啟澤) <SkyLake.Huang@mediatek.com> wrote: > On Sun, 2024-10-20 at 21:27 +0800, Sky Huang wrote: >> From: "Sky Huang" <skylake.huang@mediatek.com> >> >> Hi, this is Qi-Ze Huang(Sky Huang) from MediaTek. On our router >> platforms >> chips, we have to quality lots of SPI-NAND devices and are eager for >> a standard so that we don't need to maintain trivial flash ID table >> anymore. I also noticed a talk in 2019 Embedded Linux Conference, >> Memory Technology Devices: what's new, which mentioned "ONFI for >> SPI-NANDs? Maybe, maybe not". >> >> So earlier this year, I proposed a bold idea, CASN page (Common >> Attributes >> for SPI-NAND). I worked together with top 3 SPI-NAND market share >> flash >> vendors and other vendors to integrate CASN page on their SPI-NAND >> devices >> including but not limited to: >> > gentle ping I had a look at it, it is interesting but I have some questions and need to come back to it. Unfortunately I was a bit busy these days. Sorry for the delay. Thanks, Miquèl ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support 2024-10-20 13:27 [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support Sky Huang ` (4 preceding siblings ...) 2024-10-28 15:25 ` [RFC PATCH nand/next 0/4] " SkyLake Huang (黃啟澤) @ 2024-11-18 10:53 ` Miquel Raynal 2024-11-20 7:24 ` SkyLake Huang (黃啟澤) 5 siblings, 1 reply; 13+ messages in thread From: Miquel Raynal @ 2024-11-18 10:53 UTC (permalink / raw) To: Sky Huang Cc: Matthias Brugger, AngeloGioacchino Del Regno, Richard Weinberger, Vignesh Raghavendra, Daniel Golle, Chia-Lin Kao, Mika Westerberg, Cheng Ming Lin, linux-kernel, linux-mtd, linux-arm-kernel, linux-mediatek, Steven Liu On 20/10/2024 at 21:27:18 +08, Sky Huang <SkyLake.Huang@mediatek.com> wrote: > From: "Sky Huang" <skylake.huang@mediatek.com> > > Hi, this is Qi-Ze Huang(Sky Huang) from MediaTek. On our router platforms > chips, we have to quality lots of SPI-NAND devices and are eager for > a standard so that we don't need to maintain trivial flash ID table > anymore. I also noticed a talk in 2019 Embedded Linux Conference, > Memory Technology Devices: what's new, which mentioned "ONFI for > SPI-NANDs? Maybe, maybe not". > > So earlier this year, I proposed a bold idea, CASN page (Common Attributes > for SPI-NAND). I worked together with top 3 SPI-NAND market share flash > vendors and other vendors to integrate CASN page on their SPI-NAND devices > including but not limited to: > [ESMT] > F50L1G41LB > F50L2G41KA > > [Etron] > EM73C044VCF-H > EM73D044VCO-H > EM73E044VCE-H > EM73F044VCA-H > > [GigaDevice] > GD5F1GM7UE > GD5F1GQ5UEYIG > GD5F2GM7UE > GD5F2GQ5UEYIG > GD5F4GM8UE > GD5F4GQ6UEYIG > > [Macronix (MXIC)] > MX35LF1GE4ABZ4IG > > [Winbond] > W25N01GV > W25N01KV > W25N02KV > W25N04KV > > A document of CASN is hosted on github(https://github.com/mtk-openwrt/ > doc/blob/main/CASN%20Page%20Introduction.pdf) So I'll try to keep it > simple here. > > With CASN page, we don't need to maintain SPI-NAND flash ID table anymore. > Currently, it's integrated in 3.3V SPI-NANDs of small density and it's not > JEDEC standard yet. But it should be able to handle 1.8V and can be easily > integrated by flash vendors. > > I believe this idea and implementation have room for improvement. Hope to > hear you open source community's comments soon. I think this is a bright initiative. I'd welcome some standardisation on the discovery indeed. But to be really useful, I believe this table must be really complete, otherwise ID's will remain. For instance SDR/DDR modes are not entirely defined as we already have mixed modes. There is also no information about what maximum frequencies can be used with each operation. As another example, there is no read retry information. Nor anything about the fact that the on-die ECC engine might not be disabled. Overall I think this is an interesting initiative but I would like it to be more advanced. Is there a plan on getting this standardized through eg. a JEDEC spec? Thanks, Miquèl ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support 2024-11-18 10:53 ` Miquel Raynal @ 2024-11-20 7:24 ` SkyLake Huang (黃啟澤) 2024-11-20 10:13 ` Miquel Raynal 0 siblings, 1 reply; 13+ messages in thread From: SkyLake Huang (黃啟澤) @ 2024-11-20 7:24 UTC (permalink / raw) To: miquel.raynal@bootlin.com Cc: linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-mediatek@lists.infradead.org, acelan.kao@canonical.com, chengminglin@mxic.com.tw, mika.westerberg@linux.intel.com, linux-arm-kernel@lists.infradead.org, Steven Liu (劉人豪), matthias.bgg@gmail.com, daniel@makrotopia.org, vigneshr@ti.com, AngeloGioacchino Del Regno, richard@nod.at On Mon, 2024-11-18 at 11:53 +0100, Miquel Raynal wrote: > External email : Please do not click links or open attachments until > you have verified the sender or the content. > > > On 20/10/2024 at 21:27:18 +08, Sky Huang <SkyLake.Huang@mediatek.com> > wrote: > > > From: "Sky Huang" <skylake.huang@mediatek.com> > > > > Hi, this is Qi-Ze Huang(Sky Huang) from MediaTek. On our router > > platforms > > chips, we have to quality lots of SPI-NAND devices and are eager > > for > > a standard so that we don't need to maintain trivial flash ID table > > anymore. I also noticed a talk in 2019 Embedded Linux Conference, > > Memory Technology Devices: what's new, which mentioned "ONFI for > > SPI-NANDs? Maybe, maybe not". > > > > So earlier this year, I proposed a bold idea, CASN page (Common > > Attributes > > for SPI-NAND). I worked together with top 3 SPI-NAND market share > > flash > > vendors and other vendors to integrate CASN page on their SPI-NAND > > devices > > including but not limited to: > > [ESMT] > > F50L1G41LB > > F50L2G41KA > > > > [Etron] > > EM73C044VCF-H > > EM73D044VCO-H > > EM73E044VCE-H > > EM73F044VCA-H > > > > [GigaDevice] > > GD5F1GM7UE > > GD5F1GQ5UEYIG > > GD5F2GM7UE > > GD5F2GQ5UEYIG > > GD5F4GM8UE > > GD5F4GQ6UEYIG > > > > [Macronix (MXIC)] > > MX35LF1GE4ABZ4IG > > > > [Winbond] > > W25N01GV > > W25N01KV > > W25N02KV > > W25N04KV > > > > A document of CASN is hosted on github( > > https://urldefense.com/v3/__https://github.com/mtk-openwrt/__;!!CTRNKA9wMg0ARbw!j_TES7dJ_An-9wtyQqWgGBE9ovPnUA-tDNlZ-pGpUdYv4gphzW4v54Fal8i_nLwSmPAzK9ApgSBG1XQ_mREdTS0ZwrBWRA$ > > doc/blob/main/CASN%20Page%20Introduction.pdf) So I'll try to keep > > it > > simple here. > > > > With CASN page, we don't need to maintain SPI-NAND flash ID table > > anymore. > > Currently, it's integrated in 3.3V SPI-NANDs of small density and > > it's not > > JEDEC standard yet. But it should be able to handle 1.8V and can be > > easily > > integrated by flash vendors. > > > > I believe this idea and implementation have room for improvement. > > Hope to > > hear you open source community's comments soon. > > I think this is a bright initiative. I'd welcome some standardisation > on > the discovery indeed. > > But to be really useful, I believe this table must be really > complete, > otherwise ID's will remain. For instance SDR/DDR modes are not > entirely > defined as we already have mixed modes. There is also no information > about what maximum frequencies can be used with each operation. Maximum frequencies are limited by SPI controller's max freq now, I guess? > As > another example, there is no read retry information. What will retry information look like? > Nor anything about > the fact that the on-die ECC engine might not be disabled. As far as I know, only SkyHigh's SPI-NAND's ECC engine can't be disabled since its on-die ECC engine contains randomizer. There are some reserved fields. We can handle above requirements in CASN V1.2 or V2. But may I ask what's the purpose of involving above information in CASN? Are there any practical application scenarios? > > Overall I think this is an interesting initiative but I would like it > to > be more advanced. Agree. > Is there a plan on getting this standardized through > eg. a JEDEC spec? > > Thanks, > Miquèl Yes. We're working on it. But it will take some time. Your opinions mean a lot to CASN page standardisation. BRs, Sky ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support 2024-11-20 7:24 ` SkyLake Huang (黃啟澤) @ 2024-11-20 10:13 ` Miquel Raynal 0 siblings, 0 replies; 13+ messages in thread From: Miquel Raynal @ 2024-11-20 10:13 UTC (permalink / raw) To: SkyLake Huang Cc: linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-mediatek@lists.infradead.org, acelan.kao@canonical.com, chengminglin@mxic.com.tw, mika.westerberg@linux.intel.com, linux-arm-kernel@lists.infradead.org, Steven Liu, matthias.bgg@gmail.com, daniel@makrotopia.org, vigneshr@ti.com, AngeloGioacchino Del Regno, richard@nod.at On 20/11/2024 at 07:24:28 GMT, SkyLake Huang (黃啟澤) <SkyLake.Huang@mediatek.com> wrote: > On Mon, 2024-11-18 at 11:53 +0100, Miquel Raynal wrote: >> External email : Please do not click links or open attachments until >> you have verified the sender or the content. >> >> >> On 20/10/2024 at 21:27:18 +08, Sky Huang <SkyLake.Huang@mediatek.com> >> wrote: >> >> > From: "Sky Huang" <skylake.huang@mediatek.com> >> > >> > Hi, this is Qi-Ze Huang(Sky Huang) from MediaTek. On our router >> > platforms >> > chips, we have to quality lots of SPI-NAND devices and are eager >> > for >> > a standard so that we don't need to maintain trivial flash ID table >> > anymore. I also noticed a talk in 2019 Embedded Linux Conference, >> > Memory Technology Devices: what's new, which mentioned "ONFI for >> > SPI-NANDs? Maybe, maybe not". >> > >> > So earlier this year, I proposed a bold idea, CASN page (Common >> > Attributes >> > for SPI-NAND). I worked together with top 3 SPI-NAND market share >> > flash >> > vendors and other vendors to integrate CASN page on their SPI-NAND >> > devices >> > including but not limited to: >> > [ESMT] >> > F50L1G41LB >> > F50L2G41KA >> > >> > [Etron] >> > EM73C044VCF-H >> > EM73D044VCO-H >> > EM73E044VCE-H >> > EM73F044VCA-H >> > >> > [GigaDevice] >> > GD5F1GM7UE >> > GD5F1GQ5UEYIG >> > GD5F2GM7UE >> > GD5F2GQ5UEYIG >> > GD5F4GM8UE >> > GD5F4GQ6UEYIG >> > >> > [Macronix (MXIC)] >> > MX35LF1GE4ABZ4IG >> > >> > [Winbond] >> > W25N01GV >> > W25N01KV >> > W25N02KV >> > W25N04KV >> > >> > A document of CASN is hosted on github( >> > https://urldefense.com/v3/__https://github.com/mtk-openwrt/__;!!CTRNKA9wMg0ARbw!j_TES7dJ_An-9wtyQqWgGBE9ovPnUA-tDNlZ-pGpUdYv4gphzW4v54Fal8i_nLwSmPAzK9ApgSBG1XQ_mREdTS0ZwrBWRA$ >> > doc/blob/main/CASN%20Page%20Introduction.pdf) So I'll try to keep >> > it >> > simple here. >> > >> > With CASN page, we don't need to maintain SPI-NAND flash ID table >> > anymore. >> > Currently, it's integrated in 3.3V SPI-NANDs of small density and >> > it's not >> > JEDEC standard yet. But it should be able to handle 1.8V and can be >> > easily >> > integrated by flash vendors. >> > >> > I believe this idea and implementation have room for improvement. >> > Hope to >> > hear you open source community's comments soon. >> >> I think this is a bright initiative. I'd welcome some standardisation >> on >> the discovery indeed. >> >> But to be really useful, I believe this table must be really >> complete, >> otherwise ID's will remain. For instance SDR/DDR modes are not >> entirely >> defined as we already have mixed modes. There is also no information >> about what maximum frequencies can be used with each operation. > > Maximum frequencies are limited by SPI controller's max freq now, I > guess? No, this is just the PCB/controller limitation. But there are chips with frequency limitations depending on the type of command (see for instance Winbond AC timings tables for DDR capable devices). >> As >> another example, there is no read retry information. > What will retry information look like? Number of retry modes, how to enable retry mode (which is maybe standardized per manufacturer, in this case we can just get the right hook from the manufacturer information, but otherwise if there are differences inside production lines from a single manufacturer, we'll still need either a table or some extension of CASN. >> Nor anything about >> the fact that the on-die ECC engine might not be disabled. > As far as I know, only SkyHigh's SPI-NAND's ECC engine can't be > disabled since its on-die ECC engine contains randomizer. Randomizer and ECC engine are two different things, there are many raw NAND controllers with a programmable ECC engine *and* randomizer. They just choose to hide the controls. Today it is SkyHigh. What about tomorrow? > There are some reserved fields. We can handle above requirements in > CASN V1.2 or V2. But may I ask what's the purpose of involving above > information in CASN? Are there any practical application scenarios? You claim you want to replace the ID tables. These tables are filled with all the relevant data to make the chips supported in Linux. If one of these fields is missing from CASN, it means we need to keep the tables. So it kind of defeats the CASN purpose. Yes we may have dynamic vendor hooks to adapt these parameters "on the fly", but we still need internal tables for that. >> Overall I think this is an interesting initiative but I would like it >> to >> be more advanced. > Agree. > >> Is there a plan on getting this standardized through >> eg. a JEDEC spec? >> >> Thanks, >> Miquèl > Yes. We're working on it. But it will take some time. Your opinions > mean a lot to CASN page standardisation. Thanks, Miquèl ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2024-11-20 10:15 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-10-20 13:27 [RFC PATCH nand/next 0/4] mtd: nand: spi: Add CASN page support Sky Huang 2024-10-20 13:27 ` [RFC PATCH nand/next 1/4] mtd: nand: Create param.c to do CRC check and bitwise majority for Parameter & CASN page Sky Huang 2024-11-18 10:55 ` Miquel Raynal 2024-10-20 13:27 ` [RFC PATCH nand/next 2/4] include: mtd: Add CASN page definition and related structs Sky Huang 2024-11-18 10:58 ` Miquel Raynal 2024-10-20 13:27 ` [RFC PATCH nand/next 3/4] include: mtd: spinand: Add CASN page related macros and flags Sky Huang 2024-11-18 13:06 ` Miquel Raynal 2024-10-20 13:27 ` [RFC PATCH nand/next 4/4] mtd: nand: spi: Add CASN page support Sky Huang 2024-10-28 15:25 ` [RFC PATCH nand/next 0/4] " SkyLake Huang (黃啟澤) 2024-11-06 15:20 ` Miquel Raynal 2024-11-18 10:53 ` Miquel Raynal 2024-11-20 7:24 ` SkyLake Huang (黃啟澤) 2024-11-20 10:13 ` Miquel Raynal
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).