GNU Linux-libre 5.10.153-gnu1
[releases.git] / drivers / mtd / nand / spi / micron.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
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
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
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
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
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(&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
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 = &micron_spinand_manuf_ops,
245 };