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 WINBOND_NOR_OP_RDEAR 0xc8 /* Read Extended Address Register */ 12 #define WINBOND_NOR_OP_WREAR 0xc5 /* Write Extended Address Register */ 13 #define WINBOND_NOR_OP_SELDIE 0xc2 /* Select active die */ 14 15 #define WINBOND_NOR_WREAR_OP(buf) \ 16 SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_WREAR, 0), \ 17 SPI_MEM_OP_NO_ADDR, \ 18 SPI_MEM_OP_NO_DUMMY, \ 19 SPI_MEM_OP_DATA_OUT(1, buf, 0)) 20 21 #define WINBOND_NOR_SELDIE_OP(buf) \ 22 SPI_MEM_OP(SPI_MEM_OP_CMD(WINBOND_NOR_OP_SELDIE, 0), \ 23 SPI_MEM_OP_NO_ADDR, \ 24 SPI_MEM_OP_NO_DUMMY, \ 25 SPI_MEM_OP_DATA_OUT(1, buf, 0)) 26 27 static int 28 w25q128_post_bfpt_fixups(struct spi_nor *nor, 29 const struct sfdp_parameter_header *bfpt_header, 30 const struct sfdp_bfpt *bfpt) 31 { 32 /* 33 * Zetta ZD25Q128C is a clone of the Winbond device. But the encoded 34 * size is really wrong. It seems that they confused Mbit with MiB. 35 * Thus the flash is discovered as a 2MiB device. 36 */ 37 if (bfpt_header->major == SFDP_JESD216_MAJOR && 38 bfpt_header->minor == SFDP_JESD216_MINOR && 39 nor->params->size == SZ_2M && 40 nor->params->erase_map.regions[0].size == SZ_2M) { 41 nor->params->size = SZ_16M; 42 nor->params->erase_map.regions[0].size = SZ_16M; 43 } 44 45 return 0; 46 } 47 48 static const struct spi_nor_fixups w25q128_fixups = { 49 .post_bfpt = w25q128_post_bfpt_fixups, 50 }; 51 52 static int 53 w25q256_post_bfpt_fixups(struct spi_nor *nor, 54 const struct sfdp_parameter_header *bfpt_header, 55 const struct sfdp_bfpt *bfpt) 56 { 57 /* 58 * W25Q256JV supports 4B opcodes but W25Q256FV does not. 59 * Unfortunately, Winbond has re-used the same JEDEC ID for both 60 * variants which prevents us from defining a new entry in the parts 61 * table. 62 * To differentiate between W25Q256JV and W25Q256FV check SFDP header 63 * version: only JV has JESD216A compliant structure (version 5). 64 */ 65 if (bfpt_header->major == SFDP_JESD216_MAJOR && 66 bfpt_header->minor == SFDP_JESD216A_MINOR) 67 nor->flags |= SNOR_F_4B_OPCODES; 68 69 return 0; 70 } 71 72 static const struct spi_nor_fixups w25q256_fixups = { 73 .post_bfpt = w25q256_post_bfpt_fixups, 74 }; 75 76 /** 77 * winbond_nor_select_die() - Set active die. 78 * @nor: pointer to 'struct spi_nor'. 79 * @die: die to set active. 80 * 81 * Certain Winbond chips feature more than a single die. This is mostly hidden 82 * to the user, except that some chips may experience time deviation when 83 * modifying the status bits between dies, which in some corner cases may 84 * produce problematic races. Being able to explicitly select a die to check its 85 * state in this case may be useful. 86 * 87 * Return: 0 on success, -errno otherwise. 88 */ 89 static int winbond_nor_select_die(struct spi_nor *nor, u8 die) 90 { 91 int ret; 92 93 nor->bouncebuf[0] = die; 94 95 if (nor->spimem) { 96 struct spi_mem_op op = WINBOND_NOR_SELDIE_OP(nor->bouncebuf); 97 98 spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); 99 100 ret = spi_mem_exec_op(nor->spimem, &op); 101 } else { 102 ret = spi_nor_controller_ops_write_reg(nor, 103 WINBOND_NOR_OP_SELDIE, 104 nor->bouncebuf, 1); 105 } 106 107 if (ret) 108 dev_dbg(nor->dev, "error %d selecting die %d\n", ret, die); 109 110 return ret; 111 } 112 113 static int winbond_nor_multi_die_ready(struct spi_nor *nor) 114 { 115 int ret, i; 116 117 for (i = 0; i < nor->params->n_dice; i++) { 118 ret = winbond_nor_select_die(nor, i); 119 if (ret) 120 return ret; 121 122 ret = spi_nor_sr_ready(nor); 123 if (ret <= 0) 124 return ret; 125 } 126 127 return 1; 128 } 129 130 static int 131 winbond_nor_multi_die_post_sfdp_fixups(struct spi_nor *nor) 132 { 133 /* 134 * SFDP supports dice numbers, but this information is only available in 135 * optional additional tables which are not provided by these chips. 136 * Dice number has an impact though, because these devices need extra 137 * care when reading the busy bit. 138 */ 139 nor->params->n_dice = nor->params->size / SZ_64M; 140 nor->params->ready = winbond_nor_multi_die_ready; 141 142 return 0; 143 } 144 145 static const struct spi_nor_fixups winbond_nor_multi_die_fixups = { 146 .post_sfdp = winbond_nor_multi_die_post_sfdp_fixups, 147 }; 148 149 static const struct flash_info winbond_nor_parts[] = { 150 { 151 .id = SNOR_ID(0xef, 0x30, 0x10), 152 .name = "w25x05", 153 .size = SZ_64K, 154 .no_sfdp_flags = SECT_4K, 155 }, { 156 .id = SNOR_ID(0xef, 0x30, 0x11), 157 .name = "w25x10", 158 .size = SZ_128K, 159 .no_sfdp_flags = SECT_4K, 160 }, { 161 .id = SNOR_ID(0xef, 0x30, 0x12), 162 .name = "w25x20", 163 .size = SZ_256K, 164 .no_sfdp_flags = SECT_4K, 165 }, { 166 .id = SNOR_ID(0xef, 0x30, 0x13), 167 .name = "w25x40", 168 .size = SZ_512K, 169 .no_sfdp_flags = SECT_4K, 170 }, { 171 .id = SNOR_ID(0xef, 0x30, 0x14), 172 .name = "w25x80", 173 .size = SZ_1M, 174 .no_sfdp_flags = SECT_4K, 175 }, { 176 .id = SNOR_ID(0xef, 0x30, 0x15), 177 .name = "w25x16", 178 .size = SZ_2M, 179 .no_sfdp_flags = SECT_4K, 180 }, { 181 .id = SNOR_ID(0xef, 0x30, 0x16), 182 .name = "w25x32", 183 .size = SZ_4M, 184 .no_sfdp_flags = SECT_4K, 185 }, { 186 .id = SNOR_ID(0xef, 0x30, 0x17), 187 .name = "w25x64", 188 .size = SZ_8M, 189 .no_sfdp_flags = SECT_4K, 190 }, { 191 .id = SNOR_ID(0xef, 0x40, 0x12), 192 .name = "w25q20cl", 193 .size = SZ_256K, 194 .no_sfdp_flags = SECT_4K, 195 }, { 196 .id = SNOR_ID(0xef, 0x40, 0x14), 197 .name = "w25q80bl", 198 .size = SZ_1M, 199 .no_sfdp_flags = SECT_4K, 200 }, { 201 .id = SNOR_ID(0xef, 0x40, 0x16), 202 .name = "w25q32", 203 .size = SZ_4M, 204 .no_sfdp_flags = SECT_4K, 205 }, { 206 .id = SNOR_ID(0xef, 0x40, 0x17), 207 .name = "w25q64", 208 .size = SZ_8M, 209 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 210 }, { 211 .id = SNOR_ID(0xef, 0x40, 0x18), 212 /* Flavors w/ and w/o SFDP. */ 213 .name = "w25q128", 214 .size = SZ_16M, 215 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 216 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 217 .fixups = &w25q128_fixups, 218 }, { 219 .id = SNOR_ID(0xef, 0x40, 0x19), 220 .name = "w25q256", 221 .size = SZ_32M, 222 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 223 .fixups = &w25q256_fixups, 224 }, { 225 .id = SNOR_ID(0xef, 0x40, 0x20), 226 .name = "w25q512jvq", 227 .size = SZ_64M, 228 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 229 }, { 230 /* W25Q01JV */ 231 .id = SNOR_ID(0xef, 0x40, 0x21), 232 .fixups = &winbond_nor_multi_die_fixups, 233 }, { 234 .id = SNOR_ID(0xef, 0x50, 0x12), 235 .name = "w25q20bw", 236 .size = SZ_256K, 237 .no_sfdp_flags = SECT_4K, 238 }, { 239 .id = SNOR_ID(0xef, 0x50, 0x14), 240 .name = "w25q80", 241 .size = SZ_1M, 242 .no_sfdp_flags = SECT_4K, 243 }, { 244 .id = SNOR_ID(0xef, 0x60, 0x12), 245 .name = "w25q20ew", 246 .size = SZ_256K, 247 .no_sfdp_flags = SECT_4K, 248 }, { 249 .id = SNOR_ID(0xef, 0x60, 0x15), 250 .name = "w25q16dw", 251 .size = SZ_2M, 252 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 253 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 254 }, { 255 .id = SNOR_ID(0xef, 0x60, 0x16), 256 .name = "w25q32dw", 257 .size = SZ_4M, 258 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 259 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 260 .otp = SNOR_OTP(256, 3, 0x1000, 0x1000), 261 }, { 262 .id = SNOR_ID(0xef, 0x60, 0x17), 263 .name = "w25q64dw", 264 .size = SZ_8M, 265 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 266 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 267 }, { 268 .id = SNOR_ID(0xef, 0x60, 0x18), 269 .name = "w25q128fw", 270 .size = SZ_16M, 271 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 272 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 273 }, { 274 .id = SNOR_ID(0xef, 0x60, 0x19), 275 .name = "w25q256jw", 276 .size = SZ_32M, 277 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 278 }, { 279 .id = SNOR_ID(0xef, 0x60, 0x20), 280 .name = "w25q512nwq", 281 .otp = SNOR_OTP(256, 3, 0x1000, 0x1000), 282 }, { 283 .id = SNOR_ID(0xef, 0x70, 0x15), 284 .name = "w25q16jv-im/jm", 285 .size = SZ_2M, 286 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 287 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 288 }, { 289 .id = SNOR_ID(0xef, 0x70, 0x16), 290 .name = "w25q32jv", 291 .size = SZ_4M, 292 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 293 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 294 }, { 295 .id = SNOR_ID(0xef, 0x70, 0x17), 296 .name = "w25q64jvm", 297 .size = SZ_8M, 298 .no_sfdp_flags = SECT_4K, 299 }, { 300 .id = SNOR_ID(0xef, 0x70, 0x18), 301 .name = "w25q128jv", 302 .size = SZ_16M, 303 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 304 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 305 }, { 306 .id = SNOR_ID(0xef, 0x70, 0x19), 307 .name = "w25q256jvm", 308 }, { 309 /* W25Q02JV */ 310 .id = SNOR_ID(0xef, 0x70, 0x22), 311 .fixups = &winbond_nor_multi_die_fixups, 312 }, { 313 .id = SNOR_ID(0xef, 0x71, 0x19), 314 .name = "w25m512jv", 315 .size = SZ_64M, 316 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 317 }, { 318 .id = SNOR_ID(0xef, 0x80, 0x16), 319 .name = "w25q32jwm", 320 .size = SZ_4M, 321 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 322 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 323 .otp = SNOR_OTP(256, 3, 0x1000, 0x1000), 324 }, { 325 .id = SNOR_ID(0xef, 0x80, 0x17), 326 .name = "w25q64jwm", 327 .size = SZ_8M, 328 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 329 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 330 }, { 331 .id = SNOR_ID(0xef, 0x80, 0x18), 332 .name = "w25q128jwm", 333 .size = SZ_16M, 334 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 335 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 336 }, { 337 .id = SNOR_ID(0xef, 0x80, 0x19), 338 .name = "w25q256jwm", 339 .size = SZ_32M, 340 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, 341 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, 342 }, { 343 .id = SNOR_ID(0xef, 0x80, 0x20), 344 .name = "w25q512nwm", 345 .otp = SNOR_OTP(256, 3, 0x1000, 0x1000), 346 }, 347 }; 348 349 /** 350 * winbond_nor_write_ear() - Write Extended Address Register. 351 * @nor: pointer to 'struct spi_nor'. 352 * @ear: value to write to the Extended Address Register. 353 * 354 * Return: 0 on success, -errno otherwise. 355 */ 356 static int winbond_nor_write_ear(struct spi_nor *nor, u8 ear) 357 { 358 int ret; 359 360 nor->bouncebuf[0] = ear; 361 362 if (nor->spimem) { 363 struct spi_mem_op op = WINBOND_NOR_WREAR_OP(nor->bouncebuf); 364 365 spi_nor_spimem_setup_op(nor, &op, nor->reg_proto); 366 367 ret = spi_mem_exec_op(nor->spimem, &op); 368 } else { 369 ret = spi_nor_controller_ops_write_reg(nor, 370 WINBOND_NOR_OP_WREAR, 371 nor->bouncebuf, 1); 372 } 373 374 if (ret) 375 dev_dbg(nor->dev, "error %d writing EAR\n", ret); 376 377 return ret; 378 } 379 380 /** 381 * winbond_nor_set_4byte_addr_mode() - Set 4-byte address mode for Winbond 382 * flashes. 383 * @nor: pointer to 'struct spi_nor'. 384 * @enable: true to enter the 4-byte address mode, false to exit the 4-byte 385 * address mode. 386 * 387 * Return: 0 on success, -errno otherwise. 388 */ 389 static int winbond_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable) 390 { 391 int ret; 392 393 ret = spi_nor_set_4byte_addr_mode_en4b_ex4b(nor, enable); 394 if (ret || enable) 395 return ret; 396 397 /* 398 * On Winbond W25Q256FV, leaving 4byte mode causes the Extended Address 399 * Register to be set to 1, so all 3-byte-address reads come from the 400 * second 16M. We must clear the register to enable normal behavior. 401 */ 402 ret = spi_nor_write_enable(nor); 403 if (ret) 404 return ret; 405 406 ret = winbond_nor_write_ear(nor, 0); 407 if (ret) 408 return ret; 409 410 return spi_nor_write_disable(nor); 411 } 412 413 static const struct spi_nor_otp_ops winbond_nor_otp_ops = { 414 .read = spi_nor_otp_read_secr, 415 .write = spi_nor_otp_write_secr, 416 .erase = spi_nor_otp_erase_secr, 417 .lock = spi_nor_otp_lock_sr2, 418 .is_locked = spi_nor_otp_is_locked_sr2, 419 }; 420 421 static int winbond_nor_late_init(struct spi_nor *nor) 422 { 423 struct spi_nor_flash_parameter *params = nor->params; 424 425 if (params->otp.org) 426 params->otp.ops = &winbond_nor_otp_ops; 427 428 /* 429 * Winbond seems to require that the Extended Address Register to be set 430 * to zero when exiting the 4-Byte Address Mode, at least for W25Q256FV. 431 * This requirement is not described in the JESD216 SFDP standard, thus 432 * it is Winbond specific. Since we do not know if other Winbond flashes 433 * have the same requirement, play safe and overwrite the method parsed 434 * from BFPT, if any. 435 */ 436 params->set_4byte_addr_mode = winbond_nor_set_4byte_addr_mode; 437 438 return 0; 439 } 440 441 static const struct spi_nor_fixups winbond_nor_fixups = { 442 .late_init = winbond_nor_late_init, 443 }; 444 445 const struct spi_nor_manufacturer spi_nor_winbond = { 446 .name = "winbond", 447 .parts = winbond_nor_parts, 448 .nparts = ARRAY_SIZE(winbond_nor_parts), 449 .fixups = &winbond_nor_fixups, 450 }; 451