1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2016-2017 Micron Technology, Inc.
4 *
5 * Authors:
6 * Peter Pan <peterpandong@micron.com>
7 */
8
9 #include <linux/device.h>
10 #include <linux/kernel.h>
11 #include <linux/mtd/spinand.h>
12
13 #define SPINAND_MFR_MICRON 0x2c
14
15 #define MICRON_STATUS_ECC_MASK GENMASK(7, 4)
16 #define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4)
17 #define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
18 #define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
19 #define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
20
21 #define MICRON_CFG_CR BIT(0)
22
23 /*
24 * As per datasheet, die selection is done by the 6th bit of Die
25 * Select Register (Address 0xD0).
26 */
27 #define MICRON_DIE_SELECT_REG 0xD0
28
29 #define MICRON_SELECT_DIE(x) ((x) << 6)
30
31 static SPINAND_OP_VARIANTS(read_cache_variants,
32 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
33 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
34 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
35 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
36 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
37 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
38
39 static SPINAND_OP_VARIANTS(write_cache_variants,
40 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
41 SPINAND_PROG_LOAD(true, 0, NULL, 0));
42
43 static SPINAND_OP_VARIANTS(update_cache_variants,
44 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
45 SPINAND_PROG_LOAD(false, 0, NULL, 0));
46
micron_8_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)47 static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
48 struct mtd_oob_region *region)
49 {
50 if (section)
51 return -ERANGE;
52
53 region->offset = mtd->oobsize / 2;
54 region->length = mtd->oobsize / 2;
55
56 return 0;
57 }
58
micron_8_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)59 static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
60 struct mtd_oob_region *region)
61 {
62 if (section)
63 return -ERANGE;
64
65 /* Reserve 2 bytes for the BBM. */
66 region->offset = 2;
67 region->length = (mtd->oobsize / 2) - 2;
68
69 return 0;
70 }
71
72 static const struct mtd_ooblayout_ops micron_8_ooblayout = {
73 .ecc = micron_8_ooblayout_ecc,
74 .free = micron_8_ooblayout_free,
75 };
76
micron_select_target(struct spinand_device * spinand,unsigned int target)77 static int micron_select_target(struct spinand_device *spinand,
78 unsigned int target)
79 {
80 struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
81 spinand->scratchbuf);
82
83 if (target > 1)
84 return -EINVAL;
85
86 *spinand->scratchbuf = MICRON_SELECT_DIE(target);
87
88 return spi_mem_exec_op(spinand->spimem, &op);
89 }
90
micron_8_ecc_get_status(struct spinand_device * spinand,u8 status)91 static int micron_8_ecc_get_status(struct spinand_device *spinand,
92 u8 status)
93 {
94 switch (status & MICRON_STATUS_ECC_MASK) {
95 case STATUS_ECC_NO_BITFLIPS:
96 return 0;
97
98 case STATUS_ECC_UNCOR_ERROR:
99 return -EBADMSG;
100
101 case MICRON_STATUS_ECC_1TO3_BITFLIPS:
102 return 3;
103
104 case MICRON_STATUS_ECC_4TO6_BITFLIPS:
105 return 6;
106
107 case MICRON_STATUS_ECC_7TO8_BITFLIPS:
108 return 8;
109
110 default:
111 break;
112 }
113
114 return -EINVAL;
115 }
116
117 static const struct spinand_info micron_spinand_table[] = {
118 /* M79A 2Gb 3.3V */
119 SPINAND_INFO("MT29F2G01ABAGD",
120 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
121 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
122 NAND_ECCREQ(8, 512),
123 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
124 &write_cache_variants,
125 &update_cache_variants),
126 0,
127 SPINAND_ECCINFO(µn_8_ooblayout,
128 micron_8_ecc_get_status)),
129 /* M79A 2Gb 1.8V */
130 SPINAND_INFO("MT29F2G01ABBGD",
131 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
132 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
133 NAND_ECCREQ(8, 512),
134 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
135 &write_cache_variants,
136 &update_cache_variants),
137 0,
138 SPINAND_ECCINFO(µn_8_ooblayout,
139 micron_8_ecc_get_status)),
140 /* M78A 1Gb 3.3V */
141 SPINAND_INFO("MT29F1G01ABAFD",
142 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
143 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
144 NAND_ECCREQ(8, 512),
145 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
146 &write_cache_variants,
147 &update_cache_variants),
148 0,
149 SPINAND_ECCINFO(µn_8_ooblayout,
150 micron_8_ecc_get_status)),
151 /* M78A 1Gb 1.8V */
152 SPINAND_INFO("MT29F1G01ABAFD",
153 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
154 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
155 NAND_ECCREQ(8, 512),
156 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
157 &write_cache_variants,
158 &update_cache_variants),
159 0,
160 SPINAND_ECCINFO(µn_8_ooblayout,
161 micron_8_ecc_get_status)),
162 /* M79A 4Gb 3.3V */
163 SPINAND_INFO("MT29F4G01ADAGD",
164 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
165 NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
166 NAND_ECCREQ(8, 512),
167 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
168 &write_cache_variants,
169 &update_cache_variants),
170 0,
171 SPINAND_ECCINFO(µn_8_ooblayout,
172 micron_8_ecc_get_status),
173 SPINAND_SELECT_TARGET(micron_select_target)),
174 /* M70A 4Gb 3.3V */
175 SPINAND_INFO("MT29F4G01ABAFD",
176 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
177 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
178 NAND_ECCREQ(8, 512),
179 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
180 &write_cache_variants,
181 &update_cache_variants),
182 SPINAND_HAS_CR_FEAT_BIT,
183 SPINAND_ECCINFO(µn_8_ooblayout,
184 micron_8_ecc_get_status)),
185 /* M70A 4Gb 1.8V */
186 SPINAND_INFO("MT29F4G01ABBFD",
187 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
188 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 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_CR_FEAT_BIT,
194 SPINAND_ECCINFO(µn_8_ooblayout,
195 micron_8_ecc_get_status)),
196 /* M70A 8Gb 3.3V */
197 SPINAND_INFO("MT29F8G01ADAFD",
198 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
199 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
200 NAND_ECCREQ(8, 512),
201 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
202 &write_cache_variants,
203 &update_cache_variants),
204 SPINAND_HAS_CR_FEAT_BIT,
205 SPINAND_ECCINFO(µn_8_ooblayout,
206 micron_8_ecc_get_status),
207 SPINAND_SELECT_TARGET(micron_select_target)),
208 /* M70A 8Gb 1.8V */
209 SPINAND_INFO("MT29F8G01ADBFD",
210 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
211 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
212 NAND_ECCREQ(8, 512),
213 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
214 &write_cache_variants,
215 &update_cache_variants),
216 SPINAND_HAS_CR_FEAT_BIT,
217 SPINAND_ECCINFO(µn_8_ooblayout,
218 micron_8_ecc_get_status),
219 SPINAND_SELECT_TARGET(micron_select_target)),
220 };
221
micron_spinand_init(struct spinand_device * spinand)222 static int micron_spinand_init(struct spinand_device *spinand)
223 {
224 /*
225 * M70A device series enable Continuous Read feature at Power-up,
226 * which is not supported. Disable this bit to avoid any possible
227 * failure.
228 */
229 if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
230 return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);
231
232 return 0;
233 }
234
235 static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
236 .init = micron_spinand_init,
237 };
238
239 const struct spinand_manufacturer micron_spinand_manufacturer = {
240 .id = SPINAND_MFR_MICRON,
241 .name = "Micron",
242 .chips = micron_spinand_table,
243 .nchips = ARRAY_SIZE(micron_spinand_table),
244 .ops = µn_spinand_manuf_ops,
245 };
246