1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Author:
4  *	Chuanhong Guo <gch981213@gmail.com> - the main driver logic
5  *	Martin Kurbanov <mmkurbanov@sberdevices.ru> - OOB layout
6  */
7 
8 #include <linux/device.h>
9 #include <linux/kernel.h>
10 #include <linux/mtd/spinand.h>
11 #include <linux/spi/spi-mem.h>
12 
13 /* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
14 #define SPINAND_MFR_ESMT_C8			0xc8
15 
16 #define ESMT_F50L1G41LB_CFG_OTP_PROTECT		BIT(7)
17 #define ESMT_F50L1G41LB_CFG_OTP_LOCK		\
18 	(CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT)
19 
20 static SPINAND_OP_VARIANTS(read_cache_variants,
21 			   SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
22 			   SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
23 			   SPINAND_PAGE_READ_FROM_CACHE_FAST_OP(0, 1, NULL, 0),
24 			   SPINAND_PAGE_READ_FROM_CACHE_OP(0, 1, NULL, 0));
25 
26 static SPINAND_OP_VARIANTS(write_cache_variants,
27 			   SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
28 			   SPINAND_PROG_LOAD(true, 0, NULL, 0));
29 
30 static SPINAND_OP_VARIANTS(update_cache_variants,
31 			   SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
32 			   SPINAND_PROG_LOAD(false, 0, NULL, 0));
33 
34 /*
35  * OOB spare area map (64 bytes)
36  *
37  * Bad Block Markers
38  * filled by HW and kernel                 Reserved
39  *   |                 +-----------------------+-----------------------+
40  *   |                 |                       |                       |
41  *   |                 |    OOB free data Area |non ECC protected      |
42  *   |   +-------------|-----+-----------------|-----+-----------------|-----+
43  *   |   |             |     |                 |     |                 |     |
44  * +-|---|----------+--|-----|--------------+--|-----|--------------+--|-----|--------------+
45  * | |   | section0 |  |     |    section1  |  |     |    section2  |  |     |    section3  |
46  * +-v-+-v-+---+----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+
47  * |   |   |   |    |     |     |     |     |     |     |     |     |     |     |     |     |
48  * |0:1|2:3|4:7|8:15|16:17|18:19|20:23|24:31|32:33|34:35|36:39|40:47|48:49|50:51|52:55|56:63|
49  * |   |   |   |    |     |     |     |     |     |     |     |     |     |     |     |     |
50  * +---+---+-^-+--^-+-----+-----+--^--+--^--+-----+-----+--^--+--^--+-----+-----+--^--+--^--+
51  *           |    |                |     |                 |     |                 |     |
52  *           |    +----------------|-----+-----------------|-----+-----------------|-----+
53  *           |             ECC Area|(Main + Spare) - filled|by ESMT NAND HW        |
54  *           |                     |                       |                       |
55  *           +---------------------+-----------------------+-----------------------+
56  *                         OOB ECC protected Area - not used due to
57  *                         partial programming from some filesystems
58  *                             (like JFFS2 with cleanmarkers)
59  */
60 
61 #define ESMT_OOB_SECTION_COUNT			4
62 #define ESMT_OOB_SECTION_SIZE(nand) \
63 	(nanddev_per_page_oobsize(nand) / ESMT_OOB_SECTION_COUNT)
64 #define ESMT_OOB_FREE_SIZE(nand) \
65 	(ESMT_OOB_SECTION_SIZE(nand) / 2)
66 #define ESMT_OOB_ECC_SIZE(nand) \
67 	(ESMT_OOB_SECTION_SIZE(nand) - ESMT_OOB_FREE_SIZE(nand))
68 #define ESMT_OOB_BBM_SIZE			2
69 
f50l1g41lb_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)70 static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section,
71 				    struct mtd_oob_region *region)
72 {
73 	struct nand_device *nand = mtd_to_nanddev(mtd);
74 
75 	if (section >= ESMT_OOB_SECTION_COUNT)
76 		return -ERANGE;
77 
78 	region->offset = section * ESMT_OOB_SECTION_SIZE(nand) +
79 			 ESMT_OOB_FREE_SIZE(nand);
80 	region->length = ESMT_OOB_ECC_SIZE(nand);
81 
82 	return 0;
83 }
84 
f50l1g41lb_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)85 static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section,
86 				     struct mtd_oob_region *region)
87 {
88 	struct nand_device *nand = mtd_to_nanddev(mtd);
89 
90 	if (section >= ESMT_OOB_SECTION_COUNT)
91 		return -ERANGE;
92 
93 	/*
94 	 * Reserve space for bad blocks markers (section0) and
95 	 * reserved bytes (sections 1-3)
96 	 */
97 	region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + 2;
98 
99 	/* Use only 2 non-protected ECC bytes per each OOB section */
100 	region->length = 2;
101 
102 	return 0;
103 }
104 
105 static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
106 	.ecc = f50l1g41lb_ooblayout_ecc,
107 	.free = f50l1g41lb_ooblayout_free,
108 };
109 
f50l1g41lb_otp_info(struct spinand_device * spinand,size_t len,struct otp_info * buf,size_t * retlen,bool user)110 static int f50l1g41lb_otp_info(struct spinand_device *spinand, size_t len,
111 			       struct otp_info *buf, size_t *retlen, bool user)
112 {
113 	if (len < sizeof(*buf))
114 		return -EINVAL;
115 
116 	buf->locked = 0;
117 	buf->start = 0;
118 	buf->length = user ? spinand_user_otp_size(spinand) :
119 			     spinand_fact_otp_size(spinand);
120 
121 	*retlen = sizeof(*buf);
122 	return 0;
123 }
124 
f50l1g41lb_fact_otp_info(struct spinand_device * spinand,size_t len,struct otp_info * buf,size_t * retlen)125 static int f50l1g41lb_fact_otp_info(struct spinand_device *spinand, size_t len,
126 				    struct otp_info *buf, size_t *retlen)
127 {
128 	return f50l1g41lb_otp_info(spinand, len, buf, retlen, false);
129 }
130 
f50l1g41lb_user_otp_info(struct spinand_device * spinand,size_t len,struct otp_info * buf,size_t * retlen)131 static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len,
132 				    struct otp_info *buf, size_t *retlen)
133 {
134 	return f50l1g41lb_otp_info(spinand, len, buf, retlen, true);
135 }
136 
f50l1g41lb_otp_lock(struct spinand_device * spinand,loff_t from,size_t len)137 static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from,
138 			       size_t len)
139 {
140 	struct spi_mem_op write_op = SPINAND_WR_EN_DIS_OP(true);
141 	struct spi_mem_op exec_op = SPINAND_PROG_EXEC_OP(0);
142 	u8 status;
143 	int ret;
144 
145 	ret = spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK,
146 			      ESMT_F50L1G41LB_CFG_OTP_LOCK);
147 	if (!ret)
148 		return ret;
149 
150 	ret = spi_mem_exec_op(spinand->spimem, &write_op);
151 	if (!ret)
152 		goto out;
153 
154 	ret = spi_mem_exec_op(spinand->spimem, &exec_op);
155 	if (!ret)
156 		goto out;
157 
158 	ret = spinand_wait(spinand,
159 			   SPINAND_WRITE_INITIAL_DELAY_US,
160 			   SPINAND_WRITE_POLL_DELAY_US,
161 			   &status);
162 	if (!ret && (status & STATUS_PROG_FAILED))
163 		ret = -EIO;
164 
165 out:
166 	if (spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, 0)) {
167 		dev_warn(&spinand_to_mtd(spinand)->dev,
168 			 "Can not disable OTP mode\n");
169 		ret = -EIO;
170 	}
171 
172 	return ret;
173 }
174 
175 static const struct spinand_user_otp_ops f50l1g41lb_user_otp_ops = {
176 	.info = f50l1g41lb_user_otp_info,
177 	.lock = f50l1g41lb_otp_lock,
178 	.read = spinand_user_otp_read,
179 	.write = spinand_user_otp_write,
180 };
181 
182 static const struct spinand_fact_otp_ops f50l1g41lb_fact_otp_ops = {
183 	.info = f50l1g41lb_fact_otp_info,
184 	.read = spinand_fact_otp_read,
185 };
186 
187 static const struct spinand_info esmt_c8_spinand_table[] = {
188 	SPINAND_INFO("F50L1G41LB",
189 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
190 				0x7f, 0x7f),
191 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
192 		     NAND_ECCREQ(1, 512),
193 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
194 					      &write_cache_variants,
195 					      &update_cache_variants),
196 		     0,
197 		     SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL),
198 		     SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
199 		     SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
200 	SPINAND_INFO("F50D1G41LB",
201 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f,
202 				0x7f, 0x7f),
203 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
204 		     NAND_ECCREQ(1, 512),
205 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
206 					      &write_cache_variants,
207 					      &update_cache_variants),
208 		     0,
209 		     SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL),
210 		     SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops),
211 		     SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)),
212 	SPINAND_INFO("F50D2G41KA",
213 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f,
214 				0x7f, 0x7f),
215 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
216 		     NAND_ECCREQ(8, 512),
217 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
218 					      &write_cache_variants,
219 					      &update_cache_variants),
220 		     0,
221 		     SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
222 };
223 
224 static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
225 };
226 
227 const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
228 	.id = SPINAND_MFR_ESMT_C8,
229 	.name = "ESMT",
230 	.chips = esmt_c8_spinand_table,
231 	.nchips = ARRAY_SIZE(esmt_c8_spinand_table),
232 	.ops = &esmt_spinand_manuf_ops,
233 };
234