1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd
4 *
5 * Authors:
6 * Dingqiang Lin <jon.lin@rock-chips.com>
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_HYF 0xC9
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(false, 0, NULL, 0));
32
hyf1gq4upacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)33 static int hyf1gq4upacae_ooblayout_ecc(struct mtd_info *mtd, int section,
34 struct mtd_oob_region *region)
35 {
36 if (section)
37 return -ERANGE;
38
39 region->offset = 64;
40 region->length = 64;
41
42 return 0;
43 }
44
hyf1gq4upacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)45 static int hyf1gq4upacae_ooblayout_free(struct mtd_info *mtd, int section,
46 struct mtd_oob_region *region)
47 {
48 if (section)
49 return -ERANGE;
50
51 region->offset = 1;
52 region->length = 63;
53
54 return 0;
55 }
56
57 static const struct mtd_ooblayout_ops hyf1gq4upacae_ooblayout = {
58 .ecc = hyf1gq4upacae_ooblayout_ecc,
59 .rfree = hyf1gq4upacae_ooblayout_free,
60 };
61
hyf1gq4udacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)62 static int hyf1gq4udacae_ooblayout_ecc(struct mtd_info *mtd, int section,
63 struct mtd_oob_region *region)
64 {
65 if (section > 3)
66 return -ERANGE;
67
68 region->offset = (16 * section) + 8;
69 region->length = 8;
70
71 return 0;
72 }
73
hyf1gq4udacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)74 static int hyf1gq4udacae_ooblayout_free(struct mtd_info *mtd, int section,
75 struct mtd_oob_region *region)
76 {
77 if (section > 3)
78 return -ERANGE;
79
80 region->offset = (16 * section) + 4;
81 region->length = 4;
82
83 return 0;
84 }
85
86 static const struct mtd_ooblayout_ops hyf1gq4udacae_ooblayout = {
87 .ecc = hyf1gq4udacae_ooblayout_ecc,
88 .rfree = hyf1gq4udacae_ooblayout_free,
89 };
90
hyf2gq4uaacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)91 static int hyf2gq4uaacae_ooblayout_ecc(struct mtd_info *mtd, int section,
92 struct mtd_oob_region *region)
93 {
94 if (section > 3)
95 return -ERANGE;
96
97 region->offset = (32 * section) + 8;
98 region->length = 24;
99
100 return 0;
101 }
102
hyf2gq4uaacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)103 static int hyf2gq4uaacae_ooblayout_free(struct mtd_info *mtd, int section,
104 struct mtd_oob_region *region)
105 {
106 if (section > 3)
107 return -ERANGE;
108
109 region->offset = 32 * section;
110 region->length = 8;
111
112 return 0;
113 }
114
115 static const struct mtd_ooblayout_ops hyf2gq4uaacae_ooblayout = {
116 .ecc = hyf2gq4uaacae_ooblayout_ecc,
117 .rfree = hyf2gq4uaacae_ooblayout_free,
118 };
119
hyf1gq4udacae_ecc_get_status(struct spinand_device * spinand,u8 status)120 static int hyf1gq4udacae_ecc_get_status(struct spinand_device *spinand,
121 u8 status)
122 {
123 struct nand_device *nand = spinand_to_nand(spinand);
124
125 switch (status & STATUS_ECC_MASK) {
126 case STATUS_ECC_NO_BITFLIPS:
127 return 0;
128
129 case STATUS_ECC_UNCOR_ERROR:
130 return -EBADMSG;
131
132 case STATUS_ECC_HAS_BITFLIPS:
133 return 1;
134
135 default:
136 return nand->eccreq.strength;
137 }
138
139 return -EINVAL;
140 }
141
142 static const struct spinand_info hyf_spinand_table[] = {
143 SPINAND_INFO("HYF1GQ4UPACAE",
144 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xA1),
145 NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
146 NAND_ECCREQ(1, 512),
147 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
148 &write_cache_variants,
149 &update_cache_variants),
150 SPINAND_HAS_QE_BIT,
151 SPINAND_ECCINFO(&hyf1gq4upacae_ooblayout, NULL)),
152 SPINAND_INFO("HYF1GQ4UDACAE",
153 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x21),
154 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
155 NAND_ECCREQ(4, 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(&hyf1gq4udacae_ooblayout,
161 hyf1gq4udacae_ecc_get_status)),
162 SPINAND_INFO("HYF1GQ4UDACAE",
163 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x22),
164 NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
165 NAND_ECCREQ(4, 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(&hyf1gq4udacae_ooblayout,
171 hyf1gq4udacae_ecc_get_status)),
172 SPINAND_INFO("HYF2GQ4UAACAE",
173 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
174 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
175 NAND_ECCREQ(14, 512),
176 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
177 &write_cache_variants,
178 &update_cache_variants),
179 SPINAND_HAS_QE_BIT,
180 SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
181 hyf1gq4udacae_ecc_get_status)),
182 SPINAND_INFO("HYF2GQ4UHCCAE",
183 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x5A),
184 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
185 NAND_ECCREQ(14, 512),
186 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
187 &write_cache_variants,
188 &update_cache_variants),
189 SPINAND_HAS_QE_BIT,
190 SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
191 hyf1gq4udacae_ecc_get_status)),
192 SPINAND_INFO("HYF4GQ4UAACBE",
193 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xD4),
194 NAND_MEMORG(1, 4096, 128, 64, 2048, 1, 1, 1),
195 NAND_ECCREQ(4, 512),
196 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
197 &write_cache_variants,
198 &update_cache_variants),
199 SPINAND_HAS_QE_BIT,
200 SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
201 hyf1gq4udacae_ecc_get_status)),
202 SPINAND_INFO("HYF2GQ4IAACAE",
203 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x82),
204 NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
205 NAND_ECCREQ(14, 512),
206 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
207 &write_cache_variants,
208 &update_cache_variants),
209 SPINAND_HAS_QE_BIT,
210 SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
211 hyf1gq4udacae_ecc_get_status)),
212 SPINAND_INFO("HYF1GQ4IDACAE",
213 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x81),
214 NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
215 NAND_ECCREQ(4, 512),
216 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
217 &write_cache_variants,
218 &update_cache_variants),
219 SPINAND_HAS_QE_BIT,
220 SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
221 hyf1gq4udacae_ecc_get_status)),
222 };
223
224 static const struct spinand_manufacturer_ops hyf_spinand_manuf_ops = {
225 };
226
227 const struct spinand_manufacturer hyf_spinand_manufacturer = {
228 .id = SPINAND_MFR_HYF,
229 .name = "hyf",
230 .chips = hyf_spinand_table,
231 .nchips = ARRAY_SIZE(hyf_spinand_table),
232 .ops = &hyf_spinand_manuf_ops,
233 };
234