blob: b538213ed8eea1fe01866de3f60941809b3414a7 [file] [log] [blame]
Peter Pandf1859e2018-08-16 17:30:13 +02001// 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#ifndef __UBOOT__
10#include <linux/device.h>
11#include <linux/kernel.h>
12#endif
13#include <linux/mtd/spinand.h>
14
15#define SPINAND_MFR_MICRON 0x2c
16
17#define MICRON_STATUS_ECC_MASK GENMASK(7, 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
Shivamurthy Shastri92ecb1a2020-07-07 22:04:11 +020023#define MICRON_CFG_CR BIT(0)
24
Shivamurthy Shastrib7242882020-07-07 22:04:13 +020025/*
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
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +010033static SPINAND_OP_VARIANTS(quadio_read_cache_variants,
Peter Pandf1859e2018-08-16 17:30:13 +020034 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
35 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
36 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
37 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
38 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
39 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
40
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +010041static SPINAND_OP_VARIANTS(x4_write_cache_variants,
Peter Pandf1859e2018-08-16 17:30:13 +020042 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
43 SPINAND_PROG_LOAD(true, 0, NULL, 0));
44
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +010045static SPINAND_OP_VARIANTS(x4_update_cache_variants,
Peter Pandf1859e2018-08-16 17:30:13 +020046 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
47 SPINAND_PROG_LOAD(false, 0, NULL, 0));
48
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +010049/* Micron MT29F2G01AAAED Device */
50static SPINAND_OP_VARIANTS(x4_read_cache_variants,
51 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
52 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
53 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
54 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
55
56static SPINAND_OP_VARIANTS(x1_write_cache_variants,
57 SPINAND_PROG_LOAD(true, 0, NULL, 0));
58
59static SPINAND_OP_VARIANTS(x1_update_cache_variants,
60 SPINAND_PROG_LOAD(false, 0, NULL, 0));
61
Shivamurthy Shastricfe77252020-07-07 22:04:08 +020062static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section,
63 struct mtd_oob_region *region)
Peter Pandf1859e2018-08-16 17:30:13 +020064{
65 if (section)
66 return -ERANGE;
67
Shivamurthy Shastricfe77252020-07-07 22:04:08 +020068 region->offset = mtd->oobsize / 2;
69 region->length = mtd->oobsize / 2;
Peter Pandf1859e2018-08-16 17:30:13 +020070
71 return 0;
72}
73
Shivamurthy Shastricfe77252020-07-07 22:04:08 +020074static int micron_8_ooblayout_free(struct mtd_info *mtd, int section,
75 struct mtd_oob_region *region)
Peter Pandf1859e2018-08-16 17:30:13 +020076{
77 if (section)
78 return -ERANGE;
79
80 /* Reserve 2 bytes for the BBM. */
81 region->offset = 2;
Shivamurthy Shastricfe77252020-07-07 22:04:08 +020082 region->length = (mtd->oobsize / 2) - 2;
Peter Pandf1859e2018-08-16 17:30:13 +020083
84 return 0;
85}
86
Shivamurthy Shastricfe77252020-07-07 22:04:08 +020087static const struct mtd_ooblayout_ops micron_8_ooblayout = {
88 .ecc = micron_8_ooblayout_ecc,
89 .rfree = micron_8_ooblayout_free,
Peter Pandf1859e2018-08-16 17:30:13 +020090};
91
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +010092static int micron_4_ooblayout_ecc(struct mtd_info *mtd, int section,
93 struct mtd_oob_region *region)
94{
95 struct spinand_device *spinand = mtd_to_spinand(mtd);
96
97 if (section >= spinand->base.memorg.pagesize /
98 mtd->ecc_step_size)
99 return -ERANGE;
100
101 region->offset = (section * 16) + 8;
102 region->length = 8;
103
104 return 0;
105}
106
107static int micron_4_ooblayout_free(struct mtd_info *mtd, int section,
108 struct mtd_oob_region *region)
109{
110 struct spinand_device *spinand = mtd_to_spinand(mtd);
111
112 if (section >= spinand->base.memorg.pagesize /
113 mtd->ecc_step_size)
114 return -ERANGE;
115
116 if (section) {
117 region->offset = 16 * section;
118 region->length = 8;
119 } else {
120 /* section 0 has two bytes reserved for the BBM */
121 region->offset = 2;
122 region->length = 6;
123 }
124
125 return 0;
126}
127
128static const struct mtd_ooblayout_ops micron_4_ooblayout = {
129 .ecc = micron_4_ooblayout_ecc,
130 .rfree = micron_4_ooblayout_free,
131};
132
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200133static int micron_select_target(struct spinand_device *spinand,
134 unsigned int target)
135{
136 struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG,
137 spinand->scratchbuf);
138
139 if (target > 1)
140 return -EINVAL;
141
142 *spinand->scratchbuf = MICRON_SELECT_DIE(target);
143
144 return spi_mem_exec_op(spinand->slave, &op);
145}
146
Shivamurthy Shastricfe77252020-07-07 22:04:08 +0200147static int micron_8_ecc_get_status(struct spinand_device *spinand,
148 u8 status)
Peter Pandf1859e2018-08-16 17:30:13 +0200149{
150 switch (status & MICRON_STATUS_ECC_MASK) {
151 case STATUS_ECC_NO_BITFLIPS:
152 return 0;
153
154 case STATUS_ECC_UNCOR_ERROR:
155 return -EBADMSG;
156
157 case MICRON_STATUS_ECC_1TO3_BITFLIPS:
158 return 3;
159
160 case MICRON_STATUS_ECC_4TO6_BITFLIPS:
161 return 6;
162
163 case MICRON_STATUS_ECC_7TO8_BITFLIPS:
164 return 8;
165
166 default:
167 break;
168 }
169
170 return -EINVAL;
171}
172
173static const struct spinand_info micron_spinand_table[] = {
Shivamurthy Shastria44f6a92020-07-07 22:04:09 +0200174 /* M79A 2Gb 3.3V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100175 SPINAND_INFO("MT29F2G01ABAGD",
176 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100177 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
Peter Pandf1859e2018-08-16 17:30:13 +0200178 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100179 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
180 &x4_write_cache_variants,
181 &x4_update_cache_variants),
Peter Pandf1859e2018-08-16 17:30:13 +0200182 0,
Shivamurthy Shastricfe77252020-07-07 22:04:08 +0200183 SPINAND_ECCINFO(&micron_8_ooblayout,
184 micron_8_ecc_get_status)),
Shivamurthy Shastri8d06c5b2020-07-07 22:04:10 +0200185 /* M79A 2Gb 1.8V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100186 SPINAND_INFO("MT29F2G01ABBGD",
187 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100188 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
Shivamurthy Shastri8d06c5b2020-07-07 22:04:10 +0200189 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100190 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
191 &x4_write_cache_variants,
192 &x4_update_cache_variants),
Shivamurthy Shastri8d06c5b2020-07-07 22:04:10 +0200193 0,
194 SPINAND_ECCINFO(&micron_8_ooblayout,
195 micron_8_ecc_get_status)),
196 /* M78A 1Gb 3.3V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100197 SPINAND_INFO("MT29F1G01ABAFD",
198 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100199 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
Shivamurthy Shastri8d06c5b2020-07-07 22:04:10 +0200200 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100201 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
202 &x4_write_cache_variants,
203 &x4_update_cache_variants),
Shivamurthy Shastri8d06c5b2020-07-07 22:04:10 +0200204 0,
205 SPINAND_ECCINFO(&micron_8_ooblayout,
206 micron_8_ecc_get_status)),
207 /* M78A 1Gb 1.8V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100208 SPINAND_INFO("MT29F1G01ABAFD",
209 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100210 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
Shivamurthy Shastri8d06c5b2020-07-07 22:04:10 +0200211 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100212 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
213 &x4_write_cache_variants,
214 &x4_update_cache_variants),
Shivamurthy Shastri8d06c5b2020-07-07 22:04:10 +0200215 0,
216 SPINAND_ECCINFO(&micron_8_ooblayout,
217 micron_8_ecc_get_status)),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200218 /* M79A 4Gb 3.3V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100219 SPINAND_INFO("MT29F4G01ADAGD",
220 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x36),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100221 NAND_MEMORG(1, 2048, 128, 64, 2048, 80, 2, 1, 2),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200222 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100223 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
224 &x4_write_cache_variants,
225 &x4_update_cache_variants),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200226 0,
227 SPINAND_ECCINFO(&micron_8_ooblayout,
228 micron_8_ecc_get_status),
229 SPINAND_SELECT_TARGET(micron_select_target)),
Shivamurthy Shastri5cbf17f2020-07-07 22:04:12 +0200230 /* M70A 4Gb 3.3V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100231 SPINAND_INFO("MT29F4G01ABAFD",
232 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x34),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100233 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
Shivamurthy Shastri5cbf17f2020-07-07 22:04:12 +0200234 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100235 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
236 &x4_write_cache_variants,
237 &x4_update_cache_variants),
Shivamurthy Shastri5cbf17f2020-07-07 22:04:12 +0200238 SPINAND_HAS_CR_FEAT_BIT,
239 SPINAND_ECCINFO(&micron_8_ooblayout,
240 micron_8_ecc_get_status)),
241 /* M70A 4Gb 1.8V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100242 SPINAND_INFO("MT29F4G01ABBFD",
243 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100244 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
Shivamurthy Shastri5cbf17f2020-07-07 22:04:12 +0200245 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100246 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
247 &x4_write_cache_variants,
248 &x4_update_cache_variants),
Shivamurthy Shastri5cbf17f2020-07-07 22:04:12 +0200249 SPINAND_HAS_CR_FEAT_BIT,
250 SPINAND_ECCINFO(&micron_8_ooblayout,
251 micron_8_ecc_get_status)),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200252 /* M70A 8Gb 3.3V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100253 SPINAND_INFO("MT29F8G01ADAFD",
254 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x46),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100255 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200256 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100257 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
258 &x4_write_cache_variants,
259 &x4_update_cache_variants),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200260 SPINAND_HAS_CR_FEAT_BIT,
261 SPINAND_ECCINFO(&micron_8_ooblayout,
262 micron_8_ecc_get_status),
263 SPINAND_SELECT_TARGET(micron_select_target)),
264 /* M70A 8Gb 1.8V */
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100265 SPINAND_INFO("MT29F8G01ADBFD",
266 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x47),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100267 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 2),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200268 NAND_ECCREQ(8, 512),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100269 SPINAND_INFO_OP_VARIANTS(&quadio_read_cache_variants,
270 &x4_write_cache_variants,
271 &x4_update_cache_variants),
Shivamurthy Shastrib7242882020-07-07 22:04:13 +0200272 SPINAND_HAS_CR_FEAT_BIT,
273 SPINAND_ECCINFO(&micron_8_ooblayout,
274 micron_8_ecc_get_status),
275 SPINAND_SELECT_TARGET(micron_select_target)),
Mikhail Kshevetskiy2a1e78b2023-01-10 12:58:40 +0100276 /* M69A 2Gb 3.3V */
277 SPINAND_INFO("MT29F2G01AAAED",
278 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9F),
279 NAND_MEMORG(1, 2048, 64, 64, 2048, 80, 2, 1, 1),
280 NAND_ECCREQ(4, 512),
281 SPINAND_INFO_OP_VARIANTS(&x4_read_cache_variants,
282 &x1_write_cache_variants,
283 &x1_update_cache_variants),
284 0,
285 SPINAND_ECCINFO(&micron_4_ooblayout, NULL)),
Peter Pandf1859e2018-08-16 17:30:13 +0200286};
287
Shivamurthy Shastri92ecb1a2020-07-07 22:04:11 +0200288static int micron_spinand_init(struct spinand_device *spinand)
289{
290 /*
291 * M70A device series enable Continuous Read feature at Power-up,
292 * which is not supported. Disable this bit to avoid any possible
293 * failure.
294 */
295 if (spinand->flags & SPINAND_HAS_CR_FEAT_BIT)
296 return spinand_upd_cfg(spinand, MICRON_CFG_CR, 0);
297
298 return 0;
299}
300
Peter Pandf1859e2018-08-16 17:30:13 +0200301static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
Shivamurthy Shastri92ecb1a2020-07-07 22:04:11 +0200302 .init = micron_spinand_init,
Peter Pandf1859e2018-08-16 17:30:13 +0200303};
304
305const struct spinand_manufacturer micron_spinand_manufacturer = {
306 .id = SPINAND_MFR_MICRON,
307 .name = "Micron",
Mikhail Kshevetskiy72010312023-01-10 12:58:38 +0100308 .chips = micron_spinand_table,
309 .nchips = ARRAY_SIZE(micron_spinand_table),
Peter Pandf1859e2018-08-16 17:30:13 +0200310 .ops = &micron_spinand_manuf_ops,
311};