diff options
-rw-r--r-- | drivers/mtd/Kconfig | 5 | ||||
-rw-r--r-- | drivers/mtd/chips/Kconfig | 1 | ||||
-rw-r--r-- | drivers/mtd/devices/Kconfig | 11 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 206 | ||||
-rw-r--r-- | drivers/mtd/mtdchar.c | 4 | ||||
-rw-r--r-- | drivers/mtd/onenand/Kconfig | 1 |
6 files changed, 219 insertions, 9 deletions
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 14f11f8b9e5f..a90d50c2c3e5 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig | |||
@@ -172,6 +172,11 @@ config MTD_CHAR | |||
172 | memory chips, and also use ioctl() to obtain information about | 172 | memory chips, and also use ioctl() to obtain information about |
173 | the device, or to erase parts of it. | 173 | the device, or to erase parts of it. |
174 | 174 | ||
175 | config HAVE_MTD_OTP | ||
176 | bool | ||
177 | help | ||
178 | Enable access to OTP regions using MTD_CHAR. | ||
179 | |||
175 | config MTD_BLKDEVS | 180 | config MTD_BLKDEVS |
176 | tristate "Common interface to block layer for MTD 'translation layers'" | 181 | tristate "Common interface to block layer for MTD 'translation layers'" |
177 | depends on BLOCK | 182 | depends on BLOCK |
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 479d32b57a1e..4c35e5d77f95 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig | |||
@@ -154,6 +154,7 @@ config MTD_CFI_I8 | |||
154 | config MTD_OTP | 154 | config MTD_OTP |
155 | bool "Protection Registers aka one-time programmable (OTP) bits" | 155 | bool "Protection Registers aka one-time programmable (OTP) bits" |
156 | depends on MTD_CFI_ADV_OPTIONS | 156 | depends on MTD_CFI_ADV_OPTIONS |
157 | select HAVE_MTD_OTP | ||
157 | default n | 158 | default n |
158 | help | 159 | help |
159 | This enables support for reading, writing and locking so called | 160 | This enables support for reading, writing and locking so called |
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 9c613f06623c..88f4df047464 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig | |||
@@ -59,6 +59,17 @@ config MTD_DATAFLASH | |||
59 | Sometimes DataFlash chips are packaged inside MMC-format | 59 | Sometimes DataFlash chips are packaged inside MMC-format |
60 | cards; at this writing, the MMC stack won't handle those. | 60 | cards; at this writing, the MMC stack won't handle those. |
61 | 61 | ||
62 | config MTD_DATAFLASH_OTP | ||
63 | bool "DataFlash OTP support (Security Register)" | ||
64 | depends on MTD_DATAFLASH | ||
65 | select HAVE_MTD_OTP | ||
66 | help | ||
67 | Newer DataFlash chips (revisions C and D) support 128 bytes of | ||
68 | one-time-programmable (OTP) data. The first half may be written | ||
69 | (once) with up to 64 bytes of data, such as a serial number or | ||
70 | other key product data. The second half is programmed with a | ||
71 | unique-to-each-chip bit pattern at the factory. | ||
72 | |||
62 | config MTD_M25P80 | 73 | config MTD_M25P80 |
63 | tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" | 74 | tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" |
64 | depends on SPI_MASTER && EXPERIMENTAL | 75 | depends on SPI_MASTER && EXPERIMENTAL |
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 8bd0dea6885f..17c9b20dca87 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c | |||
@@ -80,7 +80,8 @@ | |||
80 | */ | 80 | */ |
81 | #define OP_READ_ID 0x9F | 81 | #define OP_READ_ID 0x9F |
82 | #define OP_READ_SECURITY 0x77 | 82 | #define OP_READ_SECURITY 0x77 |
83 | #define OP_WRITE_SECURITY 0x9A /* OTP bits */ | 83 | #define OP_WRITE_SECURITY_REVC 0x9A |
84 | #define OP_WRITE_SECURITY 0x9B /* revision D */ | ||
84 | 85 | ||
85 | 86 | ||
86 | struct dataflash { | 87 | struct dataflash { |
@@ -451,16 +452,192 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
451 | 452 | ||
452 | /* ......................................................................... */ | 453 | /* ......................................................................... */ |
453 | 454 | ||
455 | #ifdef CONFIG_MTD_DATAFLASH_OTP | ||
456 | |||
457 | static int dataflash_get_otp_info(struct mtd_info *mtd, | ||
458 | struct otp_info *info, size_t len) | ||
459 | { | ||
460 | /* Report both blocks as identical: bytes 0..64, locked. | ||
461 | * Unless the user block changed from all-ones, we can't | ||
462 | * tell whether it's still writable; so we assume it isn't. | ||
463 | */ | ||
464 | info->start = 0; | ||
465 | info->length = 64; | ||
466 | info->locked = 1; | ||
467 | return sizeof(*info); | ||
468 | } | ||
469 | |||
470 | static ssize_t otp_read(struct spi_device *spi, unsigned base, | ||
471 | uint8_t *buf, loff_t off, size_t len) | ||
472 | { | ||
473 | struct spi_message m; | ||
474 | size_t l; | ||
475 | uint8_t *scratch; | ||
476 | struct spi_transfer t; | ||
477 | int status; | ||
478 | |||
479 | if (off > 64) | ||
480 | return -EINVAL; | ||
481 | |||
482 | if ((off + len) > 64) | ||
483 | len = 64 - off; | ||
484 | if (len == 0) | ||
485 | return len; | ||
486 | |||
487 | spi_message_init(&m); | ||
488 | |||
489 | l = 4 + base + off + len; | ||
490 | scratch = kzalloc(l, GFP_KERNEL); | ||
491 | if (!scratch) | ||
492 | return -ENOMEM; | ||
493 | |||
494 | /* OUT: OP_READ_SECURITY, 3 don't-care bytes, zeroes | ||
495 | * IN: ignore 4 bytes, data bytes 0..N (max 127) | ||
496 | */ | ||
497 | scratch[0] = OP_READ_SECURITY; | ||
498 | |||
499 | memset(&t, 0, sizeof t); | ||
500 | t.tx_buf = scratch; | ||
501 | t.rx_buf = scratch; | ||
502 | t.len = l; | ||
503 | spi_message_add_tail(&t, &m); | ||
504 | |||
505 | dataflash_waitready(spi); | ||
506 | |||
507 | status = spi_sync(spi, &m); | ||
508 | if (status >= 0) { | ||
509 | memcpy(buf, scratch + 4 + base + off, len); | ||
510 | status = len; | ||
511 | } | ||
512 | |||
513 | kfree(scratch); | ||
514 | return status; | ||
515 | } | ||
516 | |||
517 | static int dataflash_read_fact_otp(struct mtd_info *mtd, | ||
518 | loff_t from, size_t len, size_t *retlen, u_char *buf) | ||
519 | { | ||
520 | struct dataflash *priv = (struct dataflash *)mtd->priv; | ||
521 | int status; | ||
522 | |||
523 | /* 64 bytes, from 0..63 ... start at 64 on-chip */ | ||
524 | mutex_lock(&priv->lock); | ||
525 | status = otp_read(priv->spi, 64, buf, from, len); | ||
526 | mutex_unlock(&priv->lock); | ||
527 | |||
528 | if (status < 0) | ||
529 | return status; | ||
530 | *retlen = status; | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static int dataflash_read_user_otp(struct mtd_info *mtd, | ||
535 | loff_t from, size_t len, size_t *retlen, u_char *buf) | ||
536 | { | ||
537 | struct dataflash *priv = (struct dataflash *)mtd->priv; | ||
538 | int status; | ||
539 | |||
540 | /* 64 bytes, from 0..63 ... start at 0 on-chip */ | ||
541 | mutex_lock(&priv->lock); | ||
542 | status = otp_read(priv->spi, 0, buf, from, len); | ||
543 | mutex_unlock(&priv->lock); | ||
544 | |||
545 | if (status < 0) | ||
546 | return status; | ||
547 | *retlen = status; | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int dataflash_write_user_otp(struct mtd_info *mtd, | ||
552 | loff_t from, size_t len, size_t *retlen, u_char *buf) | ||
553 | { | ||
554 | struct spi_message m; | ||
555 | const size_t l = 4 + 64; | ||
556 | uint8_t *scratch; | ||
557 | struct spi_transfer t; | ||
558 | struct dataflash *priv = (struct dataflash *)mtd->priv; | ||
559 | int status; | ||
560 | |||
561 | if (len > 64) | ||
562 | return -EINVAL; | ||
563 | |||
564 | /* Strictly speaking, we *could* truncate the write ... but | ||
565 | * let's not do that for the only write that's ever possible. | ||
566 | */ | ||
567 | if ((from + len) > 64) | ||
568 | return -EINVAL; | ||
569 | |||
570 | /* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes | ||
571 | * IN: ignore all | ||
572 | */ | ||
573 | scratch = kzalloc(l, GFP_KERNEL); | ||
574 | if (!scratch) | ||
575 | return -ENOMEM; | ||
576 | scratch[0] = OP_WRITE_SECURITY; | ||
577 | memcpy(scratch + 4 + from, buf, len); | ||
578 | |||
579 | spi_message_init(&m); | ||
580 | |||
581 | memset(&t, 0, sizeof t); | ||
582 | t.tx_buf = scratch; | ||
583 | t.len = l; | ||
584 | spi_message_add_tail(&t, &m); | ||
585 | |||
586 | /* Write the OTP bits, if they've not yet been written. | ||
587 | * This modifies SRAM buffer1. | ||
588 | */ | ||
589 | mutex_lock(&priv->lock); | ||
590 | dataflash_waitready(priv->spi); | ||
591 | status = spi_sync(priv->spi, &m); | ||
592 | mutex_unlock(&priv->lock); | ||
593 | |||
594 | kfree(scratch); | ||
595 | |||
596 | if (status >= 0) { | ||
597 | status = 0; | ||
598 | *retlen = len; | ||
599 | } | ||
600 | return status; | ||
601 | } | ||
602 | |||
603 | static char *otp_setup(struct mtd_info *device, char revision) | ||
604 | { | ||
605 | device->get_fact_prot_info = dataflash_get_otp_info; | ||
606 | device->read_fact_prot_reg = dataflash_read_fact_otp; | ||
607 | device->get_user_prot_info = dataflash_get_otp_info; | ||
608 | device->read_user_prot_reg = dataflash_read_user_otp; | ||
609 | |||
610 | /* rev c parts (at45db321c and at45db1281 only!) use a | ||
611 | * different write procedure; not (yet?) implemented. | ||
612 | */ | ||
613 | if (revision > 'c') | ||
614 | device->write_user_prot_reg = dataflash_write_user_otp; | ||
615 | |||
616 | return ", OTP"; | ||
617 | } | ||
618 | |||
619 | #else | ||
620 | |||
621 | static char *otp_setup(struct mtd_info *device) | ||
622 | { | ||
623 | return " (OTP)"; | ||
624 | } | ||
625 | |||
626 | #endif | ||
627 | |||
628 | /* ......................................................................... */ | ||
629 | |||
454 | /* | 630 | /* |
455 | * Register DataFlash device with MTD subsystem. | 631 | * Register DataFlash device with MTD subsystem. |
456 | */ | 632 | */ |
457 | static int __devinit | 633 | static int __devinit |
458 | add_dataflash(struct spi_device *spi, char *name, | 634 | add_dataflash_otp(struct spi_device *spi, char *name, |
459 | int nr_pages, int pagesize, int pageoffset) | 635 | int nr_pages, int pagesize, int pageoffset, char revision) |
460 | { | 636 | { |
461 | struct dataflash *priv; | 637 | struct dataflash *priv; |
462 | struct mtd_info *device; | 638 | struct mtd_info *device; |
463 | struct flash_platform_data *pdata = spi->dev.platform_data; | 639 | struct flash_platform_data *pdata = spi->dev.platform_data; |
640 | char *otp_tag = ""; | ||
464 | 641 | ||
465 | priv = kzalloc(sizeof *priv, GFP_KERNEL); | 642 | priv = kzalloc(sizeof *priv, GFP_KERNEL); |
466 | if (!priv) | 643 | if (!priv) |
@@ -489,8 +666,12 @@ add_dataflash(struct spi_device *spi, char *name, | |||
489 | device->write = dataflash_write; | 666 | device->write = dataflash_write; |
490 | device->priv = priv; | 667 | device->priv = priv; |
491 | 668 | ||
492 | dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes\n", | 669 | if (revision >= 'c') |
493 | name, DIV_ROUND_UP(device->size, 1024), pagesize); | 670 | otp_tag = otp_setup(device, revision); |
671 | |||
672 | dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n", | ||
673 | name, DIV_ROUND_UP(device->size, 1024), | ||
674 | pagesize, otp_tag); | ||
494 | dev_set_drvdata(&spi->dev, priv); | 675 | dev_set_drvdata(&spi->dev, priv); |
495 | 676 | ||
496 | if (mtd_has_partitions()) { | 677 | if (mtd_has_partitions()) { |
@@ -519,6 +700,14 @@ add_dataflash(struct spi_device *spi, char *name, | |||
519 | return add_mtd_device(device) == 1 ? -ENODEV : 0; | 700 | return add_mtd_device(device) == 1 ? -ENODEV : 0; |
520 | } | 701 | } |
521 | 702 | ||
703 | static inline int __devinit | ||
704 | add_dataflash(struct spi_device *spi, char *name, | ||
705 | int nr_pages, int pagesize, int pageoffset) | ||
706 | { | ||
707 | return add_dataflash_otp(spi, name, nr_pages, pagesize, | ||
708 | pageoffset, 0); | ||
709 | } | ||
710 | |||
522 | struct flash_info { | 711 | struct flash_info { |
523 | char *name; | 712 | char *name; |
524 | 713 | ||
@@ -664,13 +853,16 @@ static int __devinit dataflash_probe(struct spi_device *spi) | |||
664 | * Try to detect dataflash by JEDEC ID. | 853 | * Try to detect dataflash by JEDEC ID. |
665 | * If it succeeds we know we have either a C or D part. | 854 | * If it succeeds we know we have either a C or D part. |
666 | * D will support power of 2 pagesize option. | 855 | * D will support power of 2 pagesize option. |
856 | * Both support the security register, though with different | ||
857 | * write procedures. | ||
667 | */ | 858 | */ |
668 | info = jedec_probe(spi); | 859 | info = jedec_probe(spi); |
669 | if (IS_ERR(info)) | 860 | if (IS_ERR(info)) |
670 | return PTR_ERR(info); | 861 | return PTR_ERR(info); |
671 | if (info != NULL) | 862 | if (info != NULL) |
672 | return add_dataflash(spi, info->name, info->nr_pages, | 863 | return add_dataflash_otp(spi, info->name, info->nr_pages, |
673 | info->pagesize, info->pageoffset); | 864 | info->pagesize, info->pageoffset, |
865 | (info->flags & SUP_POW2PS) ? 'd' : 'c'); | ||
674 | 866 | ||
675 | /* | 867 | /* |
676 | * Older chips support only legacy commands, identifing | 868 | * Older chips support only legacy commands, identifing |
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d2f331876e4c..13cc67ad272a 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -350,7 +350,7 @@ static void mtdchar_erase_callback (struct erase_info *instr) | |||
350 | wake_up((wait_queue_head_t *)instr->priv); | 350 | wake_up((wait_queue_head_t *)instr->priv); |
351 | } | 351 | } |
352 | 352 | ||
353 | #if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) | 353 | #ifdef CONFIG_HAVE_MTD_OTP |
354 | static int otp_select_filemode(struct mtd_file_info *mfi, int mode) | 354 | static int otp_select_filemode(struct mtd_file_info *mfi, int mode) |
355 | { | 355 | { |
356 | struct mtd_info *mtd = mfi->mtd; | 356 | struct mtd_info *mtd = mfi->mtd; |
@@ -663,7 +663,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
663 | break; | 663 | break; |
664 | } | 664 | } |
665 | 665 | ||
666 | #if defined(CONFIG_MTD_OTP) || defined(CONFIG_MTD_ONENAND_OTP) | 666 | #ifdef CONFIG_HAVE_MTD_OTP |
667 | case OTPSELECT: | 667 | case OTPSELECT: |
668 | { | 668 | { |
669 | int mode; | 669 | int mode; |
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig index cb41cbca64f7..b94a61b670d1 100644 --- a/drivers/mtd/onenand/Kconfig +++ b/drivers/mtd/onenand/Kconfig | |||
@@ -29,6 +29,7 @@ config MTD_ONENAND_GENERIC | |||
29 | 29 | ||
30 | config MTD_ONENAND_OTP | 30 | config MTD_ONENAND_OTP |
31 | bool "OneNAND OTP Support" | 31 | bool "OneNAND OTP Support" |
32 | select HAVE_MTD_OTP | ||
32 | help | 33 | help |
33 | One Block of the NAND Flash Array memory is reserved as | 34 | One Block of the NAND Flash Array memory is reserved as |
34 | a One-Time Programmable Block memory area. | 35 | a One-Time Programmable Block memory area. |