diff options
-rw-r--r-- | drivers/mtd/devices/st_spi_fsm.c | 113 |
1 files changed, 112 insertions, 1 deletions
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 99e08b01a32d..34aac3f49ba9 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c | |||
@@ -567,6 +567,27 @@ static struct stfsm_seq stfsm_seq_erase_sector = { | |||
567 | SEQ_CFG_STARTSEQ), | 567 | SEQ_CFG_STARTSEQ), |
568 | }; | 568 | }; |
569 | 569 | ||
570 | static struct stfsm_seq stfsm_seq_erase_chip = { | ||
571 | .seq_opc = { | ||
572 | (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | | ||
573 | SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT), | ||
574 | |||
575 | (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | | ||
576 | SEQ_OPC_OPCODE(FLASH_CMD_CHIPERASE) | SEQ_OPC_CSDEASSERT), | ||
577 | }, | ||
578 | .seq = { | ||
579 | STFSM_INST_CMD1, | ||
580 | STFSM_INST_CMD2, | ||
581 | STFSM_INST_WAIT, | ||
582 | STFSM_INST_STOP, | ||
583 | }, | ||
584 | .seq_cfg = (SEQ_CFG_PADS_1 | | ||
585 | SEQ_CFG_ERASE | | ||
586 | SEQ_CFG_READNOTWRITE | | ||
587 | SEQ_CFG_CSDEASSERT | | ||
588 | SEQ_CFG_STARTSEQ), | ||
589 | }; | ||
590 | |||
570 | static struct stfsm_seq stfsm_seq_wrvcr = { | 591 | static struct stfsm_seq stfsm_seq_wrvcr = { |
571 | .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | | 592 | .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) | |
572 | SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT), | 593 | SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT), |
@@ -1217,6 +1238,47 @@ static int stfsm_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1217 | return 0; | 1238 | return 0; |
1218 | } | 1239 | } |
1219 | 1240 | ||
1241 | static int stfsm_erase_sector(struct stfsm *fsm, const uint32_t offset) | ||
1242 | { | ||
1243 | struct stfsm_seq *seq = &stfsm_seq_erase_sector; | ||
1244 | int ret; | ||
1245 | |||
1246 | dev_dbg(fsm->dev, "erasing sector at 0x%08x\n", offset); | ||
1247 | |||
1248 | /* Enter 32-bit address mode, if required */ | ||
1249 | if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR) | ||
1250 | stfsm_enter_32bit_addr(fsm, 1); | ||
1251 | |||
1252 | seq->addr1 = (offset >> 16) & 0xffff; | ||
1253 | seq->addr2 = offset & 0xffff; | ||
1254 | |||
1255 | stfsm_load_seq(fsm, seq); | ||
1256 | |||
1257 | stfsm_wait_seq(fsm); | ||
1258 | |||
1259 | /* Wait for completion */ | ||
1260 | ret = stfsm_wait_busy(fsm); | ||
1261 | |||
1262 | /* Exit 32-bit address mode, if required */ | ||
1263 | if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR) | ||
1264 | stfsm_enter_32bit_addr(fsm, 0); | ||
1265 | |||
1266 | return ret; | ||
1267 | } | ||
1268 | |||
1269 | static int stfsm_erase_chip(struct stfsm *fsm) | ||
1270 | { | ||
1271 | const struct stfsm_seq *seq = &stfsm_seq_erase_chip; | ||
1272 | |||
1273 | dev_dbg(fsm->dev, "erasing chip\n"); | ||
1274 | |||
1275 | stfsm_load_seq(fsm, seq); | ||
1276 | |||
1277 | stfsm_wait_seq(fsm); | ||
1278 | |||
1279 | return stfsm_wait_busy(fsm); | ||
1280 | } | ||
1281 | |||
1220 | /* | 1282 | /* |
1221 | * Write an address range to the flash chip. Data must be written in | 1283 | * Write an address range to the flash chip. Data must be written in |
1222 | * FLASH_PAGESIZE chunks. The address range may be any size provided | 1284 | * FLASH_PAGESIZE chunks. The address range may be any size provided |
@@ -1272,6 +1334,54 @@ out1: | |||
1272 | return ret; | 1334 | return ret; |
1273 | } | 1335 | } |
1274 | 1336 | ||
1337 | /* | ||
1338 | * Erase an address range on the flash chip. The address range may extend | ||
1339 | * one or more erase sectors. Return an error is there is a problem erasing. | ||
1340 | */ | ||
1341 | static int stfsm_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) | ||
1342 | { | ||
1343 | struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent); | ||
1344 | u32 addr, len; | ||
1345 | int ret; | ||
1346 | |||
1347 | dev_dbg(fsm->dev, "%s at 0x%llx, len %lld\n", __func__, | ||
1348 | (long long)instr->addr, (long long)instr->len); | ||
1349 | |||
1350 | addr = instr->addr; | ||
1351 | len = instr->len; | ||
1352 | |||
1353 | mutex_lock(&fsm->lock); | ||
1354 | |||
1355 | /* Whole-chip erase? */ | ||
1356 | if (len == mtd->size) { | ||
1357 | ret = stfsm_erase_chip(fsm); | ||
1358 | if (ret) | ||
1359 | goto out1; | ||
1360 | } else { | ||
1361 | while (len) { | ||
1362 | ret = stfsm_erase_sector(fsm, addr); | ||
1363 | if (ret) | ||
1364 | goto out1; | ||
1365 | |||
1366 | addr += mtd->erasesize; | ||
1367 | len -= mtd->erasesize; | ||
1368 | } | ||
1369 | } | ||
1370 | |||
1371 | mutex_unlock(&fsm->lock); | ||
1372 | |||
1373 | instr->state = MTD_ERASE_DONE; | ||
1374 | mtd_erase_callback(instr); | ||
1375 | |||
1376 | return 0; | ||
1377 | |||
1378 | out1: | ||
1379 | instr->state = MTD_ERASE_FAILED; | ||
1380 | mutex_unlock(&fsm->lock); | ||
1381 | |||
1382 | return ret; | ||
1383 | } | ||
1384 | |||
1275 | static void stfsm_read_jedec(struct stfsm *fsm, uint8_t *const jedec) | 1385 | static void stfsm_read_jedec(struct stfsm *fsm, uint8_t *const jedec) |
1276 | { | 1386 | { |
1277 | const struct stfsm_seq *seq = &stfsm_seq_read_jedec; | 1387 | const struct stfsm_seq *seq = &stfsm_seq_read_jedec; |
@@ -1529,8 +1639,9 @@ static int stfsm_probe(struct platform_device *pdev) | |||
1529 | 1639 | ||
1530 | fsm->mtd._read = stfsm_mtd_read; | 1640 | fsm->mtd._read = stfsm_mtd_read; |
1531 | fsm->mtd._write = stfsm_mtd_write; | 1641 | fsm->mtd._write = stfsm_mtd_write; |
1642 | fsm->mtd._erase = stfsm_mtd_erase; | ||
1532 | 1643 | ||
1533 | dev_err(&pdev->dev, | 1644 | dev_info(&pdev->dev, |
1534 | "Found serial flash device: %s\n" | 1645 | "Found serial flash device: %s\n" |
1535 | " size = %llx (%lldMiB) erasesize = 0x%08x (%uKiB)\n", | 1646 | " size = %llx (%lldMiB) erasesize = 0x%08x (%uKiB)\n", |
1536 | info->name, | 1647 | info->name, |