xref: /linux/drivers/mtd/nand/spi/xtx.c (revision f4c5c7f9d2e5ab005d57826b740b694b042a737c)
1*f4c5c7f9SFelix Matouschek // SPDX-License-Identifier: GPL-2.0
2*f4c5c7f9SFelix Matouschek /*
3*f4c5c7f9SFelix Matouschek  * Author:
4*f4c5c7f9SFelix Matouschek  * Felix Matouschek <felix@matouschek.org>
5*f4c5c7f9SFelix Matouschek  */
6*f4c5c7f9SFelix Matouschek 
7*f4c5c7f9SFelix Matouschek #include <linux/device.h>
8*f4c5c7f9SFelix Matouschek #include <linux/kernel.h>
9*f4c5c7f9SFelix Matouschek #include <linux/mtd/spinand.h>
10*f4c5c7f9SFelix Matouschek 
11*f4c5c7f9SFelix Matouschek #define SPINAND_MFR_XTX	0x0B
12*f4c5c7f9SFelix Matouschek 
13*f4c5c7f9SFelix Matouschek #define XT26G0XA_STATUS_ECC_MASK	GENMASK(5, 2)
14*f4c5c7f9SFelix Matouschek #define XT26G0XA_STATUS_ECC_NO_DETECTED	(0 << 2)
15*f4c5c7f9SFelix Matouschek #define XT26G0XA_STATUS_ECC_8_CORRECTED	(3 << 4)
16*f4c5c7f9SFelix Matouschek #define XT26G0XA_STATUS_ECC_UNCOR_ERROR	(2 << 4)
17*f4c5c7f9SFelix Matouschek 
18*f4c5c7f9SFelix Matouschek static SPINAND_OP_VARIANTS(read_cache_variants,
19*f4c5c7f9SFelix Matouschek 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
20*f4c5c7f9SFelix Matouschek 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
21*f4c5c7f9SFelix Matouschek 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
22*f4c5c7f9SFelix Matouschek 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
23*f4c5c7f9SFelix Matouschek 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
24*f4c5c7f9SFelix Matouschek 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
25*f4c5c7f9SFelix Matouschek 
26*f4c5c7f9SFelix Matouschek static SPINAND_OP_VARIANTS(write_cache_variants,
27*f4c5c7f9SFelix Matouschek 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
28*f4c5c7f9SFelix Matouschek 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
29*f4c5c7f9SFelix Matouschek 
30*f4c5c7f9SFelix Matouschek static SPINAND_OP_VARIANTS(update_cache_variants,
31*f4c5c7f9SFelix Matouschek 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
32*f4c5c7f9SFelix Matouschek 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
33*f4c5c7f9SFelix Matouschek 
34*f4c5c7f9SFelix Matouschek static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
35*f4c5c7f9SFelix Matouschek 				   struct mtd_oob_region *region)
36*f4c5c7f9SFelix Matouschek {
37*f4c5c7f9SFelix Matouschek 	if (section)
38*f4c5c7f9SFelix Matouschek 		return -ERANGE;
39*f4c5c7f9SFelix Matouschek 
40*f4c5c7f9SFelix Matouschek 	region->offset = 48;
41*f4c5c7f9SFelix Matouschek 	region->length = 16;
42*f4c5c7f9SFelix Matouschek 
43*f4c5c7f9SFelix Matouschek 	return 0;
44*f4c5c7f9SFelix Matouschek }
45*f4c5c7f9SFelix Matouschek 
46*f4c5c7f9SFelix Matouschek static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
47*f4c5c7f9SFelix Matouschek 				   struct mtd_oob_region *region)
48*f4c5c7f9SFelix Matouschek {
49*f4c5c7f9SFelix Matouschek 	if (section)
50*f4c5c7f9SFelix Matouschek 		return -ERANGE;
51*f4c5c7f9SFelix Matouschek 
52*f4c5c7f9SFelix Matouschek 	region->offset = 1;
53*f4c5c7f9SFelix Matouschek 	region->length = 47;
54*f4c5c7f9SFelix Matouschek 
55*f4c5c7f9SFelix Matouschek 	return 0;
56*f4c5c7f9SFelix Matouschek }
57*f4c5c7f9SFelix Matouschek 
58*f4c5c7f9SFelix Matouschek static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
59*f4c5c7f9SFelix Matouschek 	.ecc = xt26g0xa_ooblayout_ecc,
60*f4c5c7f9SFelix Matouschek 	.free = xt26g0xa_ooblayout_free,
61*f4c5c7f9SFelix Matouschek };
62*f4c5c7f9SFelix Matouschek 
63*f4c5c7f9SFelix Matouschek static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
64*f4c5c7f9SFelix Matouschek 					 u8 status)
65*f4c5c7f9SFelix Matouschek {
66*f4c5c7f9SFelix Matouschek 	status = status & XT26G0XA_STATUS_ECC_MASK;
67*f4c5c7f9SFelix Matouschek 
68*f4c5c7f9SFelix Matouschek 	switch (status) {
69*f4c5c7f9SFelix Matouschek 	case XT26G0XA_STATUS_ECC_NO_DETECTED:
70*f4c5c7f9SFelix Matouschek 		return 0;
71*f4c5c7f9SFelix Matouschek 	case XT26G0XA_STATUS_ECC_8_CORRECTED:
72*f4c5c7f9SFelix Matouschek 		return 8;
73*f4c5c7f9SFelix Matouschek 	case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
74*f4c5c7f9SFelix Matouschek 		return -EBADMSG;
75*f4c5c7f9SFelix Matouschek 	default:
76*f4c5c7f9SFelix Matouschek 		break;
77*f4c5c7f9SFelix Matouschek 	}
78*f4c5c7f9SFelix Matouschek 
79*f4c5c7f9SFelix Matouschek 	/* At this point values greater than (2 << 4) are invalid  */
80*f4c5c7f9SFelix Matouschek 	if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)
81*f4c5c7f9SFelix Matouschek 		return -EINVAL;
82*f4c5c7f9SFelix Matouschek 
83*f4c5c7f9SFelix Matouschek 	/* (1 << 2) through (7 << 2) are 1-7 corrected errors */
84*f4c5c7f9SFelix Matouschek 	return status >> 2;
85*f4c5c7f9SFelix Matouschek }
86*f4c5c7f9SFelix Matouschek 
87*f4c5c7f9SFelix Matouschek static const struct spinand_info xtx_spinand_table[] = {
88*f4c5c7f9SFelix Matouschek 	SPINAND_INFO("XT26G01A",
89*f4c5c7f9SFelix Matouschek 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE1),
90*f4c5c7f9SFelix Matouschek 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
91*f4c5c7f9SFelix Matouschek 		     NAND_ECCREQ(8, 512),
92*f4c5c7f9SFelix Matouschek 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
93*f4c5c7f9SFelix Matouschek 					      &write_cache_variants,
94*f4c5c7f9SFelix Matouschek 					      &update_cache_variants),
95*f4c5c7f9SFelix Matouschek 		     SPINAND_HAS_QE_BIT,
96*f4c5c7f9SFelix Matouschek 		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
97*f4c5c7f9SFelix Matouschek 				     xt26g0xa_ecc_get_status)),
98*f4c5c7f9SFelix Matouschek 	SPINAND_INFO("XT26G02A",
99*f4c5c7f9SFelix Matouschek 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE2),
100*f4c5c7f9SFelix Matouschek 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
101*f4c5c7f9SFelix Matouschek 		     NAND_ECCREQ(8, 512),
102*f4c5c7f9SFelix Matouschek 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
103*f4c5c7f9SFelix Matouschek 					      &write_cache_variants,
104*f4c5c7f9SFelix Matouschek 					      &update_cache_variants),
105*f4c5c7f9SFelix Matouschek 		     SPINAND_HAS_QE_BIT,
106*f4c5c7f9SFelix Matouschek 		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
107*f4c5c7f9SFelix Matouschek 				     xt26g0xa_ecc_get_status)),
108*f4c5c7f9SFelix Matouschek 	SPINAND_INFO("XT26G04A",
109*f4c5c7f9SFelix Matouschek 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xE3),
110*f4c5c7f9SFelix Matouschek 		     NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
111*f4c5c7f9SFelix Matouschek 		     NAND_ECCREQ(8, 512),
112*f4c5c7f9SFelix Matouschek 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
113*f4c5c7f9SFelix Matouschek 					      &write_cache_variants,
114*f4c5c7f9SFelix Matouschek 					      &update_cache_variants),
115*f4c5c7f9SFelix Matouschek 		     SPINAND_HAS_QE_BIT,
116*f4c5c7f9SFelix Matouschek 		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
117*f4c5c7f9SFelix Matouschek 				     xt26g0xa_ecc_get_status)),
118*f4c5c7f9SFelix Matouschek };
119*f4c5c7f9SFelix Matouschek 
120*f4c5c7f9SFelix Matouschek static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
121*f4c5c7f9SFelix Matouschek };
122*f4c5c7f9SFelix Matouschek 
123*f4c5c7f9SFelix Matouschek const struct spinand_manufacturer xtx_spinand_manufacturer = {
124*f4c5c7f9SFelix Matouschek 	.id = SPINAND_MFR_XTX,
125*f4c5c7f9SFelix Matouschek 	.name = "XTX",
126*f4c5c7f9SFelix Matouschek 	.chips = xtx_spinand_table,
127*f4c5c7f9SFelix Matouschek 	.nchips = ARRAY_SIZE(xtx_spinand_table),
128*f4c5c7f9SFelix Matouschek 	.ops = &xtx_spinand_manuf_ops,
129*f4c5c7f9SFelix Matouschek };
130