File Index
Files and directories
Sign in
FILE

xtx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mtd/nand/spi/xtx.c C
  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_1S_4S_4S_OP(0, 1, NULL, 0, 0),
 27		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
 28		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
 29		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
 30		SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
 31		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0));
 32
 33static SPINAND_OP_VARIANTS(write_cache_variants,
 34		SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
 35		SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
 36
 37static SPINAND_OP_VARIANTS(update_cache_variants,
 38		SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
 39		SPINAND_PROG_LOAD_1S_1S_1S_OP(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};
~/ Read-only file preview.