1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018 exceet electronics GmbH
4 * Copyright (c) 2018 Kontron Electronics GmbH
5 *
6 * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
7 */
8
9#include <linux/device.h>
10#include <linux/kernel.h>
11#include <linux/mtd/spinand.h>
12
13/* Kioxia is new name of Toshiba memory. */
14#define SPINAND_MFR_TOSHIBA		0x98
15#define TOSH_STATUS_ECC_HAS_BITFLIPS_T	(3 << 4)
16
17static SPINAND_OP_VARIANTS(read_cache_variants,
18		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
19		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
20		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
21		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
22
23static SPINAND_OP_VARIANTS(write_cache_x4_variants,
24		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
25		SPINAND_PROG_LOAD(true, 0, NULL, 0));
26
27static SPINAND_OP_VARIANTS(update_cache_x4_variants,
28		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
29		SPINAND_PROG_LOAD(false, 0, NULL, 0));
30
31/**
32 * Backward compatibility for 1st generation Serial NAND devices
33 * which don't support Quad Program Load operation.
34 */
35static SPINAND_OP_VARIANTS(write_cache_variants,
36		SPINAND_PROG_LOAD(true, 0, NULL, 0));
37
38static SPINAND_OP_VARIANTS(update_cache_variants,
39		SPINAND_PROG_LOAD(false, 0, NULL, 0));
40
41static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section,
42					struct mtd_oob_region *region)
43{
44	if (section > 0)
45		return -ERANGE;
46
47	region->offset = mtd->oobsize / 2;
48	region->length = mtd->oobsize / 2;
49
50	return 0;
51}
52
53static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section,
54					 struct mtd_oob_region *region)
55{
56	if (section > 0)
57		return -ERANGE;
58
59	/* 2 bytes reserved for BBM */
60	region->offset = 2;
61	region->length = (mtd->oobsize / 2) - 2;
62
63	return 0;
64}
65
66static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = {
67	.ecc = tx58cxgxsxraix_ooblayout_ecc,
68	.free = tx58cxgxsxraix_ooblayout_free,
69};
70
71static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand,
72					 u8 status)
73{
74	struct nand_device *nand = spinand_to_nand(spinand);
75	u8 mbf = 0;
76	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf);
77
78	switch (status & STATUS_ECC_MASK) {
79	case STATUS_ECC_NO_BITFLIPS:
80		return 0;
81
82	case STATUS_ECC_UNCOR_ERROR:
83		return -EBADMSG;
84
85	case STATUS_ECC_HAS_BITFLIPS:
86	case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
87		/*
88		 * Let's try to retrieve the real maximum number of bitflips
89		 * in order to avoid forcing the wear-leveling layer to move
90		 * data around if it's not necessary.
91		 */
92		if (spi_mem_exec_op(spinand->spimem, &op))
93			return nanddev_get_ecc_requirements(nand)->strength;
94
95		mbf = *(spinand->scratchbuf) >> 4;
96
97		if (WARN_ON(mbf > nanddev_get_ecc_requirements(nand)->strength || !mbf))
98			return nanddev_get_ecc_requirements(nand)->strength;
99
100		return mbf;
101
102	default:
103		break;
104	}
105
106	return -EINVAL;
107}
108
109static const struct spinand_info toshiba_spinand_table[] = {
110	/* 3.3V 1Gb (1st generation) */
111	SPINAND_INFO("TC58CVG0S3HRAIG",
112		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
113		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
114		     NAND_ECCREQ(8, 512),
115		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
116					      &write_cache_variants,
117					      &update_cache_variants),
118		     0,
119		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
120				     tx58cxgxsxraix_ecc_get_status)),
121	/* 3.3V 2Gb (1st generation) */
122	SPINAND_INFO("TC58CVG1S3HRAIG",
123		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
124		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
125		     NAND_ECCREQ(8, 512),
126		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
127					      &write_cache_variants,
128					      &update_cache_variants),
129		     0,
130		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
131				     tx58cxgxsxraix_ecc_get_status)),
132	/* 3.3V 4Gb (1st generation) */
133	SPINAND_INFO("TC58CVG2S0HRAIG",
134		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
135		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
136		     NAND_ECCREQ(8, 512),
137		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
138					      &write_cache_variants,
139					      &update_cache_variants),
140		     0,
141		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
142				     tx58cxgxsxraix_ecc_get_status)),
143	/* 1.8V 1Gb (1st generation) */
144	SPINAND_INFO("TC58CYG0S3HRAIG",
145		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
146		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
147		     NAND_ECCREQ(8, 512),
148		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
149					      &write_cache_variants,
150					      &update_cache_variants),
151		     0,
152		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
153				     tx58cxgxsxraix_ecc_get_status)),
154	/* 1.8V 2Gb (1st generation) */
155	SPINAND_INFO("TC58CYG1S3HRAIG",
156		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
157		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
158		     NAND_ECCREQ(8, 512),
159		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
160					      &write_cache_variants,
161					      &update_cache_variants),
162		     0,
163		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
164				     tx58cxgxsxraix_ecc_get_status)),
165	/* 1.8V 4Gb (1st generation) */
166	SPINAND_INFO("TC58CYG2S0HRAIG",
167		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
168		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
169		     NAND_ECCREQ(8, 512),
170		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
171					      &write_cache_variants,
172					      &update_cache_variants),
173		     0,
174		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
175				     tx58cxgxsxraix_ecc_get_status)),
176
177	/*
178	 * 2nd generation serial nand has HOLD_D which is equivalent to
179	 * QE_BIT.
180	 */
181	/* 3.3V 1Gb (2nd generation) */
182	SPINAND_INFO("TC58CVG0S3HRAIJ",
183		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
184		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
185		     NAND_ECCREQ(8, 512),
186		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
187					      &write_cache_x4_variants,
188					      &update_cache_x4_variants),
189		     SPINAND_HAS_QE_BIT,
190		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
191				     tx58cxgxsxraix_ecc_get_status)),
192	/* 3.3V 2Gb (2nd generation) */
193	SPINAND_INFO("TC58CVG1S3HRAIJ",
194		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
195		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
196		     NAND_ECCREQ(8, 512),
197		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
198					      &write_cache_x4_variants,
199					      &update_cache_x4_variants),
200		     SPINAND_HAS_QE_BIT,
201		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
202				     tx58cxgxsxraix_ecc_get_status)),
203	/* 3.3V 4Gb (2nd generation) */
204	SPINAND_INFO("TC58CVG2S0HRAIJ",
205		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED),
206		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
207		     NAND_ECCREQ(8, 512),
208		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
209					      &write_cache_x4_variants,
210					      &update_cache_x4_variants),
211		     SPINAND_HAS_QE_BIT,
212		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
213				     tx58cxgxsxraix_ecc_get_status)),
214	/* 3.3V 8Gb (2nd generation) */
215	SPINAND_INFO("TH58CVG3S0HRAIJ",
216		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
217		     NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
218		     NAND_ECCREQ(8, 512),
219		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
220					      &write_cache_x4_variants,
221					      &update_cache_x4_variants),
222		     SPINAND_HAS_QE_BIT,
223		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
224				     tx58cxgxsxraix_ecc_get_status)),
225	/* 1.8V 1Gb (2nd generation) */
226	SPINAND_INFO("TC58CYG0S3HRAIJ",
227		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2),
228		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
229		     NAND_ECCREQ(8, 512),
230		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
231					      &write_cache_x4_variants,
232					      &update_cache_x4_variants),
233		     SPINAND_HAS_QE_BIT,
234		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
235				     tx58cxgxsxraix_ecc_get_status)),
236	/* 1.8V 2Gb (2nd generation) */
237	SPINAND_INFO("TC58CYG1S3HRAIJ",
238		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB),
239		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
240		     NAND_ECCREQ(8, 512),
241		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
242					      &write_cache_x4_variants,
243					      &update_cache_x4_variants),
244		     SPINAND_HAS_QE_BIT,
245		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
246				     tx58cxgxsxraix_ecc_get_status)),
247	/* 1.8V 4Gb (2nd generation) */
248	SPINAND_INFO("TC58CYG2S0HRAIJ",
249		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD),
250		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
251		     NAND_ECCREQ(8, 512),
252		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
253					      &write_cache_x4_variants,
254					      &update_cache_x4_variants),
255		     SPINAND_HAS_QE_BIT,
256		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
257				     tx58cxgxsxraix_ecc_get_status)),
258	/* 1.8V 8Gb (2nd generation) */
259	SPINAND_INFO("TH58CYG3S0HRAIJ",
260		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4),
261		     NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
262		     NAND_ECCREQ(8, 512),
263		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
264					      &write_cache_x4_variants,
265					      &update_cache_x4_variants),
266		     SPINAND_HAS_QE_BIT,
267		     SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout,
268				     tx58cxgxsxraix_ecc_get_status)),
269};
270
271static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
272};
273
274const struct spinand_manufacturer toshiba_spinand_manufacturer = {
275	.id = SPINAND_MFR_TOSHIBA,
276	.name = "Toshiba",
277	.chips = toshiba_spinand_table,
278	.nchips = ARRAY_SIZE(toshiba_spinand_table),
279	.ops = &toshiba_spinand_manuf_ops,
280};
281