]>
Commit | Line | Data |
---|---|---|
15f5c7e5 BB |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2005, Intec Automation Inc. | |
4 | * Copyright (C) 2014, Freescale Semiconductor, Inc. | |
5 | */ | |
6 | ||
7 | #include <linux/mtd/spi-nor.h> | |
8 | ||
9 | #include "core.h" | |
10 | ||
ad624dfd PY |
11 | #define SPINOR_OP_MT_DTR_RD 0xfd /* Fast Read opcode in DTR mode */ |
12 | #define SPINOR_OP_MT_RD_ANY_REG 0x85 /* Read volatile register */ | |
13 | #define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */ | |
14 | #define SPINOR_REG_MT_CFR0V 0x00 /* For setting octal DTR mode */ | |
15 | #define SPINOR_REG_MT_CFR1V 0x01 /* For setting dummy cycles */ | |
16 | #define SPINOR_MT_OCT_DTR 0xe7 /* Enable Octal DTR. */ | |
17 | #define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */ | |
18 | ||
19 | static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor, bool enable) | |
20 | { | |
21 | struct spi_mem_op op; | |
22 | u8 *buf = nor->bouncebuf; | |
23 | int ret; | |
24 | ||
25 | if (enable) { | |
26 | /* Use 20 dummy cycles for memory array reads. */ | |
27 | ret = spi_nor_write_enable(nor); | |
28 | if (ret) | |
29 | return ret; | |
30 | ||
31 | *buf = 20; | |
32 | op = (struct spi_mem_op) | |
33 | SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), | |
34 | SPI_MEM_OP_ADDR(3, SPINOR_REG_MT_CFR1V, 1), | |
35 | SPI_MEM_OP_NO_DUMMY, | |
36 | SPI_MEM_OP_DATA_OUT(1, buf, 1)); | |
37 | ||
38 | ret = spi_mem_exec_op(nor->spimem, &op); | |
39 | if (ret) | |
40 | return ret; | |
41 | ||
42 | ret = spi_nor_wait_till_ready(nor); | |
43 | if (ret) | |
44 | return ret; | |
45 | } | |
46 | ||
47 | ret = spi_nor_write_enable(nor); | |
48 | if (ret) | |
49 | return ret; | |
50 | ||
51 | if (enable) | |
52 | *buf = SPINOR_MT_OCT_DTR; | |
53 | else | |
54 | *buf = SPINOR_MT_EXSPI; | |
55 | ||
56 | op = (struct spi_mem_op) | |
57 | SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), | |
58 | SPI_MEM_OP_ADDR(enable ? 3 : 4, | |
59 | SPINOR_REG_MT_CFR0V, 1), | |
60 | SPI_MEM_OP_NO_DUMMY, | |
61 | SPI_MEM_OP_DATA_OUT(1, buf, 1)); | |
62 | ||
63 | if (!enable) | |
64 | spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR); | |
65 | ||
66 | ret = spi_mem_exec_op(nor->spimem, &op); | |
67 | if (ret) | |
68 | return ret; | |
69 | ||
70 | /* Read flash ID to make sure the switch was successful. */ | |
71 | op = (struct spi_mem_op) | |
72 | SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDID, 1), | |
73 | SPI_MEM_OP_NO_ADDR, | |
74 | SPI_MEM_OP_DUMMY(enable ? 8 : 0, 1), | |
75 | SPI_MEM_OP_DATA_IN(round_up(nor->info->id_len, 2), | |
76 | buf, 1)); | |
77 | ||
78 | if (enable) | |
79 | spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR); | |
80 | ||
81 | ret = spi_mem_exec_op(nor->spimem, &op); | |
82 | if (ret) | |
83 | return ret; | |
84 | ||
85 | if (memcmp(buf, nor->info->id, nor->info->id_len)) | |
86 | return -EINVAL; | |
87 | ||
88 | return 0; | |
89 | } | |
90 | ||
91 | static void mt35xu512aba_default_init(struct spi_nor *nor) | |
92 | { | |
93 | nor->params->octal_dtr_enable = spi_nor_micron_octal_dtr_enable; | |
94 | } | |
95 | ||
96 | static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) | |
97 | { | |
98 | /* Set the Fast Read settings. */ | |
99 | nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; | |
100 | spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR], | |
101 | 0, 20, SPINOR_OP_MT_DTR_RD, | |
102 | SNOR_PROTO_8_8_8_DTR); | |
103 | ||
104 | nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; | |
105 | nor->params->rdsr_dummy = 8; | |
106 | nor->params->rdsr_addr_nbytes = 0; | |
107 | ||
108 | /* | |
109 | * The BFPT quad enable field is set to a reserved value so the quad | |
110 | * enable function is ignored by spi_nor_parse_bfpt(). Make sure we | |
111 | * disable it. | |
112 | */ | |
113 | nor->params->quad_enable = NULL; | |
114 | } | |
115 | ||
116 | static struct spi_nor_fixups mt35xu512aba_fixups = { | |
117 | .default_init = mt35xu512aba_default_init, | |
118 | .post_sfdp = mt35xu512aba_post_sfdp_fixup, | |
119 | }; | |
120 | ||
15f5c7e5 BB |
121 | static const struct flash_info micron_parts[] = { |
122 | { "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512, | |
123 | SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | | |
ad624dfd PY |
124 | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ | |
125 | SPI_NOR_OCTAL_DTR_PP | | |
126 | SPI_NOR_IO_MODE_EN_VOLATILE) | |
127 | .fixups = &mt35xu512aba_fixups}, | |
15f5c7e5 BB |
128 | { "mt35xu02g", INFO(0x2c5b1c, 0, 128 * 1024, 2048, |
129 | SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ | | |
130 | SPI_NOR_4B_OPCODES) }, | |
131 | }; | |
132 | ||
133 | static const struct flash_info st_parts[] = { | |
134 | { "n25q016a", INFO(0x20bb15, 0, 64 * 1024, 32, | |
135 | SECT_4K | SPI_NOR_QUAD_READ) }, | |
136 | { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, | |
137 | SPI_NOR_QUAD_READ) }, | |
138 | { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, | |
139 | SPI_NOR_QUAD_READ) }, | |
140 | { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, | |
141 | SECT_4K | SPI_NOR_QUAD_READ) }, | |
142 | { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, | |
143 | SECT_4K | SPI_NOR_QUAD_READ) }, | |
144 | { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, | |
150ccc18 XC |
145 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | |
146 | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | | |
147 | SPI_NOR_4BIT_BP | SPI_NOR_BP3_SR_BIT6) }, | |
15f5c7e5 BB |
148 | { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, |
149 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, | |
150 | { "mt25ql256a", INFO6(0x20ba19, 0x104400, 64 * 1024, 512, | |
151 | SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | | |
152 | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, | |
153 | { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | | |
154 | USE_FSR | SPI_NOR_DUAL_READ | | |
155 | SPI_NOR_QUAD_READ) }, | |
156 | { "mt25qu256a", INFO6(0x20bb19, 0x104400, 64 * 1024, 512, | |
157 | SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | | |
158 | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, | |
159 | { "n25q256ax1", INFO(0x20bb19, 0, 64 * 1024, 512, | |
160 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) }, | |
161 | { "mt25ql512a", INFO6(0x20ba20, 0x104400, 64 * 1024, 1024, | |
162 | SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | | |
163 | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, | |
164 | { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, | |
f3f2b7eb JL |
165 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | |
166 | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | | |
167 | SPI_NOR_4BIT_BP | SPI_NOR_BP3_SR_BIT6) }, | |
15f5c7e5 BB |
168 | { "mt25qu512a", INFO6(0x20bb20, 0x104400, 64 * 1024, 1024, |
169 | SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | | |
170 | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, | |
171 | { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, | |
f3f2b7eb JL |
172 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | |
173 | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | | |
174 | SPI_NOR_4BIT_BP | SPI_NOR_BP3_SR_BIT6) }, | |
15f5c7e5 BB |
175 | { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, |
176 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | | |
f80ff131 JL |
177 | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | |
178 | SPI_NOR_4BIT_BP | SPI_NOR_BP3_SR_BIT6 | | |
15f5c7e5 BB |
179 | NO_CHIP_ERASE) }, |
180 | { "n25q00a", INFO(0x20bb21, 0, 64 * 1024, 2048, | |
181 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | | |
182 | NO_CHIP_ERASE) }, | |
183 | { "mt25ql02g", INFO(0x20ba22, 0, 64 * 1024, 4096, | |
184 | SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | | |
185 | NO_CHIP_ERASE) }, | |
186 | { "mt25qu02g", INFO(0x20bb22, 0, 64 * 1024, 4096, | |
1371a80c DC |
187 | SECT_4K | USE_FSR | SPI_NOR_DUAL_READ | |
188 | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) }, | |
15f5c7e5 BB |
189 | |
190 | { "m25p05", INFO(0x202010, 0, 32 * 1024, 2, 0) }, | |
191 | { "m25p10", INFO(0x202011, 0, 32 * 1024, 4, 0) }, | |
192 | { "m25p20", INFO(0x202012, 0, 64 * 1024, 4, 0) }, | |
193 | { "m25p40", INFO(0x202013, 0, 64 * 1024, 8, 0) }, | |
194 | { "m25p80", INFO(0x202014, 0, 64 * 1024, 16, 0) }, | |
195 | { "m25p16", INFO(0x202015, 0, 64 * 1024, 32, 0) }, | |
196 | { "m25p32", INFO(0x202016, 0, 64 * 1024, 64, 0) }, | |
197 | { "m25p64", INFO(0x202017, 0, 64 * 1024, 128, 0) }, | |
198 | { "m25p128", INFO(0x202018, 0, 256 * 1024, 64, 0) }, | |
199 | ||
200 | { "m25p05-nonjedec", INFO(0, 0, 32 * 1024, 2, 0) }, | |
201 | { "m25p10-nonjedec", INFO(0, 0, 32 * 1024, 4, 0) }, | |
202 | { "m25p20-nonjedec", INFO(0, 0, 64 * 1024, 4, 0) }, | |
203 | { "m25p40-nonjedec", INFO(0, 0, 64 * 1024, 8, 0) }, | |
204 | { "m25p80-nonjedec", INFO(0, 0, 64 * 1024, 16, 0) }, | |
205 | { "m25p16-nonjedec", INFO(0, 0, 64 * 1024, 32, 0) }, | |
206 | { "m25p32-nonjedec", INFO(0, 0, 64 * 1024, 64, 0) }, | |
207 | { "m25p64-nonjedec", INFO(0, 0, 64 * 1024, 128, 0) }, | |
208 | { "m25p128-nonjedec", INFO(0, 0, 256 * 1024, 64, 0) }, | |
209 | ||
210 | { "m45pe10", INFO(0x204011, 0, 64 * 1024, 2, 0) }, | |
211 | { "m45pe80", INFO(0x204014, 0, 64 * 1024, 16, 0) }, | |
212 | { "m45pe16", INFO(0x204015, 0, 64 * 1024, 32, 0) }, | |
213 | ||
214 | { "m25pe20", INFO(0x208012, 0, 64 * 1024, 4, 0) }, | |
215 | { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, | |
216 | { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, | |
217 | ||
218 | { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, | |
219 | { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, | |
220 | { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, | |
221 | { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, | |
222 | { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, | |
223 | { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, | |
224 | }; | |
225 | ||
226 | /** | |
227 | * st_micron_set_4byte_addr_mode() - Set 4-byte address mode for ST and Micron | |
228 | * flashes. | |
229 | * @nor: pointer to 'struct spi_nor'. | |
230 | * @enable: true to enter the 4-byte address mode, false to exit the 4-byte | |
231 | * address mode. | |
232 | * | |
233 | * Return: 0 on success, -errno otherwise. | |
234 | */ | |
235 | static int st_micron_set_4byte_addr_mode(struct spi_nor *nor, bool enable) | |
236 | { | |
237 | int ret; | |
238 | ||
239 | ret = spi_nor_write_enable(nor); | |
240 | if (ret) | |
241 | return ret; | |
242 | ||
243 | ret = spi_nor_set_4byte_addr_mode(nor, enable); | |
244 | if (ret) | |
245 | return ret; | |
246 | ||
247 | return spi_nor_write_disable(nor); | |
248 | } | |
249 | ||
250 | static void micron_st_default_init(struct spi_nor *nor) | |
251 | { | |
252 | nor->flags |= SNOR_F_HAS_LOCK; | |
253 | nor->flags &= ~SNOR_F_HAS_16BIT_SR; | |
829ec640 TA |
254 | nor->params->quad_enable = NULL; |
255 | nor->params->set_4byte_addr_mode = st_micron_set_4byte_addr_mode; | |
15f5c7e5 BB |
256 | } |
257 | ||
258 | static const struct spi_nor_fixups micron_st_fixups = { | |
259 | .default_init = micron_st_default_init, | |
260 | }; | |
261 | ||
262 | const struct spi_nor_manufacturer spi_nor_micron = { | |
263 | .name = "micron", | |
264 | .parts = micron_parts, | |
265 | .nparts = ARRAY_SIZE(micron_parts), | |
266 | .fixups = µn_st_fixups, | |
267 | }; | |
268 | ||
269 | const struct spi_nor_manufacturer spi_nor_st = { | |
270 | .name = "st", | |
271 | .parts = st_parts, | |
272 | .nparts = ARRAY_SIZE(st_parts), | |
273 | .fixups = µn_st_fixups, | |
274 | }; |