aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices
diff options
context:
space:
mode:
authorAustin Boyle <Austin.Boyle@aviatnet.com>2013-01-03 19:02:28 -0500
committerArtem Bityutskiy <artem.bityutskiy@linux.intel.com>2013-02-04 02:26:29 -0500
commit972e1b7b450a93589b2a4c709e68f68da059aa5c (patch)
tree0611caf8ab75df49896c6c7890a96a7513fef88e /drivers/mtd/devices
parentaca662a3b1c9b178536267da9fb2f0faa798cb7f (diff)
mtd: m25p80: Flash protection support for STmicro chips
This patch adds generic support for flash protection on STmicro chips. On chips with less than 3 protection bits, the unused bits are don't cares and so can be written anyway. The lock function will only change the protection bits if it would not unlock other areas. Similarly, the unlock function will not lock currently unlocked areas. Tested on the m25p64. Signed-off-by: Austin Boyle <Austin.Boyle@aviatnet.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Diffstat (limited to 'drivers/mtd/devices')
-rw-r--r--drivers/mtd/devices/m25p80.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 4eeeb2d7f6ea..069e34f909ed 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
568static 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
609err: mutex_unlock(&flash->lock);
610 return res;
611}
612
613static 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
654err: mutex_unlock(&flash->lock);
655 return res;
656}
657
568/****************************************************************************/ 658/****************************************************************************/
569 659
570/* 660/*
@@ -899,6 +989,12 @@ static int m25p_probe(struct spi_device *spi)
899 flash->mtd._erase = m25p80_erase; 989 flash->mtd._erase = m25p80_erase;
900 flash->mtd._read = m25p80_read; 990 flash->mtd._read = m25p80_read;
901 991
992 /* flash protection support for STmicro chips */
993 if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
994 flash->mtd._lock = m25p80_lock;
995 flash->mtd._unlock = m25p80_unlock;
996 }
997
902 /* sst flash chips use AAI word program */ 998 /* sst flash chips use AAI word program */
903 if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) 999 if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
904 flash->mtd._write = sst_write; 1000 flash->mtd._write = sst_write;