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
11#define MXIC_NOR_OP_RD_CR2 0x71 /* Read configuration register 2 opcode */
12#define MXIC_NOR_OP_WR_CR2 0x72 /* Write configuration register 2 opcode */
13#define MXIC_NOR_ADDR_CR2_MODE 0x00000000 /* CR2 address for setting spi/sopi/dopi mode */
14#define MXIC_NOR_ADDR_CR2_DC 0x00000300 /* CR2 address for setting dummy cycles */
15#define MXIC_NOR_REG_DOPI_EN 0x2 /* Enable Octal DTR */
16#define MXIC_NOR_REG_SPI_EN 0x0 /* Enable SPI */
17
18/* Convert dummy cycles to bit pattern */
19#define MXIC_NOR_REG_DC(p) \
20 ((20 - (p)) >> 1)
21
22#define MXIC_NOR_WR_CR2(addr, ndata, buf) \
23 SPI_MEM_OP(SPI_MEM_OP_CMD(MXIC_NOR_OP_WR_CR2, 0), \
24 SPI_MEM_OP_ADDR(4, addr, 0), \
25 SPI_MEM_OP_NO_DUMMY, \
26 SPI_MEM_OP_DATA_OUT(ndata, buf, 0))
27
28static int
29mx25l25635_post_bfpt_fixups(struct spi_nor *nor,
30 const struct sfdp_parameter_header *bfpt_header,
31 const struct sfdp_bfpt *bfpt)
32{
33 /*
34 * MX25L25635F supports 4B opcodes but MX25L25635E does not.
35 * Unfortunately, Macronix has re-used the same JEDEC ID for both
36 * variants which prevents us from defining a new entry in the parts
37 * table.
38 * We need a way to differentiate MX25L25635E and MX25L25635F, and it
39 * seems that the F version advertises support for Fast Read 4-4-4 in
40 * its BFPT table.
41 */
42 if (bfpt->dwords[SFDP_DWORD(5)] & BFPT_DWORD5_FAST_READ_4_4_4)
43 nor->flags |= SNOR_F_4B_OPCODES;
44
45 return 0;
46}
47
48static int
49macronix_qpp4b_post_sfdp_fixups(struct spi_nor *nor)
50{
51 /* PP_1_1_4_4B is supported but missing in 4BAIT. */
52 struct spi_nor_flash_parameter *params = nor->params;
53
54 params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
55 spi_nor_set_pp_settings(pp: &params->page_programs[SNOR_CMD_PP_1_1_4],
56 SPINOR_OP_PP_1_1_4_4B, proto: SNOR_PROTO_1_1_4);
57
58 return 0;
59}
60
61static int
62mx25l3255e_late_init_fixups(struct spi_nor *nor)
63{
64 struct spi_nor_flash_parameter *params = nor->params;
65
66 /*
67 * SFDP of MX25L3255E is JESD216, which does not include the Quad
68 * Enable bit Requirement in BFPT. As a result, during BFPT parsing,
69 * the quad_enable method is not set to spi_nor_sr1_bit6_quad_enable.
70 * Therefore, it is necessary to correct this setting by late_init.
71 */
72 params->quad_enable = spi_nor_sr1_bit6_quad_enable;
73
74 /*
75 * In addition, MX25L3255E also supports 1-4-4 page program in 3-byte
76 * address mode. However, since the 3-byte address 1-4-4 page program
77 * is not defined in SFDP, it needs to be configured in late_init.
78 */
79 params->hwcaps.mask |= SNOR_HWCAPS_PP_1_4_4;
80 spi_nor_set_pp_settings(pp: &params->page_programs[SNOR_CMD_PP_1_4_4],
81 SPINOR_OP_PP_1_4_4, proto: SNOR_PROTO_1_4_4);
82
83 return 0;
84}
85
86static const struct spi_nor_fixups mx25l25635_fixups = {
87 .post_bfpt = mx25l25635_post_bfpt_fixups,
88 .post_sfdp = macronix_qpp4b_post_sfdp_fixups,
89};
90
91static const struct spi_nor_fixups macronix_qpp4b_fixups = {
92 .post_sfdp = macronix_qpp4b_post_sfdp_fixups,
93};
94
95static const struct spi_nor_fixups mx25l3255e_fixups = {
96 .late_init = mx25l3255e_late_init_fixups,
97};
98
99static const struct flash_info macronix_nor_parts[] = {
100 {
101 .id = SNOR_ID(0xc2, 0x20, 0x10),
102 .name = "mx25l512e",
103 .size = SZ_64K,
104 .no_sfdp_flags = SECT_4K,
105 }, {
106 .id = SNOR_ID(0xc2, 0x20, 0x12),
107 .name = "mx25l2005a",
108 .size = SZ_256K,
109 .no_sfdp_flags = SECT_4K,
110 }, {
111 .id = SNOR_ID(0xc2, 0x20, 0x13),
112 .name = "mx25l4005a",
113 .size = SZ_512K,
114 .no_sfdp_flags = SECT_4K,
115 }, {
116 .id = SNOR_ID(0xc2, 0x20, 0x14),
117 .name = "mx25l8005",
118 .size = SZ_1M,
119 }, {
120 /* MX25L1606E */
121 .id = SNOR_ID(0xc2, 0x20, 0x15),
122 }, {
123 .id = SNOR_ID(0xc2, 0x20, 0x16),
124 .name = "mx25l3205d",
125 .size = SZ_4M,
126 .no_sfdp_flags = SECT_4K,
127 }, {
128 .id = SNOR_ID(0xc2, 0x20, 0x17),
129 .name = "mx25l6405d",
130 .size = SZ_8M,
131 .no_sfdp_flags = SECT_4K,
132 }, {
133 /* MX25L12805D */
134 .id = SNOR_ID(0xc2, 0x20, 0x18),
135 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP,
136 }, {
137 /* MX25L25635E, MX25L25645G */
138 .id = SNOR_ID(0xc2, 0x20, 0x19),
139 .fixups = &mx25l25635_fixups
140 }, {
141 /* MX66L51235F */
142 .id = SNOR_ID(0xc2, 0x20, 0x1a),
143 .fixup_flags = SPI_NOR_4B_OPCODES,
144 .fixups = &macronix_qpp4b_fixups,
145 }, {
146 /* MX66L1G45G */
147 .id = SNOR_ID(0xc2, 0x20, 0x1b),
148 .fixups = &macronix_qpp4b_fixups,
149 }, {
150 /* MX66L2G45G */
151 .id = SNOR_ID(0xc2, 0x20, 0x1c),
152 .fixups = &macronix_qpp4b_fixups,
153 }, {
154 .id = SNOR_ID(0xc2, 0x23, 0x14),
155 .name = "mx25v8035f",
156 .size = SZ_1M,
157 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
158 }, {
159 .id = SNOR_ID(0xc2, 0x25, 0x32),
160 .name = "mx25u2033e",
161 .size = SZ_256K,
162 .no_sfdp_flags = SECT_4K,
163 }, {
164 .id = SNOR_ID(0xc2, 0x25, 0x33),
165 .name = "mx25u4035",
166 .size = SZ_512K,
167 .no_sfdp_flags = SECT_4K,
168 }, {
169 .id = SNOR_ID(0xc2, 0x25, 0x34),
170 .name = "mx25u8035",
171 .size = SZ_1M,
172 .no_sfdp_flags = SECT_4K,
173 }, {
174 .id = SNOR_ID(0xc2, 0x25, 0x36),
175 .name = "mx25u3235f",
176 .size = SZ_4M,
177 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
178 }, {
179 .id = SNOR_ID(0xc2, 0x25, 0x37),
180 .name = "mx25u6435f",
181 .size = SZ_8M,
182 .no_sfdp_flags = SECT_4K,
183 }, {
184 .id = SNOR_ID(0xc2, 0x25, 0x38),
185 .name = "mx25u12835f",
186 .size = SZ_16M,
187 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
188 }, {
189 /* MX25U51245G */
190 .id = SNOR_ID(0xc2, 0x25, 0x3a),
191 .fixups = &macronix_qpp4b_fixups,
192 }, {
193 /* MX66U1G45G */
194 .id = SNOR_ID(0xc2, 0x25, 0x3b),
195 .fixups = &macronix_qpp4b_fixups,
196 }, {
197 /* MX66U2G45G */
198 .id = SNOR_ID(0xc2, 0x25, 0x3c),
199 .fixups = &macronix_qpp4b_fixups,
200 }, {
201 .id = SNOR_ID(0xc2, 0x26, 0x18),
202 .name = "mx25l12855e",
203 .size = SZ_16M,
204 }, {
205 .id = SNOR_ID(0xc2, 0x26, 0x19),
206 .name = "mx25l25655e",
207 .size = SZ_32M,
208 }, {
209 .id = SNOR_ID(0xc2, 0x26, 0x1b),
210 .name = "mx66l1g55g",
211 .size = SZ_128M,
212 .no_sfdp_flags = SPI_NOR_QUAD_READ,
213 }, {
214 .id = SNOR_ID(0xc2, 0x28, 0x15),
215 .name = "mx25r1635f",
216 .size = SZ_2M,
217 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
218 }, {
219 .id = SNOR_ID(0xc2, 0x28, 0x16),
220 .name = "mx25r3235f",
221 .size = SZ_4M,
222 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
223 }, {
224 /* MX25UW51245G */
225 .id = SNOR_ID(0xc2, 0x81, 0x3a),
226 .n_banks = 4,
227 .flags = SPI_NOR_RWW,
228 }, {
229 /* MX25L3255E */
230 .id = SNOR_ID(0xc2, 0x9e, 0x16),
231 .fixups = &mx25l3255e_fixups,
232 },
233 /*
234 * This spares us of adding new flash entries for flashes that can be
235 * initialized solely based on the SFDP data, but still need the
236 * manufacturer hooks to set parameters that can't be discovered at SFDP
237 * parsing time.
238 */
239 { .id = SNOR_ID(0xc2) }
240};
241
242static int macronix_nor_octal_dtr_en(struct spi_nor *nor)
243{
244 struct spi_mem_op op;
245 u8 *buf = nor->bouncebuf, i;
246 int ret;
247
248 /* Use dummy cycles which is parse by SFDP and convert to bit pattern. */
249 buf[0] = MXIC_NOR_REG_DC(nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].num_wait_states);
250 op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_DC, 1, buf);
251 ret = spi_nor_write_any_volatile_reg(nor, op: &op, proto: nor->reg_proto);
252 if (ret)
253 return ret;
254
255 /* Set the octal and DTR enable bits. */
256 buf[0] = MXIC_NOR_REG_DOPI_EN;
257 op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 1, buf);
258 ret = spi_nor_write_any_volatile_reg(nor, op: &op, proto: nor->reg_proto);
259 if (ret)
260 return ret;
261
262 /* Read flash ID to make sure the switch was successful. */
263 ret = spi_nor_read_id(nor, naddr: nor->addr_nbytes, ndummy: 4, id: buf,
264 reg_proto: SNOR_PROTO_8_8_8_DTR);
265 if (ret) {
266 dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret);
267 return ret;
268 }
269
270 /* Macronix SPI-NOR flash 8D-8D-8D read ID would get 6 bytes data A-A-B-B-C-C */
271 for (i = 0; i < nor->info->id->len; i++)
272 if (buf[i * 2] != buf[(i * 2) + 1] || buf[i * 2] != nor->info->id->bytes[i])
273 return -EINVAL;
274
275 return 0;
276}
277
278static int macronix_nor_octal_dtr_dis(struct spi_nor *nor)
279{
280 struct spi_mem_op op;
281 u8 *buf = nor->bouncebuf;
282 int ret;
283
284 /*
285 * The register is 1-byte wide, but 1-byte transactions are not
286 * allowed in 8D-8D-8D mode. Since there is no register at the
287 * next location, just initialize the value to 0 and let the
288 * transaction go on.
289 */
290 buf[0] = MXIC_NOR_REG_SPI_EN;
291 buf[1] = 0x0;
292 op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 2, buf);
293 ret = spi_nor_write_any_volatile_reg(nor, op: &op, proto: SNOR_PROTO_8_8_8_DTR);
294 if (ret)
295 return ret;
296
297 /* Read flash ID to make sure the switch was successful. */
298 ret = spi_nor_read_id(nor, naddr: 0, ndummy: 0, id: buf, reg_proto: SNOR_PROTO_1_1_1);
299 if (ret) {
300 dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret);
301 return ret;
302 }
303
304 if (memcmp(p: buf, q: nor->info->id->bytes, size: nor->info->id->len))
305 return -EINVAL;
306
307 return 0;
308}
309
310static int macronix_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
311{
312 return enable ? macronix_nor_octal_dtr_en(nor) : macronix_nor_octal_dtr_dis(nor);
313}
314
315static void macronix_nor_default_init(struct spi_nor *nor)
316{
317 nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
318}
319
320static int macronix_nor_late_init(struct spi_nor *nor)
321{
322 if (!nor->params->set_4byte_addr_mode)
323 nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
324 nor->params->set_octal_dtr = macronix_nor_set_octal_dtr;
325
326 return 0;
327}
328
329static const struct spi_nor_fixups macronix_nor_fixups = {
330 .default_init = macronix_nor_default_init,
331 .late_init = macronix_nor_late_init,
332};
333
334const struct spi_nor_manufacturer spi_nor_macronix = {
335 .name = "macronix",
336 .parts = macronix_nor_parts,
337 .nparts = ARRAY_SIZE(macronix_nor_parts),
338 .fixups = &macronix_nor_fixups,
339};
340

source code of linux/drivers/mtd/spi-nor/macronix.c