1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2020 Grandstream Networks, Inc
4 *
5 * Authors:
6 * Carl <xjxia@grandstream.cn>
7 */
8
9 #ifndef __UBOOT__
10 #include <linux/device.h>
11 #include <linux/kernel.h>
12 #endif
13 #include <linux/mtd/spinand.h>
14
15 #define SPINAND_MFR_FORESEE 0xCD
16
17 static SPINAND_OP_VARIANTS(read_cache_variants,
18 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
19 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
20 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
21 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
22 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
23 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
24
25 static SPINAND_OP_VARIANTS(write_cache_variants,
26 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
27 SPINAND_PROG_LOAD(true, 0, NULL, 0));
28
29 static SPINAND_OP_VARIANTS(update_cache_variants,
30 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
31 SPINAND_PROG_LOAD(true, 0, NULL, 0));
32
fsxxndxxg_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)33 static int fsxxndxxg_ooblayout_ecc(struct mtd_info *mtd, int section,
34 struct mtd_oob_region *region)
35 {
36 return -ERANGE;
37 }
38
fsxxndxxg_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)39 static int fsxxndxxg_ooblayout_free(struct mtd_info *mtd, int section,
40 struct mtd_oob_region *region)
41 {
42 if (section)
43 return -ERANGE;
44
45 region->offset = 2;
46 region->length = mtd->oobsize - 2;
47
48 return 0;
49 }
50
51 static const struct mtd_ooblayout_ops fsxxndxxg_ooblayout = {
52 .ecc = fsxxndxxg_ooblayout_ecc,
53 .rfree = fsxxndxxg_ooblayout_free,
54 };
55
f35sqb00xg_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)56 static int f35sqb00xg_ooblayout_ecc(struct mtd_info *mtd, int section,
57 struct mtd_oob_region *region)
58 {
59 if (section > 0)
60 return -ERANGE;
61
62 region->offset = mtd->oobsize / 2;
63 region->length = mtd->oobsize / 2;
64
65 return 0;
66 }
67
f35sqb00xg_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)68 static int f35sqb00xg_ooblayout_free(struct mtd_info *mtd, int section,
69 struct mtd_oob_region *region)
70 {
71 if (section)
72 return -ERANGE;
73
74 /* 2 bytes reserved for BBM */
75 region->offset = 2;
76 region->length = mtd->oobsize / 2 - 2;
77
78 return 0;
79 }
80
81 static const struct mtd_ooblayout_ops f35sqb00xg_ooblayout = {
82 .ecc = f35sqb00xg_ooblayout_ecc,
83 .rfree = f35sqb00xg_ooblayout_free,
84 };
85
86 /*
87 * ecc bits: 0xC0[4,6]
88 * [0b000], No bit errors were detected;
89 * [0b001, 0b101], 3~7 Bit errors were detected and corrected. Not
90 * reach Flipping Bits;
91 * [0b110], Bit error count equals the bit flip detection threshold
92 * [0b111], Bit errors greater than ECC capability(8 bits) and not corrected;
93 */
f35sqb00xg_ecc_get_status(struct spinand_device * spinand,u8 status)94 static int f35sqb00xg_ecc_get_status(struct spinand_device *spinand, u8 status)
95 {
96 struct nand_device *nand = spinand_to_nand(spinand);
97 u8 eccsr = (status & GENMASK(6, 4)) >> 4;
98
99 if (eccsr < 6)
100 return 0;
101 else if (eccsr == 6)
102 return nand->eccreq.strength;
103 else
104 return -EBADMSG;
105 }
106
107 static const struct spinand_info foresee_spinand_table[] = {
108 SPINAND_INFO("FS35ND01G-S1Y2",
109 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEA),
110 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
111 NAND_ECCREQ(4, 512),
112 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
113 &write_cache_variants,
114 &update_cache_variants),
115 0,
116 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
117 SPINAND_INFO("FS35ND02G-S3Y2",
118 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB),
119 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
120 NAND_ECCREQ(4, 512),
121 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
122 &write_cache_variants,
123 &update_cache_variants),
124 0,
125 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
126 SPINAND_INFO("FS35ND04G-S2Y2",
127 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEC),
128 NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
129 NAND_ECCREQ(4, 512),
130 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
131 &write_cache_variants,
132 &update_cache_variants),
133 0,
134 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
135 SPINAND_INFO("F35SQA001G",
136 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71),
137 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
138 NAND_ECCREQ(1, 512),
139 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
140 &write_cache_variants,
141 &update_cache_variants),
142 SPINAND_HAS_QE_BIT,
143 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
144 SPINAND_INFO("F35SQA002G",
145 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72),
146 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
147 NAND_ECCREQ(1, 512),
148 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
149 &write_cache_variants,
150 &update_cache_variants),
151 SPINAND_HAS_QE_BIT,
152 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
153 SPINAND_INFO("F35SQA512M",
154 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x70),
155 NAND_MEMORG(1, 2048, 64, 64, 512, 1, 1, 1),
156 NAND_ECCREQ(1, 512),
157 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
158 &write_cache_variants,
159 &update_cache_variants),
160 SPINAND_HAS_QE_BIT,
161 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
162 SPINAND_INFO("F35UQA512M",
163 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x60),
164 NAND_MEMORG(1, 2048, 64, 64, 512, 1, 1, 1),
165 NAND_ECCREQ(1, 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(&fsxxndxxg_ooblayout, NULL)),
171 SPINAND_INFO("F35UQA002G-WWT",
172 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x62),
173 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
174 NAND_ECCREQ(1, 512),
175 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
176 &write_cache_variants,
177 &update_cache_variants),
178 SPINAND_HAS_QE_BIT,
179 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
180 SPINAND_INFO("F35UQA001G-WWT",
181 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x61),
182 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
183 NAND_ECCREQ(1, 512),
184 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
185 &write_cache_variants,
186 &update_cache_variants),
187 SPINAND_HAS_QE_BIT,
188 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, NULL)),
189 SPINAND_INFO("F35SQB004G",
190 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x53),
191 NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
192 NAND_ECCREQ(8, 512),
193 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
194 &write_cache_variants,
195 &update_cache_variants),
196 SPINAND_HAS_QE_BIT,
197 SPINAND_ECCINFO(&f35sqb00xg_ooblayout, f35sqb00xg_ecc_get_status)),
198 SPINAND_INFO("F35SQB002G",
199 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52),
200 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
201 NAND_ECCREQ(8, 512),
202 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
203 &write_cache_variants,
204 &update_cache_variants),
205 SPINAND_HAS_QE_BIT,
206 SPINAND_ECCINFO(&fsxxndxxg_ooblayout, f35sqb00xg_ecc_get_status)),
207 };
208
209 static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = {
210 };
211
212 const struct spinand_manufacturer foresee_spinand_manufacturer = {
213 .id = SPINAND_MFR_FORESEE,
214 .name = "foresee",
215 .chips = foresee_spinand_table,
216 .nchips = ARRAY_SIZE(foresee_spinand_table),
217 .ops = &foresee_spinand_manuf_ops,
218 };
219