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(6, 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
31static 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
39static SPINAND_OP_VARIANTS(write_cache_variants,
40		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
41		SPINAND_PROG_LOAD(true, 0, NULL, 0));
42
43static SPINAND_OP_VARIANTS(update_cache_variants,
44		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
45		SPINAND_PROG_LOAD(false, 0, NULL, 0));
46
47static 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
59static 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
72static const struct mtd_ooblayout_ops micron_8_ooblayout = {
73	.ecc = micron_8_ooblayout_ecc,
74	.free = micron_8_ooblayout_free,
75};
76
77static 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
91static 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
117static 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(&micron_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(&micron_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(&micron_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(&micron_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(&micron_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(&micron_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(&micron_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(&micron_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(&micron_8_ooblayout,
218				     micron_8_ecc_get_status),
219		     SPINAND_SELECT_TARGET(micron_select_target)),
220};
221
222static 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
235static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
236	.init = micron_spinand_init,
237};
238
239const 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 = &micron_spinand_manuf_ops,
245};
246