aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2014-03-20 05:21:00 -0400
committerBrian Norris <computersforpeace@gmail.com>2014-03-20 07:17:20 -0400
commit4a341fe758657850cbf6d2c36ee9029c0210e3c5 (patch)
treef47ac8e5a4ccbe47273af8d0dcdb081d43d6eb72 /drivers/mtd/devices
parent176b437762a310d5ac7ed3c015ece9dd65c7e240 (diff)
mtd: st_spi_fsm: Erase partly or as a whole a Serial Flash device
When an erase is requested by userspace the MTD framework calls back into the driver to conduct the actual command issue. Here we provide the routines which do exactly that. We can choose to either do an entire chip erase or by sector. Acked-by Angus Clark <angus.clark@st.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd/devices')
-rw-r--r--drivers/mtd/devices/st_spi_fsm.c113
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
570static 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
570static struct stfsm_seq stfsm_seq_wrvcr = { 591static 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
1241static 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
1269static 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 */
1341static 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
1378out1:
1379 instr->state = MTD_ERASE_FAILED;
1380 mutex_unlock(&fsm->lock);
1381
1382 return ret;
1383}
1384
1275static void stfsm_read_jedec(struct stfsm *fsm, uint8_t *const jedec) 1385static 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,