diff options
Diffstat (limited to 'drivers/mtd/devices/m25p80.c')
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 4eeeb2d7f6ea..5b6b0728be21 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -565,6 +565,96 @@ time_out: | |||
565 | return ret; | 565 | return ret; |
566 | } | 566 | } |
567 | 567 | ||
568 | static int m25p80_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
569 | { | ||
570 | struct m25p *flash = mtd_to_m25p(mtd); | ||
571 | uint32_t offset = ofs; | ||
572 | uint8_t status_old, status_new; | ||
573 | int res = 0; | ||
574 | |||
575 | mutex_lock(&flash->lock); | ||
576 | /* Wait until finished previous command */ | ||
577 | if (wait_till_ready(flash)) { | ||
578 | res = 1; | ||
579 | goto err; | ||
580 | } | ||
581 | |||
582 | status_old = read_sr(flash); | ||
583 | |||
584 | if (offset < flash->mtd.size-(flash->mtd.size/2)) | ||
585 | status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0; | ||
586 | else if (offset < flash->mtd.size-(flash->mtd.size/4)) | ||
587 | status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; | ||
588 | else if (offset < flash->mtd.size-(flash->mtd.size/8)) | ||
589 | status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; | ||
590 | else if (offset < flash->mtd.size-(flash->mtd.size/16)) | ||
591 | status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2; | ||
592 | else if (offset < flash->mtd.size-(flash->mtd.size/32)) | ||
593 | status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; | ||
594 | else if (offset < flash->mtd.size-(flash->mtd.size/64)) | ||
595 | status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1; | ||
596 | else | ||
597 | status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0; | ||
598 | |||
599 | /* Only modify protection if it will not unlock other areas */ | ||
600 | if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) > | ||
601 | (status_old&(SR_BP2|SR_BP1|SR_BP0))) { | ||
602 | write_enable(flash); | ||
603 | if (write_sr(flash, status_new) < 0) { | ||
604 | res = 1; | ||
605 | goto err; | ||
606 | } | ||
607 | } | ||
608 | |||
609 | err: mutex_unlock(&flash->lock); | ||
610 | return res; | ||
611 | } | ||
612 | |||
613 | static int m25p80_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) | ||
614 | { | ||
615 | struct m25p *flash = mtd_to_m25p(mtd); | ||
616 | uint32_t offset = ofs; | ||
617 | uint8_t status_old, status_new; | ||
618 | int res = 0; | ||
619 | |||
620 | mutex_lock(&flash->lock); | ||
621 | /* Wait until finished previous command */ | ||
622 | if (wait_till_ready(flash)) { | ||
623 | res = 1; | ||
624 | goto err; | ||
625 | } | ||
626 | |||
627 | status_old = read_sr(flash); | ||
628 | |||
629 | if (offset+len > flash->mtd.size-(flash->mtd.size/64)) | ||
630 | status_new = status_old & ~(SR_BP2|SR_BP1|SR_BP0); | ||
631 | else if (offset+len > flash->mtd.size-(flash->mtd.size/32)) | ||
632 | status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0; | ||
633 | else if (offset+len > flash->mtd.size-(flash->mtd.size/16)) | ||
634 | status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1; | ||
635 | else if (offset+len > flash->mtd.size-(flash->mtd.size/8)) | ||
636 | status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0; | ||
637 | else if (offset+len > flash->mtd.size-(flash->mtd.size/4)) | ||
638 | status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2; | ||
639 | else if (offset+len > flash->mtd.size-(flash->mtd.size/2)) | ||
640 | status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0; | ||
641 | else | ||
642 | status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1; | ||
643 | |||
644 | /* Only modify protection if it will not lock other areas */ | ||
645 | if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) < | ||
646 | (status_old&(SR_BP2|SR_BP1|SR_BP0))) { | ||
647 | write_enable(flash); | ||
648 | if (write_sr(flash, status_new) < 0) { | ||
649 | res = 1; | ||
650 | goto err; | ||
651 | } | ||
652 | } | ||
653 | |||
654 | err: mutex_unlock(&flash->lock); | ||
655 | return res; | ||
656 | } | ||
657 | |||
568 | /****************************************************************************/ | 658 | /****************************************************************************/ |
569 | 659 | ||
570 | /* | 660 | /* |
@@ -642,6 +732,10 @@ static const struct spi_device_id m25p_ids[] = { | |||
642 | /* Everspin */ | 732 | /* Everspin */ |
643 | { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) }, | 733 | { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2) }, |
644 | 734 | ||
735 | /* GigaDevice */ | ||
736 | { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) }, | ||
737 | { "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) }, | ||
738 | |||
645 | /* Intel/Numonyx -- xxxs33b */ | 739 | /* Intel/Numonyx -- xxxs33b */ |
646 | { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, | 740 | { "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) }, |
647 | { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, | 741 | { "320s33b", INFO(0x898912, 0, 64 * 1024, 64, 0) }, |
@@ -899,6 +993,12 @@ static int m25p_probe(struct spi_device *spi) | |||
899 | flash->mtd._erase = m25p80_erase; | 993 | flash->mtd._erase = m25p80_erase; |
900 | flash->mtd._read = m25p80_read; | 994 | flash->mtd._read = m25p80_read; |
901 | 995 | ||
996 | /* flash protection support for STmicro chips */ | ||
997 | if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) { | ||
998 | flash->mtd._lock = m25p80_lock; | ||
999 | flash->mtd._unlock = m25p80_unlock; | ||
1000 | } | ||
1001 | |||
902 | /* sst flash chips use AAI word program */ | 1002 | /* sst flash chips use AAI word program */ |
903 | if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) | 1003 | if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) |
904 | flash->mtd._write = sst_write; | 1004 | flash->mtd._write = sst_write; |