]> Git Repo - linux.git/blob - drivers/mtd/spi-nor/macronix.c
Linux 6.14-rc3
[linux.git] / drivers / mtd / spi-nor / macronix.c
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
28 static int
29 mx25l25635_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
48 static const struct spi_nor_fixups mx25l25635_fixups = {
49         .post_bfpt = mx25l25635_post_bfpt_fixups,
50 };
51
52 static const struct flash_info macronix_nor_parts[] = {
53         {
54                 .id = SNOR_ID(0xc2, 0x20, 0x10),
55                 .name = "mx25l512e",
56                 .size = SZ_64K,
57                 .no_sfdp_flags = SECT_4K,
58         }, {
59                 .id = SNOR_ID(0xc2, 0x20, 0x12),
60                 .name = "mx25l2005a",
61                 .size = SZ_256K,
62                 .no_sfdp_flags = SECT_4K,
63         }, {
64                 .id = SNOR_ID(0xc2, 0x20, 0x13),
65                 .name = "mx25l4005a",
66                 .size = SZ_512K,
67                 .no_sfdp_flags = SECT_4K,
68         }, {
69                 .id = SNOR_ID(0xc2, 0x20, 0x14),
70                 .name = "mx25l8005",
71                 .size = SZ_1M,
72         }, {
73                 .id = SNOR_ID(0xc2, 0x20, 0x15),
74                 .name = "mx25l1606e",
75                 .size = SZ_2M,
76                 .no_sfdp_flags = SECT_4K,
77         }, {
78                 .id = SNOR_ID(0xc2, 0x20, 0x16),
79                 .name = "mx25l3205d",
80                 .size = SZ_4M,
81                 .no_sfdp_flags = SECT_4K,
82         }, {
83                 .id = SNOR_ID(0xc2, 0x20, 0x17),
84                 .name = "mx25l6405d",
85                 .size = SZ_8M,
86                 .no_sfdp_flags = SECT_4K,
87         }, {
88                 .id = SNOR_ID(0xc2, 0x20, 0x18),
89                 .name = "mx25l12805d",
90                 .size = SZ_16M,
91                 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP,
92                 .no_sfdp_flags = SECT_4K,
93         }, {
94                 .id = SNOR_ID(0xc2, 0x20, 0x19),
95                 .name = "mx25l25635e",
96                 .size = SZ_32M,
97                 .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
98                 .fixups = &mx25l25635_fixups
99         }, {
100                 .id = SNOR_ID(0xc2, 0x20, 0x1a),
101                 .name = "mx66l51235f",
102                 .size = SZ_64M,
103                 .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
104                 .fixup_flags = SPI_NOR_4B_OPCODES,
105         }, {
106                 .id = SNOR_ID(0xc2, 0x20, 0x1b),
107                 .name = "mx66l1g45g",
108                 .size = SZ_128M,
109                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
110         }, {
111                 .id = SNOR_ID(0xc2, 0x23, 0x14),
112                 .name = "mx25v8035f",
113                 .size = SZ_1M,
114                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
115         }, {
116                 .id = SNOR_ID(0xc2, 0x25, 0x32),
117                 .name = "mx25u2033e",
118                 .size = SZ_256K,
119                 .no_sfdp_flags = SECT_4K,
120         }, {
121                 .id = SNOR_ID(0xc2, 0x25, 0x33),
122                 .name = "mx25u4035",
123                 .size = SZ_512K,
124                 .no_sfdp_flags = SECT_4K,
125         }, {
126                 .id = SNOR_ID(0xc2, 0x25, 0x34),
127                 .name = "mx25u8035",
128                 .size = SZ_1M,
129                 .no_sfdp_flags = SECT_4K,
130         }, {
131                 .id = SNOR_ID(0xc2, 0x25, 0x36),
132                 .name = "mx25u3235f",
133                 .size = SZ_4M,
134                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
135         }, {
136                 .id = SNOR_ID(0xc2, 0x25, 0x37),
137                 .name = "mx25u6435f",
138                 .size = SZ_8M,
139                 .no_sfdp_flags = SECT_4K,
140         }, {
141                 .id = SNOR_ID(0xc2, 0x25, 0x38),
142                 .name = "mx25u12835f",
143                 .size = SZ_16M,
144                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
145         }, {
146                 .id = SNOR_ID(0xc2, 0x25, 0x3a),
147                 .name = "mx25u51245g",
148                 .size = SZ_64M,
149                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
150                 .fixup_flags = SPI_NOR_4B_OPCODES,
151         }, {
152                 .id = SNOR_ID(0xc2, 0x25, 0x3a),
153                 .name = "mx66u51235f",
154                 .size = SZ_64M,
155                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
156                 .fixup_flags = SPI_NOR_4B_OPCODES,
157         }, {
158                 .id = SNOR_ID(0xc2, 0x25, 0x3c),
159                 .name = "mx66u2g45g",
160                 .size = SZ_256M,
161                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
162                 .fixup_flags = SPI_NOR_4B_OPCODES,
163         }, {
164                 .id = SNOR_ID(0xc2, 0x26, 0x18),
165                 .name = "mx25l12855e",
166                 .size = SZ_16M,
167         }, {
168                 .id = SNOR_ID(0xc2, 0x26, 0x19),
169                 .name = "mx25l25655e",
170                 .size = SZ_32M,
171         }, {
172                 .id = SNOR_ID(0xc2, 0x26, 0x1b),
173                 .name = "mx66l1g55g",
174                 .size = SZ_128M,
175                 .no_sfdp_flags = SPI_NOR_QUAD_READ,
176         }, {
177                 .id = SNOR_ID(0xc2, 0x28, 0x15),
178                 .name = "mx25r1635f",
179                 .size = SZ_2M,
180                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
181         }, {
182                 .id = SNOR_ID(0xc2, 0x28, 0x16),
183                 .name = "mx25r3235f",
184                 .size = SZ_4M,
185                 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
186         }, {
187                 .id = SNOR_ID(0xc2, 0x81, 0x3a),
188                 .name = "mx25uw51245g",
189                 .n_banks = 4,
190                 .flags = SPI_NOR_RWW,
191         }, {
192                 .id = SNOR_ID(0xc2, 0x9e, 0x16),
193                 .name = "mx25l3255e",
194                 .size = SZ_4M,
195                 .no_sfdp_flags = SECT_4K,
196         },
197         /*
198          * This spares us of adding new flash entries for flashes that can be
199          * initialized solely based on the SFDP data, but still need the
200          * manufacturer hooks to set parameters that can't be discovered at SFDP
201          * parsing time.
202          */
203         { .id = SNOR_ID(0xc2) }
204 };
205
206 static int macronix_nor_octal_dtr_en(struct spi_nor *nor)
207 {
208         struct spi_mem_op op;
209         u8 *buf = nor->bouncebuf, i;
210         int ret;
211
212         /* Use dummy cycles which is parse by SFDP and convert to bit pattern. */
213         buf[0] = MXIC_NOR_REG_DC(nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].num_wait_states);
214         op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_DC, 1, buf);
215         ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
216         if (ret)
217                 return ret;
218
219         /* Set the octal and DTR enable bits. */
220         buf[0] = MXIC_NOR_REG_DOPI_EN;
221         op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 1, buf);
222         ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
223         if (ret)
224                 return ret;
225
226         /* Read flash ID to make sure the switch was successful. */
227         ret = spi_nor_read_id(nor, nor->addr_nbytes, 4, buf,
228                               SNOR_PROTO_8_8_8_DTR);
229         if (ret) {
230                 dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret);
231                 return ret;
232         }
233
234         /* Macronix SPI-NOR flash 8D-8D-8D read ID would get 6 bytes data A-A-B-B-C-C */
235         for (i = 0; i < nor->info->id->len; i++)
236                 if (buf[i * 2] != buf[(i * 2) + 1] || buf[i * 2] != nor->info->id->bytes[i])
237                         return -EINVAL;
238
239         return 0;
240 }
241
242 static int macronix_nor_octal_dtr_dis(struct spi_nor *nor)
243 {
244         struct spi_mem_op op;
245         u8 *buf = nor->bouncebuf;
246         int ret;
247
248         /*
249          * The register is 1-byte wide, but 1-byte transactions are not
250          * allowed in 8D-8D-8D mode. Since there is no register at the
251          * next location, just initialize the value to 0 and let the
252          * transaction go on.
253          */
254         buf[0] = MXIC_NOR_REG_SPI_EN;
255         buf[1] = 0x0;
256         op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 2, buf);
257         ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
258         if (ret)
259                 return ret;
260
261         /* Read flash ID to make sure the switch was successful. */
262         ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1);
263         if (ret) {
264                 dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret);
265                 return ret;
266         }
267
268         if (memcmp(buf, nor->info->id->bytes, nor->info->id->len))
269                 return -EINVAL;
270
271         return 0;
272 }
273
274 static int macronix_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
275 {
276         return enable ? macronix_nor_octal_dtr_en(nor) : macronix_nor_octal_dtr_dis(nor);
277 }
278
279 static void macronix_nor_default_init(struct spi_nor *nor)
280 {
281         nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
282 }
283
284 static int macronix_nor_late_init(struct spi_nor *nor)
285 {
286         if (!nor->params->set_4byte_addr_mode)
287                 nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b;
288         nor->params->set_octal_dtr = macronix_nor_set_octal_dtr;
289
290         return 0;
291 }
292
293 static const struct spi_nor_fixups macronix_nor_fixups = {
294         .default_init = macronix_nor_default_init,
295         .late_init = macronix_nor_late_init,
296 };
297
298 const struct spi_nor_manufacturer spi_nor_macronix = {
299         .name = "macronix",
300         .parts = macronix_nor_parts,
301         .nparts = ARRAY_SIZE(macronix_nor_parts),
302         .fixups = &macronix_nor_fixups,
303 };
This page took 0.05147 seconds and 4 git commands to generate.