0001
0002
0003
0004
0005
0006
0007 #include <linux/mtd/spi-nor.h>
0008
0009 #include "core.h"
0010
0011
0012 #define USE_CLSR BIT(0)
0013
0014 #define SPINOR_OP_CLSR 0x30
0015 #define SPINOR_OP_RD_ANY_REG 0x65
0016 #define SPINOR_OP_WR_ANY_REG 0x71
0017 #define SPINOR_REG_CYPRESS_CFR1V 0x00800002
0018 #define SPINOR_REG_CYPRESS_CFR1V_QUAD_EN BIT(1)
0019 #define SPINOR_REG_CYPRESS_CFR2V 0x00800003
0020 #define SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24 0xb
0021 #define SPINOR_REG_CYPRESS_CFR3V 0x00800004
0022 #define SPINOR_REG_CYPRESS_CFR3V_PGSZ BIT(4)
0023 #define SPINOR_REG_CYPRESS_CFR5V 0x00800006
0024 #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN 0x3
0025 #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS 0
0026 #define SPINOR_OP_CYPRESS_RD_FAST 0xee
0027
0028
0029 #define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \
0030 SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 0), \
0031 SPI_MEM_OP_ADDR(naddr, addr, 0), \
0032 SPI_MEM_OP_NO_DUMMY, \
0033 SPI_MEM_OP_DATA_OUT(ndata, buf, 0))
0034
0035 #define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, buf) \
0036 SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0), \
0037 SPI_MEM_OP_ADDR(naddr, addr, 0), \
0038 SPI_MEM_OP_NO_DUMMY, \
0039 SPI_MEM_OP_DATA_IN(1, buf, 0))
0040
0041 #define SPANSION_CLSR_OP \
0042 SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0), \
0043 SPI_MEM_OP_NO_ADDR, \
0044 SPI_MEM_OP_NO_DUMMY, \
0045 SPI_MEM_OP_NO_DATA)
0046
0047 static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
0048 {
0049 struct spi_mem_op op;
0050 u8 *buf = nor->bouncebuf;
0051 int ret;
0052
0053
0054 *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24;
0055 op = (struct spi_mem_op)
0056 CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR2V, 1, buf);
0057
0058 ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
0059 if (ret)
0060 return ret;
0061
0062 nor->read_dummy = 24;
0063
0064
0065 buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN;
0066 op = (struct spi_mem_op)
0067 CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR5V, 1, buf);
0068
0069 ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
0070 if (ret)
0071 return ret;
0072
0073
0074 ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR);
0075 if (ret) {
0076 dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret);
0077 return ret;
0078 }
0079
0080 if (memcmp(buf, nor->info->id, nor->info->id_len))
0081 return -EINVAL;
0082
0083 return 0;
0084 }
0085
0086 static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
0087 {
0088 struct spi_mem_op op;
0089 u8 *buf = nor->bouncebuf;
0090 int ret;
0091
0092
0093
0094
0095
0096
0097 buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS;
0098 buf[1] = 0;
0099 op = (struct spi_mem_op)
0100 CYPRESS_NOR_WR_ANY_REG_OP(4, SPINOR_REG_CYPRESS_CFR5V, 2, buf);
0101 ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
0102 if (ret)
0103 return ret;
0104
0105
0106 ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1);
0107 if (ret) {
0108 dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret);
0109 return ret;
0110 }
0111
0112 if (memcmp(buf, nor->info->id, nor->info->id_len))
0113 return -EINVAL;
0114
0115 return 0;
0116 }
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132 static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
0133 {
0134 struct spi_mem_op op;
0135 u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
0136 u8 cfr1v_written;
0137 int ret;
0138
0139 op = (struct spi_mem_op)
0140 CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes,
0141 SPINOR_REG_CYPRESS_CFR1V,
0142 nor->bouncebuf);
0143
0144 ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
0145 if (ret)
0146 return ret;
0147
0148 if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1V_QUAD_EN)
0149 return 0;
0150
0151
0152 nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1V_QUAD_EN;
0153 op = (struct spi_mem_op)
0154 CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
0155 SPINOR_REG_CYPRESS_CFR1V, 1,
0156 nor->bouncebuf);
0157 ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
0158 if (ret)
0159 return ret;
0160
0161 cfr1v_written = nor->bouncebuf[0];
0162
0163
0164 op = (struct spi_mem_op)
0165 CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes,
0166 SPINOR_REG_CYPRESS_CFR1V,
0167 nor->bouncebuf);
0168 ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
0169 if (ret)
0170 return ret;
0171
0172 if (nor->bouncebuf[0] != cfr1v_written) {
0173 dev_err(nor->dev, "CFR1: Read back test failed\n");
0174 return -EIO;
0175 }
0176
0177 return 0;
0178 }
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191 static int cypress_nor_set_page_size(struct spi_nor *nor)
0192 {
0193 struct spi_mem_op op =
0194 CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR3V,
0195 nor->bouncebuf);
0196 int ret;
0197
0198 ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
0199 if (ret)
0200 return ret;
0201
0202 if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3V_PGSZ)
0203 nor->params->page_size = 512;
0204 else
0205 nor->params->page_size = 256;
0206
0207 return 0;
0208 }
0209
0210 static int
0211 s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
0212 const struct sfdp_parameter_header *bfpt_header,
0213 const struct sfdp_bfpt *bfpt)
0214 {
0215
0216 nor->params->quad_enable = cypress_nor_quad_enable_volatile;
0217
0218 return cypress_nor_set_page_size(nor);
0219 }
0220
0221 static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
0222 {
0223 struct spi_nor_erase_type *erase_type =
0224 nor->params->erase_map.erase_type;
0225 unsigned int i;
0226
0227
0228
0229
0230
0231 for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
0232 switch (erase_type[i].opcode) {
0233 case SPINOR_OP_SE:
0234 erase_type[i].opcode = SPINOR_OP_SE_4B;
0235 break;
0236 case SPINOR_OP_BE_4K:
0237 erase_type[i].opcode = SPINOR_OP_BE_4K_4B;
0238 break;
0239 default:
0240 break;
0241 }
0242 }
0243 }
0244
0245 static void s25hx_t_late_init(struct spi_nor *nor)
0246 {
0247 struct spi_nor_flash_parameter *params = nor->params;
0248
0249
0250 params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
0251
0252
0253 params->writesize = 16;
0254 }
0255
0256 static struct spi_nor_fixups s25hx_t_fixups = {
0257 .post_bfpt = s25hx_t_post_bfpt_fixup,
0258 .post_sfdp = s25hx_t_post_sfdp_fixup,
0259 .late_init = s25hx_t_late_init,
0260 };
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272 static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
0273 {
0274 return enable ? cypress_nor_octal_dtr_en(nor) :
0275 cypress_nor_octal_dtr_dis(nor);
0276 }
0277
0278 static void s28hs512t_default_init(struct spi_nor *nor)
0279 {
0280 nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable;
0281 nor->params->writesize = 16;
0282 }
0283
0284 static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor)
0285 {
0286
0287
0288
0289
0290 if (nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
0291 nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
0292 SPINOR_OP_CYPRESS_RD_FAST;
0293
0294
0295 spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP],
0296 SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
0297
0298
0299
0300
0301 spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
0302 SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
0303
0304
0305
0306
0307
0308
0309 nor->params->rdsr_addr_nbytes = 4;
0310 }
0311
0312 static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
0313 const struct sfdp_parameter_header *bfpt_header,
0314 const struct sfdp_bfpt *bfpt)
0315 {
0316 return cypress_nor_set_page_size(nor);
0317 }
0318
0319 static const struct spi_nor_fixups s28hs512t_fixups = {
0320 .default_init = s28hs512t_default_init,
0321 .post_sfdp = s28hs512t_post_sfdp_fixup,
0322 .post_bfpt = s28hs512t_post_bfpt_fixup,
0323 };
0324
0325 static int
0326 s25fs_s_nor_post_bfpt_fixups(struct spi_nor *nor,
0327 const struct sfdp_parameter_header *bfpt_header,
0328 const struct sfdp_bfpt *bfpt)
0329 {
0330
0331
0332
0333
0334
0335
0336 nor->params->page_size = 256;
0337
0338 return 0;
0339 }
0340
0341 static const struct spi_nor_fixups s25fs_s_nor_fixups = {
0342 .post_bfpt = s25fs_s_nor_post_bfpt_fixups,
0343 };
0344
0345 static const struct flash_info spansion_nor_parts[] = {
0346
0347
0348
0349 { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64)
0350 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
0351 { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128)
0352 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
0353 { "s25fl128s0", INFO6(0x012018, 0x4d0080, 256 * 1024, 64)
0354 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0355 MFR_FLAGS(USE_CLSR)
0356 },
0357 { "s25fl128s1", INFO6(0x012018, 0x4d0180, 64 * 1024, 256)
0358 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0359 MFR_FLAGS(USE_CLSR)
0360 },
0361 { "s25fl256s0", INFO6(0x010219, 0x4d0080, 256 * 1024, 128)
0362 NO_SFDP_FLAGS(SPI_NOR_SKIP_SFDP | SPI_NOR_DUAL_READ |
0363 SPI_NOR_QUAD_READ)
0364 MFR_FLAGS(USE_CLSR)
0365 },
0366 { "s25fl256s1", INFO6(0x010219, 0x4d0180, 64 * 1024, 512)
0367 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0368 MFR_FLAGS(USE_CLSR)
0369 },
0370 { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256)
0371 FLAGS(SPI_NOR_HAS_LOCK)
0372 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0373 MFR_FLAGS(USE_CLSR)
0374 },
0375 { "s25fs128s1", INFO6(0x012018, 0x4d0181, 64 * 1024, 256)
0376 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0377 MFR_FLAGS(USE_CLSR)
0378 .fixups = &s25fs_s_nor_fixups, },
0379 { "s25fs256s0", INFO6(0x010219, 0x4d0081, 256 * 1024, 128)
0380 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0381 MFR_FLAGS(USE_CLSR)
0382 },
0383 { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512)
0384 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0385 MFR_FLAGS(USE_CLSR)
0386 },
0387 { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256)
0388 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0389 MFR_FLAGS(USE_CLSR)
0390 .fixups = &s25fs_s_nor_fixups, },
0391 { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64) },
0392 { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256) },
0393 { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64)
0394 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0395 MFR_FLAGS(USE_CLSR)
0396 },
0397 { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256)
0398 NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0399 MFR_FLAGS(USE_CLSR)
0400 },
0401 { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8) },
0402 { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16) },
0403 { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32) },
0404 { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64) },
0405 { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128) },
0406 { "s25fl004k", INFO(0xef4013, 0, 64 * 1024, 8)
0407 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
0408 SPI_NOR_QUAD_READ) },
0409 { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16)
0410 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
0411 SPI_NOR_QUAD_READ) },
0412 { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32)
0413 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
0414 SPI_NOR_QUAD_READ) },
0415 { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128)
0416 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
0417 SPI_NOR_QUAD_READ) },
0418 { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32)
0419 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
0420 SPI_NOR_QUAD_READ) },
0421 { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64)
0422 NO_SFDP_FLAGS(SECT_4K) },
0423 { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128)
0424 NO_SFDP_FLAGS(SECT_4K) },
0425 { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8)
0426 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
0427 { "s25fl208k", INFO(0x014014, 0, 64 * 1024, 16)
0428 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
0429 { "s25fl064l", INFO(0x016017, 0, 64 * 1024, 128)
0430 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0431 FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
0432 { "s25fl128l", INFO(0x016018, 0, 64 * 1024, 256)
0433 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0434 FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
0435 { "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512)
0436 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0437 FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
0438 { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
0439 PARSE_SFDP
0440 MFR_FLAGS(USE_CLSR)
0441 .fixups = &s25hx_t_fixups },
0442 { "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512)
0443 PARSE_SFDP
0444 MFR_FLAGS(USE_CLSR)
0445 .fixups = &s25hx_t_fixups },
0446 { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256)
0447 PARSE_SFDP
0448 MFR_FLAGS(USE_CLSR)
0449 .fixups = &s25hx_t_fixups },
0450 { "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512)
0451 PARSE_SFDP
0452 MFR_FLAGS(USE_CLSR)
0453 .fixups = &s25hx_t_fixups },
0454 { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
0455 FLAGS(SPI_NOR_NO_ERASE) },
0456 { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256)
0457 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_DTR_READ |
0458 SPI_NOR_OCTAL_DTR_PP)
0459 .fixups = &s28hs512t_fixups,
0460 },
0461 };
0462
0463
0464
0465
0466
0467 static void spansion_nor_clear_sr(struct spi_nor *nor)
0468 {
0469 int ret;
0470
0471 if (nor->spimem) {
0472 struct spi_mem_op op = SPANSION_CLSR_OP;
0473
0474 spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
0475
0476 ret = spi_mem_exec_op(nor->spimem, &op);
0477 } else {
0478 ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
0479 NULL, 0);
0480 }
0481
0482 if (ret)
0483 dev_dbg(nor->dev, "error %d clearing SR\n", ret);
0484 }
0485
0486
0487
0488
0489
0490
0491
0492
0493 static int spansion_nor_sr_ready_and_clear(struct spi_nor *nor)
0494 {
0495 int ret;
0496
0497 ret = spi_nor_read_sr(nor, nor->bouncebuf);
0498 if (ret)
0499 return ret;
0500
0501 if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
0502 if (nor->bouncebuf[0] & SR_E_ERR)
0503 dev_err(nor->dev, "Erase Error occurred\n");
0504 else
0505 dev_err(nor->dev, "Programming Error occurred\n");
0506
0507 spansion_nor_clear_sr(nor);
0508
0509
0510
0511
0512
0513
0514
0515 ret = spi_nor_write_disable(nor);
0516 if (ret)
0517 return ret;
0518
0519 return -EIO;
0520 }
0521
0522 return !(nor->bouncebuf[0] & SR_WIP);
0523 }
0524
0525 static void spansion_nor_late_init(struct spi_nor *nor)
0526 {
0527 if (nor->params->size > SZ_16M) {
0528 nor->flags |= SNOR_F_4B_OPCODES;
0529
0530 nor->erase_opcode = SPINOR_OP_SE;
0531 nor->mtd.erasesize = nor->info->sector_size;
0532 }
0533
0534 if (nor->info->mfr_flags & USE_CLSR)
0535 nor->params->ready = spansion_nor_sr_ready_and_clear;
0536 }
0537
0538 static const struct spi_nor_fixups spansion_nor_fixups = {
0539 .late_init = spansion_nor_late_init,
0540 };
0541
0542 const struct spi_nor_manufacturer spi_nor_spansion = {
0543 .name = "spansion",
0544 .parts = spansion_nor_parts,
0545 .nparts = ARRAY_SIZE(spansion_nor_parts),
0546 .fixups = &spansion_nor_fixups,
0547 };