xref: /OK3568_Linux_fs/kernel/drivers/mtd/nand/spi/dosilicon.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Rockchip Electronics Co., Ltd
4  */
5 
6 #include <linux/device.h>
7 #include <linux/kernel.h>
8 #include <linux/mtd/spinand.h>
9 
10 #define SPINAND_MFR_DOSILICON			0xE5
11 
12 #define DOSICON_STATUS_ECC_MASK			GENMASK(6, 4)
13 #define DOSICON_STATUS_ECC_NO_BITFLIPS		(0 << 4)
14 #define DOSICON_STATUS_ECC_1TO3_BITFLIPS	(1 << 4)
15 #define DOSICON_STATUS_ECC_4TO6_BITFLIPS	(3 << 4)
16 #define DOSICON_STATUS_ECC_7TO8_BITFLIPS	(5 << 4)
17 
18 static SPINAND_OP_VARIANTS(read_cache_variants,
19 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
20 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
21 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
22 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
23 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
24 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
25 
26 static SPINAND_OP_VARIANTS(write_cache_variants,
27 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
28 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
29 
30 static SPINAND_OP_VARIANTS(update_cache_variants,
31 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
32 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
33 
ds35xxga_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)34 static int ds35xxga_ooblayout_ecc(struct mtd_info *mtd, int section,
35 				  struct mtd_oob_region *region)
36 {
37 	if (section > 3)
38 		return -ERANGE;
39 
40 	region->offset = (16 * section) + 8;
41 	region->length = 8;
42 
43 	return 0;
44 }
45 
ds35xxga_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)46 static int ds35xxga_ooblayout_free(struct mtd_info *mtd, int section,
47 				   struct mtd_oob_region *region)
48 {
49 	if (section > 3)
50 		return -ERANGE;
51 
52 	region->offset = (16 * section) + 2;
53 	region->length = 6;
54 
55 	return 0;
56 }
57 
58 static const struct mtd_ooblayout_ops ds35xxga_ooblayout = {
59 	.ecc = ds35xxga_ooblayout_ecc,
60 	.free = ds35xxga_ooblayout_free,
61 };
62 
ds35xxgb_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)63 static int ds35xxgb_ooblayout_ecc(struct mtd_info *mtd, int section,
64 				  struct mtd_oob_region *region)
65 {
66 	if (section)
67 		return -ERANGE;
68 
69 	region->offset = 64;
70 	region->length = 64;
71 
72 	return 0;
73 }
74 
ds35xxgb_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)75 static int ds35xxgb_ooblayout_free(struct mtd_info *mtd, int section,
76 				   struct mtd_oob_region *region)
77 {
78 	if (section)
79 		return -ERANGE;
80 
81 	/* Reserve 1 bytes for the BBM. */
82 	region->offset = 1;
83 	region->length = 63;
84 
85 	return 0;
86 }
87 
88 static const struct mtd_ooblayout_ops ds35xxgb_ooblayout = {
89 	.ecc = ds35xxgb_ooblayout_ecc,
90 	.free = ds35xxgb_ooblayout_free,
91 };
92 
ds35xxgb_ecc_get_status(struct spinand_device * spinand,u8 status)93 static int ds35xxgb_ecc_get_status(struct spinand_device *spinand,
94 				   u8 status)
95 {
96 	switch (status & DOSICON_STATUS_ECC_MASK) {
97 	case STATUS_ECC_NO_BITFLIPS:
98 		return 0;
99 
100 	case STATUS_ECC_UNCOR_ERROR:
101 		return -EBADMSG;
102 
103 	case DOSICON_STATUS_ECC_1TO3_BITFLIPS:
104 		return 3;
105 
106 	case DOSICON_STATUS_ECC_4TO6_BITFLIPS:
107 		return 6;
108 
109 	case DOSICON_STATUS_ECC_7TO8_BITFLIPS:
110 		return 8;
111 
112 	default:
113 		break;
114 	}
115 
116 	return -EINVAL;
117 }
118 
119 static const struct spinand_info dosilicon_spinand_table[] = {
120 	SPINAND_INFO("DS35X1GA",
121 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71),
122 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
123 		     NAND_ECCREQ(4, 512),
124 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
125 					      &write_cache_variants,
126 					      &update_cache_variants),
127 		     SPINAND_HAS_QE_BIT,
128 		     SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
129 	SPINAND_INFO("DS35Q2GA",
130 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72),
131 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
132 		     NAND_ECCREQ(4, 512),
133 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
134 					      &write_cache_variants,
135 					      &update_cache_variants),
136 		     SPINAND_HAS_QE_BIT,
137 		     SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
138 	SPINAND_INFO("DS35M1GA",
139 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x21),
140 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
141 		     NAND_ECCREQ(4, 512),
142 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
143 					      &write_cache_variants,
144 					      &update_cache_variants),
145 		     SPINAND_HAS_QE_BIT,
146 		     SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
147 	SPINAND_INFO("DS35M2GA",
148 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
149 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
150 		     NAND_ECCREQ(4, 512),
151 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
152 					      &write_cache_variants,
153 					      &update_cache_variants),
154 		     SPINAND_HAS_QE_BIT,
155 		     SPINAND_ECCINFO(&ds35xxga_ooblayout, NULL)),
156 	SPINAND_INFO("DS35Q2GB",
157 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF2),
158 		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
159 		     NAND_ECCREQ(8, 512),
160 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
161 					      &write_cache_variants,
162 					      &update_cache_variants),
163 		     SPINAND_HAS_QE_BIT,
164 		     SPINAND_ECCINFO(&ds35xxgb_ooblayout,
165 				     ds35xxgb_ecc_get_status)),
166 	SPINAND_INFO("DS35M1GB",
167 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1),
168 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 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 		     SPINAND_HAS_QE_BIT,
174 		     SPINAND_ECCINFO(&ds35xxgb_ooblayout,
175 				     ds35xxgb_ecc_get_status)),
176 	SPINAND_INFO("DS35Q1GB",
177 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF1),
178 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
179 		     NAND_ECCREQ(8, 512),
180 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
181 					      &write_cache_variants,
182 					      &update_cache_variants),
183 		     SPINAND_HAS_QE_BIT,
184 		     SPINAND_ECCINFO(&ds35xxgb_ooblayout,
185 				     ds35xxgb_ecc_get_status)),
186 	SPINAND_INFO("DS35Q4GM",
187 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF4),
188 		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1),
189 		     NAND_ECCREQ(8, 512),
190 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
191 					      &write_cache_variants,
192 					      &update_cache_variants),
193 		     SPINAND_HAS_QE_BIT,
194 		     SPINAND_ECCINFO(&ds35xxgb_ooblayout,
195 				     ds35xxgb_ecc_get_status)),
196 	SPINAND_INFO("DS35Q12B",
197 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xF5),
198 		     NAND_MEMORG(1, 2048, 128, 64, 512, 10, 1, 1, 1),
199 		     NAND_ECCREQ(8, 512),
200 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
201 					      &write_cache_variants,
202 					      &update_cache_variants),
203 		     SPINAND_HAS_QE_BIT,
204 		     SPINAND_ECCINFO(&ds35xxgb_ooblayout,
205 				     ds35xxgb_ecc_get_status)),
206 	SPINAND_INFO("DS35M12B",
207 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA5),
208 		     NAND_MEMORG(1, 2048, 128, 64, 512, 10, 1, 1, 1),
209 		     NAND_ECCREQ(8, 512),
210 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
211 					      &write_cache_variants,
212 					      &update_cache_variants),
213 		     SPINAND_HAS_QE_BIT,
214 		     SPINAND_ECCINFO(&ds35xxgb_ooblayout,
215 				     ds35xxgb_ecc_get_status)),
216 };
217 
218 static const struct spinand_manufacturer_ops dosilicon_spinand_manuf_ops = {
219 };
220 
221 const struct spinand_manufacturer dosilicon_spinand_manufacturer = {
222 	.id = SPINAND_MFR_DOSILICON,
223 	.name = "dosilicon",
224 	.chips = dosilicon_spinand_table,
225 	.nchips = ARRAY_SIZE(dosilicon_spinand_table),
226 	.ops = &dosilicon_spinand_manuf_ops,
227 };
228