xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/esmt.c (revision fb6306ed830268464b1df12364a3d6c50a2d85ae)
152b00601SJon Lin // SPDX-License-Identifier: GPL-2.0
252b00601SJon Lin /*
352b00601SJon Lin  * Copyright (c) 2020 Grandstream Networks, Inc
452b00601SJon Lin  *
552b00601SJon Lin  * Authors:
652b00601SJon Lin  *	Carl <xjxia@grandstream.cn>
752b00601SJon Lin  */
852b00601SJon Lin 
952b00601SJon Lin #ifndef __UBOOT__
1052b00601SJon Lin #include <linux/device.h>
1152b00601SJon Lin #include <linux/kernel.h>
1252b00601SJon Lin #endif
1352b00601SJon Lin #include <linux/mtd/spinand.h>
1452b00601SJon Lin 
1552b00601SJon Lin #define SPINAND_MFR_ESMT		0xC8
1652b00601SJon Lin 
1752b00601SJon Lin static SPINAND_OP_VARIANTS(read_cache_variants,
1852b00601SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
1952b00601SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
2052b00601SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
2152b00601SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
2252b00601SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
2352b00601SJon Lin 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
2452b00601SJon Lin 
2552b00601SJon Lin static SPINAND_OP_VARIANTS(write_cache_variants,
2652b00601SJon Lin 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
2752b00601SJon Lin 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
2852b00601SJon Lin 
2952b00601SJon Lin static SPINAND_OP_VARIANTS(update_cache_variants,
3052b00601SJon Lin 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
3152b00601SJon Lin 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
3252b00601SJon Lin 
f50lxx41x_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)3352b00601SJon Lin static int f50lxx41x_ooblayout_ecc(struct mtd_info *mtd, int section,
3452b00601SJon Lin 				   struct mtd_oob_region *region)
3552b00601SJon Lin {
3652b00601SJon Lin 	if (section > 3)
3752b00601SJon Lin 		return -ERANGE;
3852b00601SJon Lin 
3952b00601SJon Lin 	region->offset = (16 * section) + 8;
4052b00601SJon Lin 	region->length = 8;
4152b00601SJon Lin 
4252b00601SJon Lin 	return 0;
4352b00601SJon Lin }
4452b00601SJon Lin 
f50lxx41x_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)4552b00601SJon Lin static int f50lxx41x_ooblayout_free(struct mtd_info *mtd, int section,
4652b00601SJon Lin 				    struct mtd_oob_region *region)
4752b00601SJon Lin {
4852b00601SJon Lin 	if (section > 3)
4952b00601SJon Lin 		return -ERANGE;
5052b00601SJon Lin 
5152b00601SJon Lin 	region->offset = (16 * section) + 2;
5252b00601SJon Lin 	region->length = 6;
5352b00601SJon Lin 
5452b00601SJon Lin 	return 0;
5552b00601SJon Lin }
5652b00601SJon Lin 
5752b00601SJon Lin static const struct mtd_ooblayout_ops f50lxx41x_ooblayout = {
5852b00601SJon Lin 	.ecc = f50lxx41x_ooblayout_ecc,
5952b00601SJon Lin 	.rfree = f50lxx41x_ooblayout_free,
6052b00601SJon Lin };
6152b00601SJon Lin 
f50l2g41ka_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)62*fb6306edSJon Lin static int f50l2g41ka_ooblayout_ecc(struct mtd_info *mtd, int section,
63*fb6306edSJon Lin 				    struct mtd_oob_region *region)
64*fb6306edSJon Lin {
65*fb6306edSJon Lin 	if (section)
66*fb6306edSJon Lin 		return -ERANGE;
67*fb6306edSJon Lin 
68*fb6306edSJon Lin 	region->offset = mtd->oobsize / 2;
69*fb6306edSJon Lin 	region->length = mtd->oobsize / 2;
70*fb6306edSJon Lin 
71*fb6306edSJon Lin 	return 0;
72*fb6306edSJon Lin }
73*fb6306edSJon Lin 
f50l2g41ka_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)74*fb6306edSJon Lin static int f50l2g41ka_ooblayout_free(struct mtd_info *mtd, int section,
75*fb6306edSJon Lin 				     struct mtd_oob_region *region)
76*fb6306edSJon Lin {
77*fb6306edSJon Lin 	if (section)
78*fb6306edSJon Lin 		return -ERANGE;
79*fb6306edSJon Lin 
80*fb6306edSJon Lin 	region->offset = 2;
81*fb6306edSJon Lin 	region->length = mtd->oobsize / 2 - 2;
82*fb6306edSJon Lin 
83*fb6306edSJon Lin 	return 0;
84*fb6306edSJon Lin }
85*fb6306edSJon Lin 
86*fb6306edSJon Lin static const struct mtd_ooblayout_ops f50l2g41ka_ooblayout = {
87*fb6306edSJon Lin 	.ecc = f50l2g41ka_ooblayout_ecc,
88*fb6306edSJon Lin 	.rfree = f50l2g41ka_ooblayout_free,
89*fb6306edSJon Lin };
90*fb6306edSJon Lin 
91*fb6306edSJon Lin /*
92*fb6306edSJon Lin  * ecc bits: 0xC0[4,6]
93*fb6306edSJon Lin  * [0b000], No bit errors were detected;
94*fb6306edSJon Lin  * [0b001] and [0b011], 1~6 Bit errors were detected and corrected. Not
95*fb6306edSJon Lin  *	reach Flipping Bits;
96*fb6306edSJon Lin  * [0b101], Bit error count equals the bit flip
97*fb6306edSJon Lin  *	detection threshold
98*fb6306edSJon Lin  * [0b010], Multiple bit errors were detected and
99*fb6306edSJon Lin  *	not corrected.
100*fb6306edSJon Lin  * others, Reserved.
101*fb6306edSJon Lin  */
f50l2g41ka_ecc_ecc_get_status(struct spinand_device * spinand,u8 status)102*fb6306edSJon Lin static int f50l2g41ka_ecc_ecc_get_status(struct spinand_device *spinand,
103*fb6306edSJon Lin 					 u8 status)
104*fb6306edSJon Lin {
105*fb6306edSJon Lin 	struct nand_device *nand = spinand_to_nand(spinand);
106*fb6306edSJon Lin 	u8 eccsr = (status & GENMASK(6, 4)) >> 4;
107*fb6306edSJon Lin 
108*fb6306edSJon Lin 	if (eccsr <= 1 || eccsr == 3)
109*fb6306edSJon Lin 		return eccsr;
110*fb6306edSJon Lin 	else if (eccsr == 5)
111*fb6306edSJon Lin 		return nand->eccreq.strength;
112*fb6306edSJon Lin 	else
113*fb6306edSJon Lin 		return -EBADMSG;
114*fb6306edSJon Lin }
115*fb6306edSJon Lin 
11652b00601SJon Lin static const struct spinand_info esmt_spinand_table[] = {
11781afcfe1SJon Lin 	SPINAND_INFO("F50L1G41LB",
11881afcfe1SJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x01),
11952b00601SJon Lin 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
12052b00601SJon Lin 		     NAND_ECCREQ(1, 512),
12152b00601SJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
12252b00601SJon Lin 					      &write_cache_variants,
12352b00601SJon Lin 					      &update_cache_variants),
12452b00601SJon Lin 		     0,
12552b00601SJon Lin 		     SPINAND_ECCINFO(&f50lxx41x_ooblayout, NULL)),
126*fb6306edSJon Lin 	SPINAND_INFO("F50L2G41KA",
127*fb6306edSJon Lin 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41, 0x7F),
128*fb6306edSJon Lin 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
129*fb6306edSJon Lin 		     NAND_ECCREQ(8, 512),
130*fb6306edSJon Lin 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
131*fb6306edSJon Lin 					      &write_cache_variants,
132*fb6306edSJon Lin 					      &update_cache_variants),
133*fb6306edSJon Lin 		     0,
134*fb6306edSJon Lin 		     SPINAND_ECCINFO(&f50l2g41ka_ooblayout, f50l2g41ka_ecc_ecc_get_status)),
13552b00601SJon Lin };
13652b00601SJon Lin 
13752b00601SJon Lin static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
13852b00601SJon Lin };
13952b00601SJon Lin 
14052b00601SJon Lin const struct spinand_manufacturer esmt_spinand_manufacturer = {
14152b00601SJon Lin 	.id = SPINAND_MFR_ESMT,
14252b00601SJon Lin 	.name = "esmt",
14381afcfe1SJon Lin 	.chips = esmt_spinand_table,
14481afcfe1SJon Lin 	.nchips = ARRAY_SIZE(esmt_spinand_table),
14552b00601SJon Lin 	.ops = &esmt_spinand_manuf_ops,
14652b00601SJon Lin };
147