1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Author:
4 * Felix Matouschek <felix@matouschek.org>
5 */
6
7#include <linux/bitfield.h>
8#include <linux/device.h>
9#include <linux/kernel.h>
10#include <linux/mtd/spinand.h>
11
12#define SPINAND_MFR_XTX	0x0B
13
14#define XT26G0XA_STATUS_ECC_MASK	GENMASK(5, 2)
15#define XT26G0XA_STATUS_ECC_NO_DETECTED	(0 << 2)
16#define XT26G0XA_STATUS_ECC_8_CORRECTED	(3 << 4)
17#define XT26G0XA_STATUS_ECC_UNCOR_ERROR	(2 << 4)
18
19#define XT26XXXD_STATUS_ECC3_ECC2_MASK	    GENMASK(7, 6)
20#define XT26XXXD_STATUS_ECC_NO_DETECTED     (0)
21#define XT26XXXD_STATUS_ECC_1_7_CORRECTED   (1)
22#define XT26XXXD_STATUS_ECC_8_CORRECTED     (3)
23#define XT26XXXD_STATUS_ECC_UNCOR_ERROR     (2)
24
25static SPINAND_OP_VARIANTS(read_cache_variants,
26		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
27		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
28		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
29		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
30		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
31		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
32
33static SPINAND_OP_VARIANTS(write_cache_variants,
34		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
35		SPINAND_PROG_LOAD(true, 0, NULL, 0));
36
37static SPINAND_OP_VARIANTS(update_cache_variants,
38		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
39		SPINAND_PROG_LOAD(false, 0, NULL, 0));
40
41static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
42				   struct mtd_oob_region *region)
43{
44	if (section)
45		return -ERANGE;
46
47	region->offset = 48;
48	region->length = 16;
49
50	return 0;
51}
52
53static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
54				   struct mtd_oob_region *region)
55{
56	if (section)
57		return -ERANGE;
58
59	region->offset = 1;
60	region->length = 47;
61
62	return 0;
63}
64
65static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
66	.ecc = xt26g0xa_ooblayout_ecc,
67	.free = xt26g0xa_ooblayout_free,
68};
69
70static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
71					 u8 status)
72{
73	status = status & XT26G0XA_STATUS_ECC_MASK;
74
75	switch (status) {
76	case XT26G0XA_STATUS_ECC_NO_DETECTED:
77		return 0;
78	case XT26G0XA_STATUS_ECC_8_CORRECTED:
79		return 8;
80	case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
81		return -EBADMSG;
82	default:
83		break;
84	}
85
86	/* At this point values greater than (2 << 4) are invalid  */
87	if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)
88		return -EINVAL;
89
90	/* (1 << 2) through (7 << 2) are 1-7 corrected errors */
91	return status >> 2;
92}
93
94static int xt26xxxd_ooblayout_ecc(struct mtd_info *mtd, int section,
95				  struct mtd_oob_region *region)
96{
97	if (section)
98		return -ERANGE;
99
100	region->offset = mtd->oobsize / 2;
101	region->length = mtd->oobsize / 2;
102
103	return 0;
104}
105
106static int xt26xxxd_ooblayout_free(struct mtd_info *mtd, int section,
107				   struct mtd_oob_region *region)
108{
109	if (section)
110		return -ERANGE;
111
112	region->offset = 2;
113	region->length = mtd->oobsize / 2 - 2;
114
115	return 0;
116}
117
118static const struct mtd_ooblayout_ops xt26xxxd_ooblayout = {
119	.ecc = xt26xxxd_ooblayout_ecc,
120	.free = xt26xxxd_ooblayout_free,
121};
122
123static int xt26xxxd_ecc_get_status(struct spinand_device *spinand,
124				   u8 status)
125{
126	switch (FIELD_GET(STATUS_ECC_MASK, status)) {
127	case XT26XXXD_STATUS_ECC_NO_DETECTED:
128		return 0;
129	case XT26XXXD_STATUS_ECC_UNCOR_ERROR:
130		return -EBADMSG;
131	case XT26XXXD_STATUS_ECC_1_7_CORRECTED:
132		return 4 + FIELD_GET(XT26XXXD_STATUS_ECC3_ECC2_MASK, status);
133	case XT26XXXD_STATUS_ECC_8_CORRECTED:
134		return 8;
135	default:
136		break;
137	}
138
139	return -EINVAL;
140}
141static const struct spinand_info xtx_spinand_table[] = {
142	SPINAND_INFO("XT26G01A",
143		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),
144		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
145		     NAND_ECCREQ(8, 512),
146		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
147					      &write_cache_variants,
148					      &update_cache_variants),
149		     SPINAND_HAS_QE_BIT,
150		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
151				     xt26g0xa_ecc_get_status)),
152	SPINAND_INFO("XT26G02A",
153		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2),
154		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
155		     NAND_ECCREQ(8, 512),
156		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
157					      &write_cache_variants,
158					      &update_cache_variants),
159		     SPINAND_HAS_QE_BIT,
160		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
161				     xt26g0xa_ecc_get_status)),
162	SPINAND_INFO("XT26G04A",
163		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3),
164		     NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
165		     NAND_ECCREQ(8, 512),
166		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
167					      &write_cache_variants,
168					      &update_cache_variants),
169		     SPINAND_HAS_QE_BIT,
170		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
171				     xt26g0xa_ecc_get_status)),
172	SPINAND_INFO("XT26G01D",
173		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x31),
174		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
175		     NAND_ECCREQ(8, 512),
176		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
177					      &write_cache_variants,
178					      &update_cache_variants),
179		     0,
180		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
181				     xt26xxxd_ecc_get_status)),
182	SPINAND_INFO("XT26G11D",
183		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x34),
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_variants,
188					      &update_cache_variants),
189		     0,
190		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
191				     xt26xxxd_ecc_get_status)),
192	SPINAND_INFO("XT26Q01D",
193		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51),
194		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
195		     NAND_ECCREQ(8, 512),
196		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
197					      &write_cache_variants,
198					      &update_cache_variants),
199		     0,
200		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
201				     xt26xxxd_ecc_get_status)),
202	SPINAND_INFO("XT26G02D",
203		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x32),
204		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
205		     NAND_ECCREQ(8, 512),
206		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
207					      &write_cache_variants,
208					      &update_cache_variants),
209		     0,
210		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
211				     xt26xxxd_ecc_get_status)),
212	SPINAND_INFO("XT26G12D",
213		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x35),
214		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
215		     NAND_ECCREQ(8, 512),
216		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
217					      &write_cache_variants,
218					      &update_cache_variants),
219		     0,
220		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
221				     xt26xxxd_ecc_get_status)),
222	SPINAND_INFO("XT26Q02D",
223		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
224		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
225		     NAND_ECCREQ(8, 512),
226		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
227					      &write_cache_variants,
228					      &update_cache_variants),
229		     0,
230		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
231				     xt26xxxd_ecc_get_status)),
232	SPINAND_INFO("XT26G04D",
233		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x33),
234		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
235		     NAND_ECCREQ(8, 512),
236		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
237					      &write_cache_variants,
238					      &update_cache_variants),
239		     0,
240		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
241				     xt26xxxd_ecc_get_status)),
242	SPINAND_INFO("XT26Q04D",
243		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x53),
244		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
245		     NAND_ECCREQ(8, 512),
246		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
247					      &write_cache_variants,
248					      &update_cache_variants),
249		     0,
250		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
251				     xt26xxxd_ecc_get_status)),
252};
253
254static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
255};
256
257const struct spinand_manufacturer xtx_spinand_manufacturer = {
258	.id = SPINAND_MFR_XTX,
259	.name = "XTX",
260	.chips = xtx_spinand_table,
261	.nchips = ARRAY_SIZE(xtx_spinand_table),
262	.ops = &xtx_spinand_manuf_ops,
263};
264