diff options
author | Christian Riesch <christian.riesch@omicron.at> | 2014-03-06 07:18:29 -0500 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2014-07-11 22:44:25 -0400 |
commit | af7447505732ea729af6a99e76fc558b6e3fcbcd (patch) | |
tree | a1da6bfeccbdb113e9f5d61a0811ffd883d4e091 /drivers/mtd | |
parent | feb8677935d4319c6d22b017fefac1532cd80529 (diff) |
mtd: cfi_cmdset_0002: Add support for writing OTP memory
This patch adds support for writing the one time programmable (OTP)
memory of Micron M29EW devices.
Signed-off-by: Christian Riesch <christian.riesch@omicron.at>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 67 |
1 files changed, 60 insertions, 7 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 612eb3d6902c..6c575e65010b 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -67,6 +67,8 @@ static int cfi_amdstd_read_fact_prot_reg(struct mtd_info *, loff_t, size_t, | |||
67 | size_t *, u_char *); | 67 | size_t *, u_char *); |
68 | static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t, | 68 | static int cfi_amdstd_read_user_prot_reg(struct mtd_info *, loff_t, size_t, |
69 | size_t *, u_char *); | 69 | size_t *, u_char *); |
70 | static int cfi_amdstd_write_user_prot_reg(struct mtd_info *, loff_t, size_t, | ||
71 | size_t *, u_char *); | ||
70 | 72 | ||
71 | static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, | 73 | static int cfi_amdstd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, |
72 | size_t *retlen, const u_char *buf); | 74 | size_t *retlen, const u_char *buf); |
@@ -530,6 +532,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) | |||
530 | mtd->_read_fact_prot_reg = cfi_amdstd_read_fact_prot_reg; | 532 | mtd->_read_fact_prot_reg = cfi_amdstd_read_fact_prot_reg; |
531 | mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info; | 533 | mtd->_get_fact_prot_info = cfi_amdstd_get_fact_prot_info; |
532 | mtd->_get_user_prot_info = cfi_amdstd_get_user_prot_info; | 534 | mtd->_get_user_prot_info = cfi_amdstd_get_user_prot_info; |
535 | mtd->_write_user_prot_reg = cfi_amdstd_write_user_prot_reg; | ||
533 | mtd->flags = MTD_CAP_NORFLASH; | 536 | mtd->flags = MTD_CAP_NORFLASH; |
534 | mtd->name = map->name; | 537 | mtd->name = map->name; |
535 | mtd->writesize = 1; | 538 | mtd->writesize = 1; |
@@ -1257,6 +1260,40 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, | |||
1257 | return ret; | 1260 | return ret; |
1258 | } | 1261 | } |
1259 | 1262 | ||
1263 | static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | ||
1264 | unsigned long adr, map_word datum, | ||
1265 | int mode); | ||
1266 | |||
1267 | static int do_otp_write(struct map_info *map, struct flchip *chip, loff_t adr, | ||
1268 | size_t len, u_char *buf) | ||
1269 | { | ||
1270 | int ret; | ||
1271 | while (len) { | ||
1272 | unsigned long bus_ofs = adr & ~(map_bankwidth(map)-1); | ||
1273 | int gap = adr - bus_ofs; | ||
1274 | int n = min_t(int, len, map_bankwidth(map) - gap); | ||
1275 | map_word datum; | ||
1276 | |||
1277 | if (n != map_bankwidth(map)) { | ||
1278 | /* partial write of a word, load old contents */ | ||
1279 | otp_enter(map, chip, bus_ofs, map_bankwidth(map)); | ||
1280 | datum = map_read(map, bus_ofs); | ||
1281 | otp_exit(map, chip, bus_ofs, map_bankwidth(map)); | ||
1282 | } | ||
1283 | |||
1284 | datum = map_word_load_partial(map, datum, buf, gap, n); | ||
1285 | ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); | ||
1286 | if (ret) | ||
1287 | return ret; | ||
1288 | |||
1289 | adr += n; | ||
1290 | buf += n; | ||
1291 | len -= n; | ||
1292 | } | ||
1293 | |||
1294 | return 0; | ||
1295 | } | ||
1296 | |||
1260 | static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, | 1297 | static int cfi_amdstd_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, |
1261 | size_t *retlen, u_char *buf, | 1298 | size_t *retlen, u_char *buf, |
1262 | otp_op_t action, int user_regs) | 1299 | otp_op_t action, int user_regs) |
@@ -1400,7 +1437,17 @@ static int cfi_amdstd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, | |||
1400 | buf, do_read_secsi_onechip, 1); | 1437 | buf, do_read_secsi_onechip, 1); |
1401 | } | 1438 | } |
1402 | 1439 | ||
1403 | static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum) | 1440 | static int cfi_amdstd_write_user_prot_reg(struct mtd_info *mtd, loff_t from, |
1441 | size_t len, size_t *retlen, | ||
1442 | u_char *buf) | ||
1443 | { | ||
1444 | return cfi_amdstd_otp_walk(mtd, from, len, retlen, buf, | ||
1445 | do_otp_write, 1); | ||
1446 | } | ||
1447 | |||
1448 | static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | ||
1449 | unsigned long adr, map_word datum, | ||
1450 | int mode) | ||
1404 | { | 1451 | { |
1405 | struct cfi_private *cfi = map->fldrv_priv; | 1452 | struct cfi_private *cfi = map->fldrv_priv; |
1406 | unsigned long timeo = jiffies + HZ; | 1453 | unsigned long timeo = jiffies + HZ; |
@@ -1421,7 +1468,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1421 | adr += chip->start; | 1468 | adr += chip->start; |
1422 | 1469 | ||
1423 | mutex_lock(&chip->mutex); | 1470 | mutex_lock(&chip->mutex); |
1424 | ret = get_chip(map, chip, adr, FL_WRITING); | 1471 | ret = get_chip(map, chip, adr, mode); |
1425 | if (ret) { | 1472 | if (ret) { |
1426 | mutex_unlock(&chip->mutex); | 1473 | mutex_unlock(&chip->mutex); |
1427 | return ret; | 1474 | return ret; |
@@ -1430,6 +1477,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1430 | pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", | 1477 | pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", |
1431 | __func__, adr, datum.x[0] ); | 1478 | __func__, adr, datum.x[0] ); |
1432 | 1479 | ||
1480 | if (mode == FL_OTP_WRITE) | ||
1481 | otp_enter(map, chip, adr, map_bankwidth(map)); | ||
1482 | |||
1433 | /* | 1483 | /* |
1434 | * Check for a NOP for the case when the datum to write is already | 1484 | * Check for a NOP for the case when the datum to write is already |
1435 | * present - it saves time and works around buggy chips that corrupt | 1485 | * present - it saves time and works around buggy chips that corrupt |
@@ -1446,12 +1496,13 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1446 | XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); | 1496 | XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); |
1447 | ENABLE_VPP(map); | 1497 | ENABLE_VPP(map); |
1448 | xip_disable(map, chip, adr); | 1498 | xip_disable(map, chip, adr); |
1499 | |||
1449 | retry: | 1500 | retry: |
1450 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1501 | cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
1451 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); | 1502 | cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); |
1452 | cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); | 1503 | cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); |
1453 | map_write(map, datum, adr); | 1504 | map_write(map, datum, adr); |
1454 | chip->state = FL_WRITING; | 1505 | chip->state = mode; |
1455 | 1506 | ||
1456 | INVALIDATE_CACHE_UDELAY(map, chip, | 1507 | INVALIDATE_CACHE_UDELAY(map, chip, |
1457 | adr, map_bankwidth(map), | 1508 | adr, map_bankwidth(map), |
@@ -1460,7 +1511,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1460 | /* See comment above for timeout value. */ | 1511 | /* See comment above for timeout value. */ |
1461 | timeo = jiffies + uWriteTimeout; | 1512 | timeo = jiffies + uWriteTimeout; |
1462 | for (;;) { | 1513 | for (;;) { |
1463 | if (chip->state != FL_WRITING) { | 1514 | if (chip->state != mode) { |
1464 | /* Someone's suspended the write. Sleep */ | 1515 | /* Someone's suspended the write. Sleep */ |
1465 | DECLARE_WAITQUEUE(wait, current); | 1516 | DECLARE_WAITQUEUE(wait, current); |
1466 | 1517 | ||
@@ -1500,6 +1551,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, | |||
1500 | } | 1551 | } |
1501 | xip_enable(map, chip, adr); | 1552 | xip_enable(map, chip, adr); |
1502 | op_done: | 1553 | op_done: |
1554 | if (mode == FL_OTP_WRITE) | ||
1555 | otp_exit(map, chip, adr, map_bankwidth(map)); | ||
1503 | chip->state = FL_READY; | 1556 | chip->state = FL_READY; |
1504 | DISABLE_VPP(map); | 1557 | DISABLE_VPP(map); |
1505 | put_chip(map, chip, adr); | 1558 | put_chip(map, chip, adr); |
@@ -1555,7 +1608,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1555 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); | 1608 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, i, n); |
1556 | 1609 | ||
1557 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1610 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1558 | bus_ofs, tmp_buf); | 1611 | bus_ofs, tmp_buf, FL_WRITING); |
1559 | if (ret) | 1612 | if (ret) |
1560 | return ret; | 1613 | return ret; |
1561 | 1614 | ||
@@ -1579,7 +1632,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1579 | datum = map_word_load(map, buf); | 1632 | datum = map_word_load(map, buf); |
1580 | 1633 | ||
1581 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1634 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1582 | ofs, datum); | 1635 | ofs, datum, FL_WRITING); |
1583 | if (ret) | 1636 | if (ret) |
1584 | return ret; | 1637 | return ret; |
1585 | 1638 | ||
@@ -1622,7 +1675,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, | |||
1622 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); | 1675 | tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); |
1623 | 1676 | ||
1624 | ret = do_write_oneword(map, &cfi->chips[chipnum], | 1677 | ret = do_write_oneword(map, &cfi->chips[chipnum], |
1625 | ofs, tmp_buf); | 1678 | ofs, tmp_buf, FL_WRITING); |
1626 | if (ret) | 1679 | if (ret) |
1627 | return ret; | 1680 | return ret; |
1628 | 1681 | ||