File Index
Files and directories
Sign in
FILE

micron.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mtd/nand/spi/micron.c C
  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, 0),
 39		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0),
 40		SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0),
 41		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
 42		SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
 43		SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 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, 0),
 56			   SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0),
 57			   SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0),
 58			   SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 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(spinand->spimem, &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, 0, bufsize, &retlen, buf);
195
196	if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK,
197			    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(buf, bufsize))
208		ret = 1;
209
210free_buf:
211	kfree(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, 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, 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(spinand->spimem, &write_op);
266	if (!ret)
267		goto out;
268
269	ret = spi_mem_exec_op(spinand->spimem, &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			   &status);
277	if (!ret && (status & STATUS_PROG_FAILED))
278		ret = -EIO;
279
280out:
281	if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, 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, 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};
~/ Read-only file preview.