1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2018 Stefan Roese <sr@denx.de>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Derived from drivers/mtd/nand/spi/micron.c
6*4882a593Smuzhiyun * Copyright (c) 2016-2017 Micron Technology, Inc.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #ifndef __UBOOT__
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #endif
13*4882a593Smuzhiyun #include <linux/mtd/spinand.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #define SPINAND_MFR_GIGADEVICE 0xC8
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
18*4882a593Smuzhiyun #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS (1 << 4)
21*4882a593Smuzhiyun #define GD5FXGQ5XE_STATUS_ECC_4_BITFLIPS (3 << 4)
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define GD5FXGQXXEXXG_REG_STATUS2 0xf0
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4)
26*4882a593Smuzhiyun #define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
27*4882a593Smuzhiyun #define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4)
28*4882a593Smuzhiyun #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static SPINAND_OP_VARIANTS(read_cache_variants,
31*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
32*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
33*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
34*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
35*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
36*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun static SPINAND_OP_VARIANTS(read_cache_variants_f,
39*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
40*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
41*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
42*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
43*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
44*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static SPINAND_OP_VARIANTS(read_cache_variants_1gq5,
47*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
48*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
49*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
50*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
51*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
52*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static SPINAND_OP_VARIANTS(read_cache_variants_2gq5,
55*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
56*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
57*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
58*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
59*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
60*4882a593Smuzhiyun SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static SPINAND_OP_VARIANTS(write_cache_variants,
63*4882a593Smuzhiyun SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
64*4882a593Smuzhiyun SPINAND_PROG_LOAD(true, 0, NULL, 0));
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static SPINAND_OP_VARIANTS(update_cache_variants,
67*4882a593Smuzhiyun SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
68*4882a593Smuzhiyun SPINAND_PROG_LOAD(false, 0, NULL, 0));
69*4882a593Smuzhiyun
gd5fxgq4xa_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)70*4882a593Smuzhiyun static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
71*4882a593Smuzhiyun struct mtd_oob_region *region)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun if (section > 3)
74*4882a593Smuzhiyun return -ERANGE;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun region->offset = (16 * section) + 8;
77*4882a593Smuzhiyun region->length = 8;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun return 0;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
gd5fxgq4xa_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)82*4882a593Smuzhiyun static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
83*4882a593Smuzhiyun struct mtd_oob_region *region)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun if (section > 3)
86*4882a593Smuzhiyun return -ERANGE;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun if (section) {
89*4882a593Smuzhiyun region->offset = 16 * section;
90*4882a593Smuzhiyun region->length = 8;
91*4882a593Smuzhiyun } else {
92*4882a593Smuzhiyun /* section 0 has one byte reserved for bad block mark */
93*4882a593Smuzhiyun region->offset = 1;
94*4882a593Smuzhiyun region->length = 7;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun return 0;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
100*4882a593Smuzhiyun .ecc = gd5fxgq4xa_ooblayout_ecc,
101*4882a593Smuzhiyun .rfree = gd5fxgq4xa_ooblayout_free,
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun
gd5fxgq4xa_ecc_get_status(struct spinand_device * spinand,u8 status)104*4882a593Smuzhiyun static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
105*4882a593Smuzhiyun u8 status)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun switch (status & STATUS_ECC_MASK) {
108*4882a593Smuzhiyun case STATUS_ECC_NO_BITFLIPS:
109*4882a593Smuzhiyun return 0;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
112*4882a593Smuzhiyun /* 1-7 bits are flipped. return the maximum. */
113*4882a593Smuzhiyun return 7;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
116*4882a593Smuzhiyun return 8;
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun case STATUS_ECC_UNCOR_ERROR:
119*4882a593Smuzhiyun return -EBADMSG;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun default:
122*4882a593Smuzhiyun break;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun return -EINVAL;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)128*4882a593Smuzhiyun static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
129*4882a593Smuzhiyun struct mtd_oob_region *region)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun if (section)
132*4882a593Smuzhiyun return -ERANGE;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun region->offset = 64;
135*4882a593Smuzhiyun region->length = 64;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun return 0;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
gd5fxgqx_variant2_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)140*4882a593Smuzhiyun static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
141*4882a593Smuzhiyun struct mtd_oob_region *region)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun if (section)
144*4882a593Smuzhiyun return -ERANGE;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* Reserve 1 bytes for the BBM. */
147*4882a593Smuzhiyun region->offset = 1;
148*4882a593Smuzhiyun region->length = 63;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return 0;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /* Valid for Q4/Q5 and Q6 (untested) devices */
154*4882a593Smuzhiyun static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
155*4882a593Smuzhiyun .ecc = gd5fxgqx_variant2_ooblayout_ecc,
156*4882a593Smuzhiyun .rfree = gd5fxgqx_variant2_ooblayout_free,
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun
gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)159*4882a593Smuzhiyun static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
160*4882a593Smuzhiyun struct mtd_oob_region *oobregion)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun if (section)
163*4882a593Smuzhiyun return -ERANGE;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun oobregion->offset = 128;
166*4882a593Smuzhiyun oobregion->length = 128;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun return 0;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
gd5fxgq4xc_ooblayout_256_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)171*4882a593Smuzhiyun static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
172*4882a593Smuzhiyun struct mtd_oob_region *oobregion)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun if (section)
175*4882a593Smuzhiyun return -ERANGE;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun oobregion->offset = 1;
178*4882a593Smuzhiyun oobregion->length = 127;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return 0;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
184*4882a593Smuzhiyun .ecc = gd5fxgq4xc_ooblayout_256_ecc,
185*4882a593Smuzhiyun .rfree = gd5fxgq4xc_ooblayout_256_free,
186*4882a593Smuzhiyun };
187*4882a593Smuzhiyun
gd5fxgqx_variant3_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)188*4882a593Smuzhiyun static int gd5fxgqx_variant3_ooblayout_ecc(struct mtd_info *mtd, int section,
189*4882a593Smuzhiyun struct mtd_oob_region *region)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun return -ERANGE;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
gd5fxgqx_variant3_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)194*4882a593Smuzhiyun static int gd5fxgqx_variant3_ooblayout_free(struct mtd_info *mtd, int section,
195*4882a593Smuzhiyun struct mtd_oob_region *region)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun if (section)
198*4882a593Smuzhiyun return -ERANGE;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* Reserve 1 bytes for the BBM. */
201*4882a593Smuzhiyun region->offset = 1;
202*4882a593Smuzhiyun region->length = 63;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun return 0;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun static const struct mtd_ooblayout_ops gd5fxgqx_variant3_ooblayout = {
208*4882a593Smuzhiyun .ecc = gd5fxgqx_variant3_ooblayout_ecc,
209*4882a593Smuzhiyun .rfree = gd5fxgqx_variant3_ooblayout_free,
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun
gd5fxgq4uexxg_ecc_get_status(struct spinand_device * spinand,u8 status)212*4882a593Smuzhiyun static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
213*4882a593Smuzhiyun u8 status)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun u8 status2;
216*4882a593Smuzhiyun struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
217*4882a593Smuzhiyun &status2);
218*4882a593Smuzhiyun int ret;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun switch (status & STATUS_ECC_MASK) {
221*4882a593Smuzhiyun case STATUS_ECC_NO_BITFLIPS:
222*4882a593Smuzhiyun return 0;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
225*4882a593Smuzhiyun /*
226*4882a593Smuzhiyun * Read status2 register to determine a more fine grained
227*4882a593Smuzhiyun * bit error status
228*4882a593Smuzhiyun */
229*4882a593Smuzhiyun ret = spi_mem_exec_op(spinand->slave, &op);
230*4882a593Smuzhiyun if (ret)
231*4882a593Smuzhiyun return ret;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /*
234*4882a593Smuzhiyun * 4 ... 7 bits are flipped (1..4 can't be detected, so
235*4882a593Smuzhiyun * report the maximum of 4 in this case
236*4882a593Smuzhiyun */
237*4882a593Smuzhiyun /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
238*4882a593Smuzhiyun return ((status & STATUS_ECC_MASK) >> 2) |
239*4882a593Smuzhiyun ((status2 & STATUS_ECC_MASK) >> 4);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
242*4882a593Smuzhiyun return 8;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun case STATUS_ECC_UNCOR_ERROR:
245*4882a593Smuzhiyun return -EBADMSG;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun default:
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return -EINVAL;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
gd5fxgq5xexxg_ecc_get_status(struct spinand_device * spinand,u8 status)254*4882a593Smuzhiyun static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
255*4882a593Smuzhiyun u8 status)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun u8 status2;
258*4882a593Smuzhiyun struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
259*4882a593Smuzhiyun &status2);
260*4882a593Smuzhiyun int ret;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun switch (status & STATUS_ECC_MASK) {
263*4882a593Smuzhiyun case STATUS_ECC_NO_BITFLIPS:
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun case GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS:
267*4882a593Smuzhiyun /*
268*4882a593Smuzhiyun * Read status2 register to determine a more fine grained
269*4882a593Smuzhiyun * bit error status
270*4882a593Smuzhiyun */
271*4882a593Smuzhiyun ret = spi_mem_exec_op(spinand->slave, &op);
272*4882a593Smuzhiyun if (ret)
273*4882a593Smuzhiyun return ret;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /*
276*4882a593Smuzhiyun * 1 ... 4 bits are flipped (and corrected)
277*4882a593Smuzhiyun */
278*4882a593Smuzhiyun /* bits sorted this way (1...0): ECCSE1, ECCSE0 */
279*4882a593Smuzhiyun return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun case STATUS_ECC_UNCOR_ERROR:
282*4882a593Smuzhiyun return -EBADMSG;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun default:
285*4882a593Smuzhiyun break;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun return -EINVAL;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
gd5fxgq4ufxxg_ecc_get_status(struct spinand_device * spinand,u8 status)291*4882a593Smuzhiyun static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
292*4882a593Smuzhiyun u8 status)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
295*4882a593Smuzhiyun case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
296*4882a593Smuzhiyun return 0;
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
299*4882a593Smuzhiyun return 3;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
302*4882a593Smuzhiyun return -EBADMSG;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
305*4882a593Smuzhiyun return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun return -EINVAL;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun static const struct spinand_info gigadevice_spinand_table[] = {
312*4882a593Smuzhiyun SPINAND_INFO("GD5F1GQ4xA",
313*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
314*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
315*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
316*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
317*4882a593Smuzhiyun &write_cache_variants,
318*4882a593Smuzhiyun &update_cache_variants),
319*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
320*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
321*4882a593Smuzhiyun gd5fxgq4xa_ecc_get_status)),
322*4882a593Smuzhiyun SPINAND_INFO("GD5F2GQ4xA",
323*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
324*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
325*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
326*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
327*4882a593Smuzhiyun &write_cache_variants,
328*4882a593Smuzhiyun &update_cache_variants),
329*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
330*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
331*4882a593Smuzhiyun gd5fxgq4xa_ecc_get_status)),
332*4882a593Smuzhiyun SPINAND_INFO("GD5F4GQ4xA",
333*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
334*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
335*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
336*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
337*4882a593Smuzhiyun &write_cache_variants,
338*4882a593Smuzhiyun &update_cache_variants),
339*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
340*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
341*4882a593Smuzhiyun gd5fxgq4xa_ecc_get_status)),
342*4882a593Smuzhiyun SPINAND_INFO("GD5F4GQ4RC",
343*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
344*4882a593Smuzhiyun NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
345*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
346*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
347*4882a593Smuzhiyun &write_cache_variants,
348*4882a593Smuzhiyun &update_cache_variants),
349*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
350*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
351*4882a593Smuzhiyun gd5fxgq4ufxxg_ecc_get_status)),
352*4882a593Smuzhiyun SPINAND_INFO("GD5F4GQ4UC",
353*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
354*4882a593Smuzhiyun NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
355*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
356*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
357*4882a593Smuzhiyun &write_cache_variants,
358*4882a593Smuzhiyun &update_cache_variants),
359*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
360*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
361*4882a593Smuzhiyun gd5fxgq4ufxxg_ecc_get_status)),
362*4882a593Smuzhiyun SPINAND_INFO("GD5F1GQ4UExxG",
363*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
364*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
365*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
366*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
367*4882a593Smuzhiyun &write_cache_variants,
368*4882a593Smuzhiyun &update_cache_variants),
369*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
370*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
371*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
372*4882a593Smuzhiyun SPINAND_INFO("GD5F1GQ4RExxG",
373*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc1),
374*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
375*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
376*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
377*4882a593Smuzhiyun &write_cache_variants,
378*4882a593Smuzhiyun &update_cache_variants),
379*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
380*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
381*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
382*4882a593Smuzhiyun SPINAND_INFO("GD5F2GQ4UExxG",
383*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd2),
384*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
385*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
386*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
387*4882a593Smuzhiyun &write_cache_variants,
388*4882a593Smuzhiyun &update_cache_variants),
389*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
390*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
391*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
392*4882a593Smuzhiyun SPINAND_INFO("GD5F2GQ4RExxG",
393*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc2),
394*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
395*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
396*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
397*4882a593Smuzhiyun &write_cache_variants,
398*4882a593Smuzhiyun &update_cache_variants),
399*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
400*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
401*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
402*4882a593Smuzhiyun SPINAND_INFO("GD5F1GQ4UFxxG",
403*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
404*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
405*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
406*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
407*4882a593Smuzhiyun &write_cache_variants,
408*4882a593Smuzhiyun &update_cache_variants),
409*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
410*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
411*4882a593Smuzhiyun gd5fxgq4ufxxg_ecc_get_status)),
412*4882a593Smuzhiyun SPINAND_INFO("GD5F1GQ5UExxG",
413*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
414*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
415*4882a593Smuzhiyun NAND_ECCREQ(4, 512),
416*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
417*4882a593Smuzhiyun &write_cache_variants,
418*4882a593Smuzhiyun &update_cache_variants),
419*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
420*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
421*4882a593Smuzhiyun gd5fxgq5xexxg_ecc_get_status)),
422*4882a593Smuzhiyun SPINAND_INFO("GD5F1GQ5RExxG",
423*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41),
424*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
425*4882a593Smuzhiyun NAND_ECCREQ(4, 512),
426*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
427*4882a593Smuzhiyun &write_cache_variants,
428*4882a593Smuzhiyun &update_cache_variants),
429*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
430*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
431*4882a593Smuzhiyun gd5fxgq5xexxg_ecc_get_status)),
432*4882a593Smuzhiyun SPINAND_INFO("GD5F2GQ5UExxG",
433*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52),
434*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
435*4882a593Smuzhiyun NAND_ECCREQ(4, 512),
436*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
437*4882a593Smuzhiyun &write_cache_variants,
438*4882a593Smuzhiyun &update_cache_variants),
439*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
440*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
441*4882a593Smuzhiyun gd5fxgq5xexxg_ecc_get_status)),
442*4882a593Smuzhiyun SPINAND_INFO("GD5F2GQ5RExxG",
443*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x42),
444*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
445*4882a593Smuzhiyun NAND_ECCREQ(4, 512),
446*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
447*4882a593Smuzhiyun &write_cache_variants,
448*4882a593Smuzhiyun &update_cache_variants),
449*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
450*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
451*4882a593Smuzhiyun gd5fxgq5xexxg_ecc_get_status)),
452*4882a593Smuzhiyun SPINAND_INFO("GD5F4GQ6UExxG",
453*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x55),
454*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 2, 1),
455*4882a593Smuzhiyun NAND_ECCREQ(4, 512),
456*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
457*4882a593Smuzhiyun &write_cache_variants,
458*4882a593Smuzhiyun &update_cache_variants),
459*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
460*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
461*4882a593Smuzhiyun gd5fxgq5xexxg_ecc_get_status)),
462*4882a593Smuzhiyun SPINAND_INFO("GD5F4GQ6RExxG",
463*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x45),
464*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 2, 1),
465*4882a593Smuzhiyun NAND_ECCREQ(4, 512),
466*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
467*4882a593Smuzhiyun &write_cache_variants,
468*4882a593Smuzhiyun &update_cache_variants),
469*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
470*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
471*4882a593Smuzhiyun gd5fxgq5xexxg_ecc_get_status)),
472*4882a593Smuzhiyun SPINAND_INFO("GD5F1GM7UExxG",
473*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91),
474*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
475*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
476*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
477*4882a593Smuzhiyun &write_cache_variants,
478*4882a593Smuzhiyun &update_cache_variants),
479*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
480*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
481*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
482*4882a593Smuzhiyun SPINAND_INFO("GD5F1GM7RExxG",
483*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81),
484*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
485*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
486*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
487*4882a593Smuzhiyun &write_cache_variants,
488*4882a593Smuzhiyun &update_cache_variants),
489*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
490*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
491*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
492*4882a593Smuzhiyun SPINAND_INFO("GD5F2GM7UExxG",
493*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
494*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
495*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
496*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
497*4882a593Smuzhiyun &write_cache_variants,
498*4882a593Smuzhiyun &update_cache_variants),
499*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
500*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
501*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
502*4882a593Smuzhiyun SPINAND_INFO("GD5F2GM7RExxG",
503*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x82),
504*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
505*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
506*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
507*4882a593Smuzhiyun &write_cache_variants,
508*4882a593Smuzhiyun &update_cache_variants),
509*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
510*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
511*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
512*4882a593Smuzhiyun SPINAND_INFO("GD5F4GM8UExxG",
513*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x95),
514*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
515*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
516*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
517*4882a593Smuzhiyun &write_cache_variants,
518*4882a593Smuzhiyun &update_cache_variants),
519*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
520*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
521*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
522*4882a593Smuzhiyun SPINAND_INFO("GD5F4GM8RExxG",
523*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x85),
524*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 128, 64, 4096, 1, 1, 1),
525*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
526*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
527*4882a593Smuzhiyun &write_cache_variants,
528*4882a593Smuzhiyun &update_cache_variants),
529*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
530*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
531*4882a593Smuzhiyun gd5fxgq4uexxg_ecc_get_status)),
532*4882a593Smuzhiyun SPINAND_INFO("GD5F1GQ4UExxH",
533*4882a593Smuzhiyun SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd9),
534*4882a593Smuzhiyun NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
535*4882a593Smuzhiyun NAND_ECCREQ(8, 512),
536*4882a593Smuzhiyun SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
537*4882a593Smuzhiyun &write_cache_variants,
538*4882a593Smuzhiyun &update_cache_variants),
539*4882a593Smuzhiyun SPINAND_HAS_QE_BIT,
540*4882a593Smuzhiyun SPINAND_ECCINFO(&gd5fxgqx_variant3_ooblayout,
541*4882a593Smuzhiyun gd5fxgq4xa_ecc_get_status)),
542*4882a593Smuzhiyun };
543*4882a593Smuzhiyun
gigadevice_spinand_set_ds(struct spinand_device * spinand,u8 ds_io)544*4882a593Smuzhiyun static int gigadevice_spinand_set_ds(struct spinand_device *spinand, u8 ds_io)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun struct spi_mem_op op = SPINAND_SET_FEATURE_OP(0xD0,
547*4882a593Smuzhiyun spinand->scratchbuf);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun *spinand->scratchbuf = (ds_io & 0x3) << 5;
550*4882a593Smuzhiyun return spi_mem_exec_op(spinand->slave, &op);
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun
gigadevice_spinand_init(struct spinand_device * spinand)553*4882a593Smuzhiyun static int gigadevice_spinand_init(struct spinand_device *spinand)
554*4882a593Smuzhiyun {
555*4882a593Smuzhiyun /* GD5F1GQ5UExxG */
556*4882a593Smuzhiyun if (spinand->id.data[1] == 0x51)
557*4882a593Smuzhiyun gigadevice_spinand_set_ds(spinand, 3);
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun return 0;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
563*4882a593Smuzhiyun .init = gigadevice_spinand_init,
564*4882a593Smuzhiyun };
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
567*4882a593Smuzhiyun .id = SPINAND_MFR_GIGADEVICE,
568*4882a593Smuzhiyun .name = "GigaDevice",
569*4882a593Smuzhiyun .chips = gigadevice_spinand_table,
570*4882a593Smuzhiyun .nchips = ARRAY_SIZE(gigadevice_spinand_table),
571*4882a593Smuzhiyun .ops = &gigadevice_spinand_manuf_ops,
572*4882a593Smuzhiyun };
573