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