Message ID | 20241020132722.20565-4-SkyLake.Huang@mediatek.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | mtd: nand: spi: Add CASN page support | expand |
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
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 */ +