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, 0x39), 147 .name = "mx25u25635f", 148 .size = SZ_32M, 149 .no_sfdp_flags = SECT_4K, 150 .fixup_flags = SPI_NOR_4B_OPCODES, 151 }, { 152 .id = SNOR_ID(0xc2, 0x25, 0x3a), 153 .name = "mx25u51245g", 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, 0x3a), 159 .name = "mx66u51235f", 160 .size = SZ_64M, 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, 0x25, 0x3c), 165 .name = "mx66u2g45g", 166 .size = SZ_256M, 167 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 168 .fixup_flags = SPI_NOR_4B_OPCODES, 169 }, { 170 .id = SNOR_ID(0xc2, 0x26, 0x18), 171 .name = "mx25l12855e", 172 .size = SZ_16M, 173 }, { 174 .id = SNOR_ID(0xc2, 0x26, 0x19), 175 .name = "mx25l25655e", 176 .size = SZ_32M, 177 }, { 178 .id = SNOR_ID(0xc2, 0x26, 0x1b), 179 .name = "mx66l1g55g", 180 .size = SZ_128M, 181 .no_sfdp_flags = SPI_NOR_QUAD_READ, 182 }, { 183 .id = SNOR_ID(0xc2, 0x28, 0x15), 184 .name = "mx25r1635f", 185 .size = SZ_2M, 186 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 187 }, { 188 .id = SNOR_ID(0xc2, 0x28, 0x16), 189 .name = "mx25r3235f", 190 .size = SZ_4M, 191 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 192 }, { 193 .id = SNOR_ID(0xc2, 0x81, 0x3a), 194 .name = "mx25uw51245g", 195 .n_banks = 4, 196 .flags = SPI_NOR_RWW, 197 }, { 198 .id = SNOR_ID(0xc2, 0x9e, 0x16), 199 .name = "mx25l3255e", 200 .size = SZ_4M, 201 .no_sfdp_flags = SECT_4K, 202 }, 203 /* 204 * This spares us of adding new flash entries for flashes that can be 205 * initialized solely based on the SFDP data, but still need the 206 * manufacturer hooks to set parameters that can't be discovered at SFDP 207 * parsing time. 208 */ 209 { .id = SNOR_ID(0xc2) } 210 }; 211 212 static int macronix_nor_octal_dtr_en(struct spi_nor *nor) 213 { 214 struct spi_mem_op op; 215 u8 *buf = nor->bouncebuf, i; 216 int ret; 217 218 /* Use dummy cycles which is parse by SFDP and convert to bit pattern. */ 219 buf[0] = MXIC_NOR_REG_DC(nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].num_wait_states); 220 op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_DC, 1, buf); 221 ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); 222 if (ret) 223 return ret; 224 225 /* Set the octal and DTR enable bits. */ 226 buf[0] = MXIC_NOR_REG_DOPI_EN; 227 op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 1, buf); 228 ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); 229 if (ret) 230 return ret; 231 232 /* Read flash ID to make sure the switch was successful. */ 233 ret = spi_nor_read_id(nor, 4, 4, buf, SNOR_PROTO_8_8_8_DTR); 234 if (ret) { 235 dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); 236 return ret; 237 } 238 239 /* Macronix SPI-NOR flash 8D-8D-8D read ID would get 6 bytes data A-A-B-B-C-C */ 240 for (i = 0; i < nor->info->id->len; i++) 241 if (buf[i * 2] != buf[(i * 2) + 1] || buf[i * 2] != nor->info->id->bytes[i]) 242 return -EINVAL; 243 244 return 0; 245 } 246 247 static int macronix_nor_octal_dtr_dis(struct spi_nor *nor) 248 { 249 struct spi_mem_op op; 250 u8 *buf = nor->bouncebuf; 251 int ret; 252 253 /* 254 * The register is 1-byte wide, but 1-byte transactions are not 255 * allowed in 8D-8D-8D mode. Since there is no register at the 256 * next location, just initialize the value to 0 and let the 257 * transaction go on. 258 */ 259 buf[0] = MXIC_NOR_REG_SPI_EN; 260 buf[1] = 0x0; 261 op = (struct spi_mem_op)MXIC_NOR_WR_CR2(MXIC_NOR_ADDR_CR2_MODE, 2, buf); 262 ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); 263 if (ret) 264 return ret; 265 266 /* Read flash ID to make sure the switch was successful. */ 267 ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); 268 if (ret) { 269 dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret); 270 return ret; 271 } 272 273 if (memcmp(buf, nor->info->id->bytes, nor->info->id->len)) 274 return -EINVAL; 275 276 return 0; 277 } 278 279 static int macronix_nor_set_octal_dtr(struct spi_nor *nor, bool enable) 280 { 281 return enable ? macronix_nor_octal_dtr_en(nor) : macronix_nor_octal_dtr_dis(nor); 282 } 283 284 static void macronix_nor_default_init(struct spi_nor *nor) 285 { 286 nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable; 287 } 288 289 static int macronix_nor_late_init(struct spi_nor *nor) 290 { 291 if (!nor->params->set_4byte_addr_mode) 292 nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_en4b_ex4b; 293 nor->params->set_octal_dtr = macronix_nor_set_octal_dtr; 294 295 return 0; 296 } 297 298 static const struct spi_nor_fixups macronix_nor_fixups = { 299 .default_init = macronix_nor_default_init, 300 .late_init = macronix_nor_late_init, 301 }; 302 303 const struct spi_nor_manufacturer spi_nor_macronix = { 304 .name = "macronix", 305 .parts = macronix_nor_parts, 306 .nparts = ARRAY_SIZE(macronix_nor_parts), 307 .fixups = ¯onix_nor_fixups, 308 }; 309