File Index
Files and directories
Sign in
FILE

winbond.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mtd/nand/spi/winbond.c C
  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#include <linux/device.h>
 11#include <linux/kernel.h>
 12#include <linux/mtd/spinand.h>
 13#include <linux/units.h>
 14#include <linux/delay.h>
 15
 16#define SPINAND_MFR_WINBOND		0xEF
 17
 18#define WINBOND_CFG_BUF_READ		BIT(3)
 19
 20#define W25N04KV_STATUS_ECC_5_8_BITFLIPS	(3 << 4)
 21
 22#define W25N0XJW_SR4			0xD0
 23#define W25N0XJW_SR4_HS			BIT(2)
 24
 25#define W35N01JW_VCR_IO_MODE			0x00
 26#define W35N01JW_VCR_IO_MODE_SINGLE_SDR		0xFF
 27#define W35N01JW_VCR_IO_MODE_OCTAL_SDR		0xDF
 28#define W35N01JW_VCR_IO_MODE_OCTAL_DDR_DS	0xE7
 29#define W35N01JW_VCR_IO_MODE_OCTAL_DDR		0xC7
 30#define W35N01JW_VCR_DUMMY_CLOCK_REG	0x01
 31
 32/*
 33 * "X2" in the core is equivalent to "dual output" in the datasheets,
 34 * "X4" in the core is equivalent to "quad output" in the datasheets.
 35 * Quad and octal capable chips feature an absolute maximum frequency of 166MHz.
 36 */
 37
 38static SPINAND_OP_VARIANTS(read_cache_octal_variants,
 39		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 3, NULL, 0, 120 * HZ_PER_MHZ),
 40		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 2, NULL, 0, 105 * HZ_PER_MHZ),
 41		SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 20, NULL, 0, 0),
 42		SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 16, NULL, 0, 162 * HZ_PER_MHZ),
 43		SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 12, NULL, 0, 124 * HZ_PER_MHZ),
 44		SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 8, NULL, 0, 86 * HZ_PER_MHZ),
 45		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 2, NULL, 0, 0),
 46		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 1, NULL, 0, 133 * HZ_PER_MHZ),
 47		SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
 48		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
 49
 50static SPINAND_OP_VARIANTS(write_cache_octal_variants,
 51		SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0),
 52		SPINAND_PROG_LOAD_1S_1S_8S_OP(0, NULL, 0),
 53		SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
 54
 55static SPINAND_OP_VARIANTS(update_cache_octal_variants,
 56		SPINAND_PROG_LOAD_1S_8S_8S_OP(false, 0, NULL, 0),
 57		SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
 58
 59static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_variants,
 60		SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ),
 61		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
 62		SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0),
 63		SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 104 * HZ_PER_MHZ),
 64		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
 65		SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ),
 66		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
 67		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0),
 68		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 104 * HZ_PER_MHZ),
 69		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
 70		SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ),
 71		SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
 72		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ));
 73
 74static SPINAND_OP_VARIANTS(read_cache_variants,
 75		SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0),
 76		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
 77		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
 78		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
 79		SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
 80		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
 81
 82static SPINAND_OP_VARIANTS(write_cache_variants,
 83		SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
 84		SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
 85
 86static SPINAND_OP_VARIANTS(update_cache_variants,
 87		SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
 88		SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
 89
 90static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
 91				  struct mtd_oob_region *region)
 92{
 93	if (section > 3)
 94		return -ERANGE;
 95
 96	region->offset = (16 * section) + 8;
 97	region->length = 8;
 98
 99	return 0;
100}
101
102static int w25m02gv_ooblayout_free(struct mtd_info *mtd, int section,
103				   struct mtd_oob_region *region)
104{
105	if (section > 3)
106		return -ERANGE;
107
108	region->offset = (16 * section) + 2;
109	region->length = 6;
110
111	return 0;
112}
113
114static const struct mtd_ooblayout_ops w25m02gv_ooblayout = {
115	.ecc = w25m02gv_ooblayout_ecc,
116	.free = w25m02gv_ooblayout_free,
117};
118
119static int w25m02gv_select_target(struct spinand_device *spinand,
120				  unsigned int target)
121{
122	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0xc2, 1),
123					  SPI_MEM_OP_NO_ADDR,
124					  SPI_MEM_OP_NO_DUMMY,
125					  SPI_MEM_OP_DATA_OUT(1,
126							spinand->scratchbuf,
127							1));
128
129	*spinand->scratchbuf = target;
130	return spi_mem_exec_op(spinand->spimem, &op);
131}
132
133static int w25n01kv_ooblayout_ecc(struct mtd_info *mtd, int section,
134				  struct mtd_oob_region *region)
135{
136	if (section > 3)
137		return -ERANGE;
138
139	region->offset = 64 + (8 * section);
140	region->length = 7;
141
142	return 0;
143}
144
145static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section,
146				  struct mtd_oob_region *region)
147{
148	if (section > 3)
149		return -ERANGE;
150
151	region->offset = 64 + (16 * section);
152	region->length = 13;
153
154	return 0;
155}
156
157static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section,
158				   struct mtd_oob_region *region)
159{
160	if (section > 3)
161		return -ERANGE;
162
163	region->offset = (16 * section) + 2;
164	region->length = 14;
165
166	return 0;
167}
168
169static const struct mtd_ooblayout_ops w25n01kv_ooblayout = {
170	.ecc = w25n01kv_ooblayout_ecc,
171	.free = w25n02kv_ooblayout_free,
172};
173
174static const struct mtd_ooblayout_ops w25n02kv_ooblayout = {
175	.ecc = w25n02kv_ooblayout_ecc,
176	.free = w25n02kv_ooblayout_free,
177};
178
179static int w25n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
180				  struct mtd_oob_region *region)
181{
182	if (section > 3)
183		return -ERANGE;
184
185	region->offset = (16 * section) + 12;
186	region->length = 4;
187
188	return 0;
189}
190
191static int w25n01jw_ooblayout_free(struct mtd_info *mtd, int section,
192				   struct mtd_oob_region *region)
193{
194	if (section > 3)
195		return -ERANGE;
196
197	region->offset = (16 * section);
198	region->length = 12;
199
200	/* Extract BBM */
201	if (!section) {
202		region->offset += 2;
203		region->length -= 2;
204	}
205
206	return 0;
207}
208
209static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section,
210				  struct mtd_oob_region *region)
211{
212	if (section > 7)
213		return -ERANGE;
214
215	region->offset = (16 * section) + 12;
216	region->length = 4;
217
218	return 0;
219}
220
221static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section,
222				   struct mtd_oob_region *region)
223{
224	if (section > 7)
225		return -ERANGE;
226
227	region->offset = 16 * section;
228	region->length = 12;
229
230	/* Extract BBM */
231	if (!section) {
232		region->offset += 2;
233		region->length -= 2;
234	}
235
236	return 0;
237}
238
239static const struct mtd_ooblayout_ops w25n01jw_ooblayout = {
240	.ecc = w25n01jw_ooblayout_ecc,
241	.free = w25n01jw_ooblayout_free,
242};
243
244static const struct mtd_ooblayout_ops w35n01jw_ooblayout = {
245	.ecc = w35n01jw_ooblayout_ecc,
246	.free = w35n01jw_ooblayout_free,
247};
248
249static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
250				   u8 status)
251{
252	struct nand_device *nand = spinand_to_nand(spinand);
253	u8 mbf = 0;
254	struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf);
255
256	switch (status & STATUS_ECC_MASK) {
257	case STATUS_ECC_NO_BITFLIPS:
258		return 0;
259
260	case STATUS_ECC_UNCOR_ERROR:
261		return -EBADMSG;
262
263	case STATUS_ECC_HAS_BITFLIPS:
264	case W25N04KV_STATUS_ECC_5_8_BITFLIPS:
265		/*
266		 * Let's try to retrieve the real maximum number of bitflips
267		 * in order to avoid forcing the wear-leveling layer to move
268		 * data around if it's not necessary.
269		 */
270		if (spi_mem_exec_op(spinand->spimem, &op))
271			return nanddev_get_ecc_conf(nand)->strength;
272
273		mbf = *(spinand->scratchbuf) >> 4;
274
275		if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf))
276			return nanddev_get_ecc_conf(nand)->strength;
277
278		return mbf;
279
280	default:
281		break;
282	}
283
284	return -EINVAL;
285}
286
287static int w25n0xjw_hs_cfg(struct spinand_device *spinand)
288{
289	const struct spi_mem_op *op;
290	bool hs;
291	u8 sr4;
292	int ret;
293
294	op = spinand->op_templates.read_cache;
295	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
296		hs = false;
297	else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 &&
298		 op->dummy.buswidth == 1 && op->data.buswidth == 1)
299		hs = false;
300	else if (!op->max_freq)
301		hs = true;
302	else
303		hs = false;
304
305	ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4);
306	if (ret)
307		return ret;
308
309	if (hs)
310		sr4 |= W25N0XJW_SR4_HS;
311	else
312		sr4 &= ~W25N0XJW_SR4_HS;
313
314	ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4);
315	if (ret)
316		return ret;
317
318	return 0;
319}
320
321static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val)
322{
323	struct spi_mem_op op =
324		SPI_MEM_OP(SPI_MEM_OP_CMD(0x81, 1),
325			   SPI_MEM_OP_ADDR(3, reg, 1),
326			   SPI_MEM_OP_NO_DUMMY,
327			   SPI_MEM_OP_DATA_OUT(1, spinand->scratchbuf, 1));
328	int ret;
329
330	*spinand->scratchbuf = val;
331
332	ret = spinand_write_enable_op(spinand);
333	if (ret)
334		return ret;
335
336	ret = spi_mem_exec_op(spinand->spimem, &op);
337	if (ret)
338		return ret;
339
340	/*
341	 * Write VCR operation doesn't set the busy bit in SR, which means we
342	 * cannot perform a status poll. Minimum time of 50ns is needed to
343	 * complete the write.
344	 */
345	ndelay(50);
346
347	return 0;
348}
349
350static int w35n0xjw_vcr_cfg(struct spinand_device *spinand)
351{
352	const struct spi_mem_op *op;
353	unsigned int dummy_cycles;
354	bool dtr, single;
355	u8 io_mode;
356	int ret;
357
358	op = spinand->op_templates.read_cache;
359
360	single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1);
361	dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr);
362	if (single && !dtr)
363		io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR;
364	else if (!single && !dtr)
365		io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR;
366	else if (!single && dtr)
367		io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR;
368	else
369		return -EINVAL;
370
371	ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE, io_mode);
372	if (ret)
373		return ret;
374
375	dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
376	switch (dummy_cycles) {
377	case 8:
378	case 12:
379	case 16:
380	case 20:
381	case 24:
382	case 28:
383		break;
384	default:
385		return -EINVAL;
386	}
387	ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_DUMMY_CLOCK_REG, dummy_cycles);
388	if (ret)
389		return ret;
390
391	return 0;
392}
393
394static const struct spinand_info winbond_spinand_table[] = {
395	/* 512M-bit densities */
396	SPINAND_INFO("W25N512GW", /* 1.8V */
397		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20),
398		     NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1),
399		     NAND_ECCREQ(1, 512),
400		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
401					      &write_cache_variants,
402					      &update_cache_variants),
403		     0,
404		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
405	/* 1G-bit densities */
406	SPINAND_INFO("W25N01GV", /* 3.3V */
407		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21),
408		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
409		     NAND_ECCREQ(1, 512),
410		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
411					      &write_cache_variants,
412					      &update_cache_variants),
413		     0,
414		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
415	SPINAND_INFO("W25N01GW", /* 1.8V */
416		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21),
417		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
418		     NAND_ECCREQ(1, 512),
419		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
420					      &write_cache_variants,
421					      &update_cache_variants),
422		     0,
423		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
424	SPINAND_INFO("W25N01JW", /* high-speed 1.8V */
425		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21),
426		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
427		     NAND_ECCREQ(1, 512),
428		     SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants,
429					      &write_cache_variants,
430					      &update_cache_variants),
431		     0,
432		     SPINAND_ECCINFO(&w25n01jw_ooblayout, NULL),
433		     SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
434	SPINAND_INFO("W25N01KV", /* 3.3V */
435		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
436		     NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1),
437		     NAND_ECCREQ(4, 512),
438		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
439					      &write_cache_variants,
440					      &update_cache_variants),
441		     0,
442		     SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)),
443	SPINAND_INFO("W35N01JW", /* 1.8V */
444		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21),
445		     NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1),
446		     NAND_ECCREQ(1, 512),
447		     SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
448					      &write_cache_octal_variants,
449					      &update_cache_octal_variants),
450		     0,
451		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
452		     SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
453	SPINAND_INFO("W35N02JW", /* 1.8V */
454		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22),
455		     NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1),
456		     NAND_ECCREQ(1, 512),
457		     SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
458					      &write_cache_octal_variants,
459					      &update_cache_octal_variants),
460		     0,
461		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
462		     SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
463	SPINAND_INFO("W35N04JW", /* 1.8V */
464		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23),
465		     NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1),
466		     NAND_ECCREQ(1, 512),
467		     SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants,
468					      &write_cache_octal_variants,
469					      &update_cache_octal_variants),
470		     0,
471		     SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL),
472		     SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)),
473	/* 2G-bit densities */
474	SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */
475		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21),
476		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
477		     NAND_ECCREQ(1, 512),
478		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
479					      &write_cache_variants,
480					      &update_cache_variants),
481		     0,
482		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
483		     SPINAND_SELECT_TARGET(w25m02gv_select_target)),
484	SPINAND_INFO("W25N02JW", /* high-speed 1.8V */
485		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22),
486		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1),
487		     NAND_ECCREQ(1, 512),
488		     SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants,
489					      &write_cache_variants,
490					      &update_cache_variants),
491		     0,
492		     SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
493		     SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)),
494	SPINAND_INFO("W25N02KV", /* 3.3V */
495		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
496		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
497		     NAND_ECCREQ(8, 512),
498		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
499					      &write_cache_variants,
500					      &update_cache_variants),
501		     0,
502		     SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
503	SPINAND_INFO("W25N02KW", /* 1.8V */
504		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x22),
505		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
506		     NAND_ECCREQ(8, 512),
507		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
508					      &write_cache_variants,
509					      &update_cache_variants),
510		     0,
511		     SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
512	/* 4G-bit densities */
513	SPINAND_INFO("W25N04KV", /* 3.3V */
514		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
515		     NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1),
516		     NAND_ECCREQ(8, 512),
517		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
518					      &write_cache_variants,
519					      &update_cache_variants),
520		     0,
521		     SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
522	SPINAND_INFO("W25N04KW", /* 1.8V */
523		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x23),
524		     NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 1, 1, 1),
525		     NAND_ECCREQ(8, 512),
526		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
527					      &write_cache_variants,
528					      &update_cache_variants),
529		     0,
530		     SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
531};
532
533static int winbond_spinand_init(struct spinand_device *spinand)
534{
535	struct nand_device *nand = spinand_to_nand(spinand);
536	unsigned int i;
537
538	/*
539	 * Make sure all dies are in buffer read mode and not continuous read
540	 * mode.
541	 */
542	for (i = 0; i < nand->memorg.ntargets; i++) {
543		spinand_select_target(spinand, i);
544		spinand_upd_cfg(spinand, WINBOND_CFG_BUF_READ,
545				WINBOND_CFG_BUF_READ);
546	}
547
548	return 0;
549}
550
551static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
552	.init = winbond_spinand_init,
553};
554
555const struct spinand_manufacturer winbond_spinand_manufacturer = {
556	.id = SPINAND_MFR_WINBOND,
557	.name = "Winbond",
558	.chips = winbond_spinand_table,
559	.nchips = ARRAY_SIZE(winbond_spinand_table),
560	.ops = &winbond_spinand_manuf_ops,
561};
~/ Read-only file preview.