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 #include <linux/device.h>
10 #include <linux/kernel.h>
11 #include <linux/mtd/spinand.h>
12
13 #define SPINAND_MFR_HYF 0xC9
14
15 static SPINAND_OP_VARIANTS(read_cache_variants,
16 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
17 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
18 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
19 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
20 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
21 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
22
23 static SPINAND_OP_VARIANTS(write_cache_variants,
24 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
25 SPINAND_PROG_LOAD(true, 0, NULL, 0));
26
27 static SPINAND_OP_VARIANTS(update_cache_variants,
28 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
29 SPINAND_PROG_LOAD(false, 0, NULL, 0));
30
hyf1gq4upacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)31 static int hyf1gq4upacae_ooblayout_ecc(struct mtd_info *mtd, int section,
32 struct mtd_oob_region *region)
33 {
34 if (section)
35 return -ERANGE;
36
37 region->offset = 64;
38 region->length = 64;
39
40 return 0;
41 }
42
hyf1gq4upacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)43 static int hyf1gq4upacae_ooblayout_free(struct mtd_info *mtd, int section,
44 struct mtd_oob_region *region)
45 {
46 if (section)
47 return -ERANGE;
48
49 region->offset = 1;
50 region->length = 63;
51
52 return 0;
53 }
54
55 static const struct mtd_ooblayout_ops hyf1gq4upacae_ooblayout = {
56 .ecc = hyf1gq4upacae_ooblayout_ecc,
57 .free = hyf1gq4upacae_ooblayout_free,
58 };
59
hyf1gq4udacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)60 static int hyf1gq4udacae_ooblayout_ecc(struct mtd_info *mtd, int section,
61 struct mtd_oob_region *region)
62 {
63 if (section > 3)
64 return -ERANGE;
65
66 region->offset = (16 * section) + 8;
67 region->length = 8;
68
69 return 0;
70 }
71
hyf1gq4udacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)72 static int hyf1gq4udacae_ooblayout_free(struct mtd_info *mtd, int section,
73 struct mtd_oob_region *region)
74 {
75 if (section > 3)
76 return -ERANGE;
77
78 region->offset = (16 * section) + 4;
79 region->length = 4;
80
81 return 0;
82 }
83
84 static const struct mtd_ooblayout_ops hyf1gq4udacae_ooblayout = {
85 .ecc = hyf1gq4udacae_ooblayout_ecc,
86 .free = hyf1gq4udacae_ooblayout_free,
87 };
88
hyf2gq4uaacae_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)89 static int hyf2gq4uaacae_ooblayout_ecc(struct mtd_info *mtd, int section,
90 struct mtd_oob_region *region)
91 {
92 if (section > 3)
93 return -ERANGE;
94
95 region->offset = (32 * section) + 8;
96 region->length = 24;
97
98 return 0;
99 }
100
hyf2gq4uaacae_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)101 static int hyf2gq4uaacae_ooblayout_free(struct mtd_info *mtd, int section,
102 struct mtd_oob_region *region)
103 {
104 if (section > 3)
105 return -ERANGE;
106
107 region->offset = 32 * section;
108 region->length = 8;
109
110 return 0;
111 }
112
113 static const struct mtd_ooblayout_ops hyf2gq4uaacae_ooblayout = {
114 .ecc = hyf2gq4uaacae_ooblayout_ecc,
115 .free = hyf2gq4uaacae_ooblayout_free,
116 };
117
hyf1gq4udacae_ecc_get_status(struct spinand_device * spinand,u8 status)118 static int hyf1gq4udacae_ecc_get_status(struct spinand_device *spinand,
119 u8 status)
120 {
121 struct nand_device *nand = spinand_to_nand(spinand);
122
123 switch (status & STATUS_ECC_MASK) {
124 case STATUS_ECC_NO_BITFLIPS:
125 return 0;
126
127 case STATUS_ECC_UNCOR_ERROR:
128 return -EBADMSG;
129
130 case STATUS_ECC_HAS_BITFLIPS:
131 return 1;
132
133 default:
134 return nanddev_get_ecc_requirements(nand)->strength;
135 }
136
137 return -EINVAL;
138 }
139
140 static const struct spinand_info hyf_spinand_table[] = {
141 SPINAND_INFO("HYF1GQ4UPACAE",
142 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xA1),
143 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
144 NAND_ECCREQ(1, 512),
145 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
146 &write_cache_variants,
147 &update_cache_variants),
148 SPINAND_HAS_QE_BIT,
149 SPINAND_ECCINFO(&hyf1gq4upacae_ooblayout, NULL)),
150 SPINAND_INFO("HYF1GQ4UDACAE",
151 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x21),
152 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
153 NAND_ECCREQ(4, 512),
154 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
155 &write_cache_variants,
156 &update_cache_variants),
157 SPINAND_HAS_QE_BIT,
158 SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
159 hyf1gq4udacae_ecc_get_status)),
160 SPINAND_INFO("HYF1GQ4UDACAE",
161 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x22),
162 NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
163 NAND_ECCREQ(4, 512),
164 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
165 &write_cache_variants,
166 &update_cache_variants),
167 SPINAND_HAS_QE_BIT,
168 SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
169 hyf1gq4udacae_ecc_get_status)),
170 SPINAND_INFO("HYF2GQ4UAACAE",
171 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
172 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
173 NAND_ECCREQ(14, 512),
174 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
175 &write_cache_variants,
176 &update_cache_variants),
177 SPINAND_HAS_QE_BIT,
178 SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
179 hyf1gq4udacae_ecc_get_status)),
180 SPINAND_INFO("HYF2GQ4UHCCAE",
181 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x5A),
182 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
183 NAND_ECCREQ(14, 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(&hyf2gq4uaacae_ooblayout,
189 hyf1gq4udacae_ecc_get_status)),
190 SPINAND_INFO("HYF4GQ4UAACBE",
191 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xD4),
192 NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
193 NAND_ECCREQ(4, 512),
194 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
195 &write_cache_variants,
196 &update_cache_variants),
197 SPINAND_HAS_QE_BIT,
198 SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
199 hyf1gq4udacae_ecc_get_status)),
200 SPINAND_INFO("HYF2GQ4IAACAE",
201 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x82),
202 NAND_MEMORG(1, 2048, 128, 64, 2048, 20, 1, 1, 1),
203 NAND_ECCREQ(14, 512),
204 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
205 &write_cache_variants,
206 &update_cache_variants),
207 SPINAND_HAS_QE_BIT,
208 SPINAND_ECCINFO(&hyf2gq4uaacae_ooblayout,
209 hyf1gq4udacae_ecc_get_status)),
210 SPINAND_INFO("HYF1GQ4IDACAE",
211 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x81),
212 NAND_MEMORG(1, 2048, 64, 64, 1024, 10, 1, 1, 1),
213 NAND_ECCREQ(4, 512),
214 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
215 &write_cache_variants,
216 &update_cache_variants),
217 SPINAND_HAS_QE_BIT,
218 SPINAND_ECCINFO(&hyf1gq4udacae_ooblayout,
219 hyf1gq4udacae_ecc_get_status)),
220 };
221
222 static const struct spinand_manufacturer_ops hyf_spinand_manuf_ops = {
223 };
224
225 const struct spinand_manufacturer hyf_spinand_manufacturer = {
226 .id = SPINAND_MFR_HYF,
227 .name = "hyf",
228 .chips = hyf_spinand_table,
229 .nchips = ARRAY_SIZE(hyf_spinand_table),
230 .ops = &hyf_spinand_manuf_ops,
231 };
232