xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/winbond.c (revision f947fca4e63be90f2fbc2fa6ac2e99fcec95078a)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2017 exceet electronics GmbH
4  *
5  * Authors:
6  *	Frieder Schrempf <frieder.schrempf@exceet.de>
7  *	Boris Brezillon <boris.brezillon@bootlin.com>
8  */
9 
10 #ifndef __UBOOT__
11 #include <linux/device.h>
12 #include <linux/kernel.h>
13 #endif
14 #include <linux/mtd/spinand.h>
15 
16 #define SPINAND_MFR_WINBOND		0xEF
17 
18 #define WINBOND_CFG_BUF_READ		BIT(3)
19 
20 static SPINAND_OP_VARIANTS(read_cache_variants,
21 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
22 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
23 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
24 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
25 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
26 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
27 
28 #ifdef CONFIG_SPI_NAND_WINBOND_CONT_READ
29 static SPINAND_OP_VARIANTS(read_cache_variants_cont,
30 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
31 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
32 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
33 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
34 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
35 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
36 #endif
37 
38 static SPINAND_OP_VARIANTS(write_cache_variants,
39 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
40 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
41 
42 static SPINAND_OP_VARIANTS(update_cache_variants,
43 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
44 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
45 
46 static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
47 				  struct mtd_oob_region *region)
48 {
49 	if (section > 3)
50 		return -ERANGE;
51 
52 	region->offset = (16 * section) + 8;
53 	region->length = 8;
54 
55 	return 0;
56 }
57 
58 static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
59 				   struct mtd_oob_region *region)
60 {
61 	if (section > 3)
62 		return -ERANGE;
63 
64 	region->offset = (16 * section) + 2;
65 	region->length = 6;
66 
67 	return 0;
68 }
69 
70 static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
71 	.ecc = w25m02gv_ooblayout_ecc,
72 	.rfree = w25m02gv_ooblayout_free,
73 };
74 
75 static int w25m02gv_select_target(struct spinand_device *spinand,
76 				  unsigned int target)
77 {
78 	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),
79 					  SPI_MEM_OP_NO_ADDR,
80 					  SPI_MEM_OP_NO_DUMMY,
81 					  SPI_MEM_OP_DATA_OUT(1,
82 							spinand->scratchbuf,
83 							1));
84 
85 	*spinand->scratchbuf = target;
86 	return spi_mem_exec_op(spinand->slave, &op);
87 }
88 
89 static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
90 				  struct mtd_oob_region *region)
91 {
92 	if (section)
93 		return -ERANGE;
94 
95 	region->offset = 64;
96 	region->length = 64;
97 
98 	return 0;
99 }
100 
101 static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
102 				   struct mtd_oob_region *region)
103 {
104 	if (section)
105 		return -ERANGE;
106 
107 	/* Reserve 2 bytes for the BBM. */
108 	region->offset = 2;
109 	region->length = 62;
110 
111 	return 0;
112 }
113 
114 static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
115 	.ecc = w25n02kv_ooblayout_ecc,
116 	.rfree = w25n02kv_ooblayout_free,
117 };
118 
119 static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
120 				   u8 status)
121 {
122 	struct nand_device *nand = spinand_to_nand(spinand);
123 
124 	switch (status & STATUS_ECC_MASK) {
125 	case STATUS_ECC_NO_BITFLIPS:
126 		return 0;
127 
128 	case STATUS_ECC_UNCOR_ERROR:
129 		return -EBADMSG;
130 
131 	case STATUS_ECC_HAS_BITFLIPS:
132 		return 1;
133 
134 	default:
135 		return nand->eccreq.strength;
136 	}
137 
138 	return -EINVAL;
139 }
140 
141 /* Another set for the same id[2] devices in one series */
142 static const struct spinand_info winbond_spinand_table[] = {
143 	SPINAND_INFO("W25M02GV",
144 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAB),
145 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 2),
146 		     NAND_ECCREQ(1, 512),
147 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
148 					      &write_cache_variants,
149 					      &update_cache_variants),
150 		     0,
151 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
152 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
153 	SPINAND_INFO("W25N512GV",
154 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAA, 0x20),
155 		     NAND_MEMORG(1, 2048, 64, 64, 512, 1, 1, 1),
156 		     NAND_ECCREQ(1, 512),
157 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
158 					      &write_cache_variants,
159 					      &update_cache_variants),
160 		     0,
161 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
162 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
163 	SPINAND_INFO("W25N01GV",
164 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAA, 0x21),
165 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
166 		     NAND_ECCREQ(1, 512),
167 #ifdef CONFIG_SPI_NAND_WINBOND_CONT_READ
168 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_cont,
169 					      &write_cache_variants,
170 					      &update_cache_variants),
171 #else
172 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
173 					      &write_cache_variants,
174 					      &update_cache_variants),
175 #endif
176 		     0,
177 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
178 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
179 	SPINAND_INFO("W25N02KV",
180 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAA, 0x22),
181 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
182 		     NAND_ECCREQ(8, 512),
183 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
184 					      &write_cache_variants,
185 					      &update_cache_variants),
186 		     0,
187 		     SPINAND_ECCINFO(&w25n02kv_ooblayout,
188 				     w25n02kv_ecc_get_status)),
189 	SPINAND_INFO("W25N04KV",
190 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAA, 0x23),
191 		     NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
192 		     NAND_ECCREQ(8, 512),
193 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
194 					      &write_cache_variants,
195 					      &update_cache_variants),
196 		     0,
197 		     SPINAND_ECCINFO(&w25n02kv_ooblayout,
198 				     w25n02kv_ecc_get_status)),
199 	SPINAND_INFO("W25N01GW",
200 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBA, 0x21),
201 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
202 		     NAND_ECCREQ(1, 512),
203 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
204 					      &write_cache_variants,
205 					      &update_cache_variants),
206 		     0,
207 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
208 		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
209 	SPINAND_INFO("W25N02KW",
210 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBA, 0x22),
211 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
212 		     NAND_ECCREQ(8, 512),
213 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
214 					      &write_cache_variants,
215 					      &update_cache_variants),
216 		     0,
217 		     SPINAND_ECCINFO(&w25n02kv_ooblayout,
218 				     w25n02kv_ecc_get_status)),
219 	SPINAND_INFO("W25N01KV",
220 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAE, 0x21),
221 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
222 		     NAND_ECCREQ(4, 512),
223 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
224 					      &write_cache_variants,
225 					      &update_cache_variants),
226 		     0,
227 		     SPINAND_ECCINFO(&w25n02kv_ooblayout,
228 				     w25n02kv_ecc_get_status)),
229 	SPINAND_INFO("W25N01JWZEIG",
230 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBC, 0x21),
231 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
232 		     NAND_ECCREQ(1, 512),
233 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
234 					      &write_cache_variants,
235 					      &update_cache_variants),
236 		     SPINAND_HAS_QE_BIT,
237 		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
238 	SPINAND_INFO("W25N01KWZPIG",
239 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBE, 0x21),
240 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
241 		     NAND_ECCREQ(4, 512),
242 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
243 					      &write_cache_variants,
244 					      &update_cache_variants),
245 		     0,
246 		     SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
247 };
248 
249 static int winbond_spinand_init(struct spinand_device *spinand)
250 {
251 	struct nand_device *nand = spinand_to_nand(spinand);
252 	unsigned int i;
253 
254 	/*
255 	 * Make sure all dies are in buffer read mode and not continuous read
256 	 * mode.
257 	 */
258 	for (i = 0; i < nand->memorg.ntargets; i++) {
259 		spinand_select_target(spinand, i);
260 		spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ,
261 				WINBOND_CFG_BUF_READ);
262 	}
263 
264 	/* W25N01JWZEIG enable continuous read */
265 #ifdef CONFIG_SPI_NAND_WINBOND_CONT_READ
266 	if (spinand->id.data[1] == 0xaa && spinand->id.data[2] == 0x21) {
267 		spinand->support_cont_read = true;
268 		spinand_upd_cfg(spinand, CFG_BUF_ENABLE, 0);
269 		printf("Support cont_read\n");
270 	}
271 #endif
272 
273 	return 0;
274 }
275 
276 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
277 	.init = winbond_spinand_init,
278 };
279 
280 const struct spinand_manufacturer winbond_spinand_manufacturer = {
281 	.id = SPINAND_MFR_WINBOND,
282 	.name = "Winbond",
283 	.chips = winbond_spinand_table,
284 	.nchips = ARRAY_SIZE(winbond_spinand_table),
285 	.ops = &winbond_spinand_manuf_ops,
286 };
287