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#include <linux/spi/spi-mem.h>
13#include <linux/string.h>
14
15#define SPINAND_MFR_MICRON 0x2c
16
17#define MICRON_STATUS_ECC_MASK GENMASK(6, 4)
18#define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4)
19#define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4)
20#define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4)
21#define MICRON_STATUS_ECC_7TO8_BITFLIPS (5 << 4)
22
23#define MICRON_CFG_CR BIT(0)
24
25/*
26 * As per datasheet, die selection is done by the 6th bit of Die
27 * Select Register (Address 0xD0).
28 */
29#define MICRON_DIE_SELECT_REG 0xD0
30
31#define MICRON_SELECT_DIE(x) ((x) << 6)
32
33#define MICRON_MT29F2G01ABAGD_CFG_OTP_STATE BIT(7)
34#define MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK \
35 (CFG_OTP_ENABLE | MICRON_MT29F2G01ABAGD_CFG_OTP_STATE)
36
37static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
38 SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0),
39 SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
40 SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0),
41 SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
42 SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
43 SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
44
45static SPINAND_OP_VARIANTS(x4_write_cache_variants,
46 SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0),
47 SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
48
49static SPINAND_OP_VARIANTS(x4_update_cache_variants,
50 SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0),
51 SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
52
53/* Micron MT29F2G01AAAED Device */
54static SPINAND_OP_VARIANTS(x4_read_cache_variants,
55 SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0),
56 SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0),
57 SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0),
58 SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0));
59
60static SPINAND_OP_VARIANTS(x1_write_cache_variants,
61 SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0));
62
63static SPINAND_OP_VARIANTS(x1_update_cache_variants,
64 SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0));
65
66static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
67 struct mtd_oob_region *region)
68{
69 if (section)
70 return -ERANGE;
71
72 region->offset = mtd->oobsize / 2;
73 region->length = mtd->oobsize / 2;
74
75 return 0;
76}
77
78static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
79 struct mtd_oob_region *region)
80{
81 if (section)
82 return -ERANGE;
83
84 /* Reserve 2 bytes for the BBM. */
85 region->offset = 2;
86 region->length = (mtd->oobsize / 2) - 2;
87
88 return 0;
89}
90
91static const struct mtd_ooblayout_ops micron_8_ooblayout = {
92 .ecc = micron_8_ooblayout_ecc,
93 .free = micron_8_ooblayout_free,
94};
95
96static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
97 struct mtd_oob_region *region)
98{
99 struct spinand_device *spinand = mtd_to_spinand(mtd);
100
101 if (section >= spinand->base.memorg.pagesize /
102 mtd->ecc_step_size)
103 return -ERANGE;
104
105 region->offset = (section * 16) + 8;
106 region->length = 8;
107
108 return 0;
109}
110
111static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
112 struct mtd_oob_region *region)
113{
114 struct spinand_device *spinand = mtd_to_spinand(mtd);
115
116 if (section >= spinand->base.memorg.pagesize /
117 mtd->ecc_step_size)
118 return -ERANGE;
119
120 if (section) {
121 region->offset = 16 * section;
122 region->length = 8;
123 } else {
124 /* section 0 has two bytes reserved for the BBM */
125 region->offset = 2;
126 region->length = 6;
127 }
128
129 return 0;
130}
131
132static const struct mtd_ooblayout_ops micron_4_ooblayout = {
133 .ecc = micron_4_ooblayout_ecc,
134 .free = micron_4_ooblayout_free,
135};
136
137static int micron_select_target(struct spinand_device *spinand,
138 unsigned int target)
139{
140 struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MICRON_DIE_SELECT_REG,
141 spinand->scratchbuf);
142
143 if (target > 1)
144 return -EINVAL;
145
146 *spinand->scratchbuf = MICRON_SELECT_DIE(target);
147
148 return spi_mem_exec_op(mem: spinand->spimem, op: &op);
149}
150
151static int micron_8_ecc_get_status(struct spinand_device *spinand,
152 u8 status)
153{
154 switch (status & MICRON_STATUS_ECC_MASK) {
155 case STATUS_ECC_NO_BITFLIPS:
156 return 0;
157
158 case STATUS_ECC_UNCOR_ERROR:
159 return -EBADMSG;
160
161 case MICRON_STATUS_ECC_1TO3_BITFLIPS:
162 return 3;
163
164 case MICRON_STATUS_ECC_4TO6_BITFLIPS:
165 return 6;
166
167 case MICRON_STATUS_ECC_7TO8_BITFLIPS:
168 return 8;
169
170 default:
171 break;
172 }
173
174 return -EINVAL;
175}
176
177static int mt29f2g01abagd_otp_is_locked(struct spinand_device *spinand)
178{
179 size_t bufsize = spinand_otp_page_size(spinand);
180 size_t retlen;
181 u8 *buf;
182 int ret;
183
184 buf = kmalloc(bufsize, GFP_KERNEL);
185 if (!buf)
186 return -ENOMEM;
187
188 ret = spinand_upd_cfg(spinand,
189 MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
190 MICRON_MT29F2G01ABAGD_CFG_OTP_STATE);
191 if (ret)
192 goto free_buf;
193
194 ret = spinand_user_otp_read(spinand, ofs: 0, len: bufsize, retlen: &retlen, buf);
195
196 if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
197 val: 0)) {
198 dev_warn(&spinand_to_mtd(spinand)->dev,
199 "Can not disable OTP mode\n");
200 ret = -EIO;
201 }
202
203 if (ret)
204 goto free_buf;
205
206 /* If all zeros, then the OTP area is locked. */
207 if (mem_is_zero(s: buf, n: bufsize))
208 ret = 1;
209
210free_buf:
211 kfree(objp: buf);
212 return ret;
213}
214
215static int mt29f2g01abagd_otp_info(struct spinand_device *spinand, size_t len,
216 struct otp_info *buf, size_t *retlen,
217 bool user)
218{
219 int locked;
220
221 if (len < sizeof(*buf))
222 return -EINVAL;
223
224 locked = mt29f2g01abagd_otp_is_locked(spinand);
225 if (locked < 0)
226 return locked;
227
228 buf->locked = locked;
229 buf->start = 0;
230 buf->length = user ? spinand_user_otp_size(spinand) :
231 spinand_fact_otp_size(spinand);
232
233 *retlen = sizeof(*buf);
234 return 0;
235}
236
237static int mt29f2g01abagd_fact_otp_info(struct spinand_device *spinand,
238 size_t len, struct otp_info *buf,
239 size_t *retlen)
240{
241 return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, user: false);
242}
243
244static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand,
245 size_t len, struct otp_info *buf,
246 size_t *retlen)
247{
248 return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, user: true);
249}
250
251static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from,
252 size_t len)
253{
254 struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true);
255 struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0);
256 u8 status;
257 int ret;
258
259 ret = spinand_upd_cfg(spinand,
260 MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
261 MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK);
262 if (!ret)
263 return ret;
264
265 ret = spi_mem_exec_op(mem: spinand->spimem, op: &write_op);
266 if (!ret)
267 goto out;
268
269 ret = spi_mem_exec_op(mem: spinand->spimem, op: &exec_op);
270 if (!ret)
271 goto out;
272
273 ret = spinand_wait(spinand,
274 SPINAND_WRITE_INITIAL_DELAY_US,
275 SPINAND_WRITE_POLL_DELAY_US,
276 s: &status);
277 if (!ret && (status & STATUS_PROG_FAILED))
278 ret = -EIO;
279
280out:
281 if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, val: 0)) {
282 dev_warn(&spinand_to_mtd(spinand)->dev,
283 "Can not disable OTP mode\n");
284 ret = -EIO;
285 }
286
287 return ret;
288}
289
290static const struct spinand_user_otp_ops mt29f2g01abagd_user_otp_ops = {
291 .info = mt29f2g01abagd_user_otp_info,
292 .lock = mt29f2g01abagd_otp_lock,
293 .read = spinand_user_otp_read,
294 .write = spinand_user_otp_write,
295};
296
297static const struct spinand_fact_otp_ops mt29f2g01abagd_fact_otp_ops = {
298 .info = mt29f2g01abagd_fact_otp_info,
299 .read = spinand_fact_otp_read,
300};
301
302static const struct spinand_info micron_spinand_table[] = {
303 /* M79A 2Gb 3.3V */
304 SPINAND_INFO("MT29F2G01ABAGD",
305 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
306 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
307 NAND_ECCREQ(8, 512),
308 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
309 &x4_write_cache_variants,
310 &x4_update_cache_variants),
311 0,
312 SPINAND_ECCINFO(&micron_8_ooblayout,
313 micron_8_ecc_get_status),
314 SPINAND_USER_OTP_INFO(12, 2, &mt29f2g01abagd_user_otp_ops),
315 SPINAND_FACT_OTP_INFO(2, 0, &mt29f2g01abagd_fact_otp_ops)),
316 /* M79A 2Gb 1.8V */
317 SPINAND_INFO("MT29F2G01ABBGD",
318 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
319 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
320 NAND_ECCREQ(8, 512),
321 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
322 &x4_write_cache_variants,
323 &x4_update_cache_variants),
324 0,
325 SPINAND_ECCINFO(&micron_8_ooblayout,
326 micron_8_ecc_get_status)),
327 /* M78A 1Gb 3.3V */
328 SPINAND_INFO("MT29F1G01ABAFD",
329 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
330 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
331 NAND_ECCREQ(8, 512),
332 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
333 &x4_write_cache_variants,
334 &x4_update_cache_variants),
335 0,
336 SPINAND_ECCINFO(&micron_8_ooblayout,
337 micron_8_ecc_get_status)),
338 /* M78A 1Gb 1.8V */
339 SPINAND_INFO("MT29F1G01ABAFD",
340 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
341 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
342 NAND_ECCREQ(8, 512),
343 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
344 &x4_write_cache_variants,
345 &x4_update_cache_variants),
346 0,
347 SPINAND_ECCINFO(&micron_8_ooblayout,
348 micron_8_ecc_get_status)),
349 /* M79A 4Gb 3.3V */
350 SPINAND_INFO("MT29F4G01ADAGD",
351 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
352 NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
353 NAND_ECCREQ(8, 512),
354 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
355 &x4_write_cache_variants,
356 &x4_update_cache_variants),
357 0,
358 SPINAND_ECCINFO(&micron_8_ooblayout,
359 micron_8_ecc_get_status),
360 SPINAND_SELECT_TARGET(micron_select_target)),
361 /* M70A 4Gb 3.3V */
362 SPINAND_INFO("MT29F4G01ABAFD",
363 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
364 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
365 NAND_ECCREQ(8, 512),
366 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
367 &x4_write_cache_variants,
368 &x4_update_cache_variants),
369 SPINAND_HAS_CR_FEAT_BIT,
370 SPINAND_ECCINFO(&micron_8_ooblayout,
371 micron_8_ecc_get_status)),
372 /* M70A 4Gb 1.8V */
373 SPINAND_INFO("MT29F4G01ABBFD",
374 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
375 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
376 NAND_ECCREQ(8, 512),
377 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
378 &x4_write_cache_variants,
379 &x4_update_cache_variants),
380 SPINAND_HAS_CR_FEAT_BIT,
381 SPINAND_ECCINFO(&micron_8_ooblayout,
382 micron_8_ecc_get_status)),
383 /* M70A 8Gb 3.3V */
384 SPINAND_INFO("MT29F8G01ADAFD",
385 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
386 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
387 NAND_ECCREQ(8, 512),
388 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
389 &x4_write_cache_variants,
390 &x4_update_cache_variants),
391 SPINAND_HAS_CR_FEAT_BIT,
392 SPINAND_ECCINFO(&micron_8_ooblayout,
393 micron_8_ecc_get_status),
394 SPINAND_SELECT_TARGET(micron_select_target)),
395 /* M70A 8Gb 1.8V */
396 SPINAND_INFO("MT29F8G01ADBFD",
397 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
398 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
399 NAND_ECCREQ(8, 512),
400 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
401 &x4_write_cache_variants,
402 &x4_update_cache_variants),
403 SPINAND_HAS_CR_FEAT_BIT,
404 SPINAND_ECCINFO(&micron_8_ooblayout,
405 micron_8_ecc_get_status),
406 SPINAND_SELECT_TARGET(micron_select_target)),
407 /* M69A 2Gb 3.3V */
408 SPINAND_INFO("MT29F2G01AAAED",
409 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
410 NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
411 NAND_ECCREQ(4, 512),
412 SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
413 &x1_write_cache_variants,
414 &x1_update_cache_variants),
415 0,
416 SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
417};
418
419static int micron_spinand_init(struct spinand_device *spinand)
420{
421 /*
422 * M70A device series enable Continuous Read feature at Power-up,
423 * which is not supported. Disable this bit to avoid any possible
424 * failure.
425 */
426 if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
427 return spinand_upd_cfg(spinand, MICRON_CFG_CR, val: 0);
428
429 return 0;
430}
431
432static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
433 .init = micron_spinand_init,
434};
435
436const struct spinand_manufacturer micron_spinand_manufacturer = {
437 .id = SPINAND_MFR_MICRON,
438 .name = "Micron",
439 .chips = micron_spinand_table,
440 .nchips = ARRAY_SIZE(micron_spinand_table),
441 .ops = &micron_spinand_manuf_ops,
442};
443

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/drivers/mtd/nand/spi/micron.c