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 = ¯onix_nor_fixups, 303 }; 304