summaryrefslogtreecommitdiff
path: root/package/boot/uboot-layerscape/patches/0086-driver-spi-add-spansion-s25fs-s-family-protect-unpro.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/boot/uboot-layerscape/patches/0086-driver-spi-add-spansion-s25fs-s-family-protect-unpro.patch')
-rw-r--r--package/boot/uboot-layerscape/patches/0086-driver-spi-add-spansion-s25fs-s-family-protect-unpro.patch233
1 files changed, 233 insertions, 0 deletions
diff --git a/package/boot/uboot-layerscape/patches/0086-driver-spi-add-spansion-s25fs-s-family-protect-unpro.patch b/package/boot/uboot-layerscape/patches/0086-driver-spi-add-spansion-s25fs-s-family-protect-unpro.patch
new file mode 100644
index 0000000..008b601
--- /dev/null
+++ b/package/boot/uboot-layerscape/patches/0086-driver-spi-add-spansion-s25fs-s-family-protect-unpro.patch
@@ -0,0 +1,233 @@
+From 986172ece10eee928ce66597d76f3f40ac3d25f7 Mon Sep 17 00:00:00 2001
+From: Yunhui Cui <yunhui.cui@nxp.com>
+Date: Mon, 8 Aug 2016 14:24:13 +0800
+Subject: [PATCH 86/93] driver: spi: add spansion s25fs-s family
+ protect/unprotect
+
+In order to support spansion s25fs512s flash protect/unprotect:
+
+[1] Fill callbak flash->lock/unlock/is_locked by spansion_lock/
+unlock/is_locked.
+
+[2] Achieve protect/unprotected by operating sr1nv, cr1nv.
+
+Signed-off-by: Yunhui Cui <yunhui.cui@nxp.com>
+---
+ drivers/mtd/spi/spi_flash.c | 194 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 194 insertions(+)
+
+diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
+index e04bd55..87a92e9 100644
+--- a/drivers/mtd/spi/spi_flash.c
++++ b/drivers/mtd/spi/spi_flash.c
+@@ -877,6 +877,193 @@ int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len)
+ }
+ #endif
+
++#if defined(CONFIG_SPI_FLASH_SPANSION)
++/*
++ * Return 1 if the entire region is locked, 0 otherwise
++ */
++static int spansion_is_locked_sr(struct spi_flash *flash, u32 ofs, u32 len,
++ u8 sr)
++{
++ loff_t lock_offs;
++ u32 lock_len;
++
++ stm_get_locked_range(flash, sr, &lock_offs, &lock_len);
++
++ return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs);
++}
++
++/*
++ * Check if a region of the flash is (completely) locked. See spansion_lock() for
++ * more info.
++ *
++ * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
++ * negative on errors.
++ */
++int spansion_is_locked(struct spi_flash *flash, u32 ofs, size_t len)
++{
++ u8 cmd[4];
++ u32 sr1nv_offset = 0x0;
++ u8 sr1nv;
++ int ret;
++
++ cmd[0] = CMD_SPANSION_RDAR;
++ cmd[1] = sr1nv_offset >> 16;
++ cmd[2] = sr1nv_offset >> 8;
++ cmd[3] = sr1nv_offset >> 0;
++
++ ret = spi_flash_cmd_read(flash->spi, cmd, 4, &sr1nv, 1);
++ if (ret)
++ return -EIO;
++
++ return spansion_is_locked_sr(flash, ofs, len, sr1nv);
++}
++
++/*
++ * Lock a region of the flash. Compatible with Spansion s25fs-s family flash.
++ * Supports only the block protection bits BP{0,1,2} in the Status Register-1
++ * Non-Volatile(SR1NV).
++ *
++ * Sample table portion for 64MB flash (S25FS512S):
++ * Configuration Register-1 Non-Volatile(CR1NV[5])== 0
++ *
++ * | BP2 | BP1 | BP0 | Prot Length | Protected Portion
++ * ------------------------------------------------------------
++ * | 0 | 0 | 0 | NONE | NONE
++ * | 0 | 0 | 1 | 1 MB | Upper 1/64
++ * | 0 | 1 | 0 | 2 MB | Upper 1/32
++ * | 0 | 1 | 1 | 4 MB | Upper 1/16
++ * | 1 | 0 | 0 | 8 MB | Upper 1/8
++ * | 1 | 0 | 1 | 16 MB | Upper 1/4
++ * | 1 | 1 | 0 | 32 MB | Upper 1/2
++ * | 1 | 1 | 1 | 64 MB | ALL
++ *
++ * When CR1NV[5] == 1, the Lower memory array are protected.
++ *
++ * Returns negative on errors, 0 on success.
++ */
++int spansion_lock(struct spi_flash *flash, u32 ofs, size_t len)
++{
++ u8 status_old, status_new;
++ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++ u8 shift = ffs(mask) - 1, pow, val;
++ int ret;
++ u8 cmd[4];
++ u32 sr1nv_offset = 0x0;
++ u8 sr1nv;
++
++ cmd[0] = CMD_SPANSION_RDAR;
++ cmd[1] = sr1nv_offset >> 16;
++ cmd[2] = sr1nv_offset >> 8;
++ cmd[3] = sr1nv_offset >> 0;
++
++ ret = spi_flash_cmd_read(flash->spi, cmd, 4, &sr1nv, 1);
++ if (ret)
++ return -EIO;
++ status_old = sr1nv;
++
++ /* SPI NOR always locks to the end */
++ if (ofs + len != flash->size) {
++ /* Does combined region extend to end? */
++ if (!stm_is_locked_sr(flash, ofs + len, flash->size - ofs - len,
++ status_old))
++ return -EINVAL;
++ len = flash->size - ofs;
++ }
++
++ /*
++ * Need smallest pow such that:
++ *
++ * 1 / (2^pow) <= (len / size)
++ *
++ * so (assuming power-of-2 size) we do:
++ *
++ * pow = ceil(log2(size / len)) = log2(size) - floor(log2(len))
++ */
++ pow = ilog2(flash->size) - ilog2(len);
++ val = mask - (pow << shift);
++ if (val & ~mask)
++ return -EINVAL;
++
++ /* Don't "lock" with no region! */
++ if (!(val & mask))
++ return -EINVAL;
++
++ status_new = (status_old & ~mask) | val;
++
++ /* Only modify protection if it will not unlock other areas */
++ if ((status_new & mask) <= (status_old & mask))
++ return -EINVAL;
++
++ cmd[0] = CMD_SPANSION_WRAR;
++ ret = spi_flash_cmd_write(flash->spi, cmd, 4, &status_new, 1);
++ if (ret)
++ return -EIO;
++
++ return 0;
++}
++
++/*
++ * Unlock a region of the flash. See spansion_lock() for more info
++ *
++ * Returns negative on errors, 0 on success.
++ */
++int spansion_unlock(struct spi_flash *flash, u32 ofs, size_t len)
++{
++ uint8_t status_old, status_new;
++ u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
++ u8 shift = ffs(mask) - 1, pow, val;
++ int ret;
++
++ u8 cmd[4];
++ u32 sr1nv_offset = 0x0;
++ u8 sr1nv;
++
++ cmd[0] = CMD_SPANSION_RDAR;
++ cmd[1] = sr1nv_offset >> 16;
++ cmd[2] = sr1nv_offset >> 8;
++ cmd[3] = sr1nv_offset >> 0;
++
++ ret = spi_flash_cmd_read(flash->spi, cmd, 4, &sr1nv, 1);
++ if (ret)
++ return -EIO;
++ status_old = sr1nv;
++
++ /* Cannot unlock; would unlock larger region than requested */
++ if (spansion_is_locked_sr(flash, ofs - flash->erase_size, flash->erase_size,
++ status_old))
++ return -EINVAL;
++ /*
++ * Need largest pow such that:
++ *
++ * 1 / (2^pow) >= (len / size)
++ *
++ * so (assuming power-of-2 size) we do:
++ *
++ * pow = floor(log2(size / len)) = log2(size) - ceil(log2(len))
++ */
++ pow = ilog2(flash->size) - order_base_2(flash->size - (ofs + len));
++ if (ofs + len == flash->size) {
++ val = 0; /* fully unlocked */
++ } else {
++ val = mask - (pow << shift);
++ /* Some power-of-two sizes are not supported */
++ if (val & ~mask)
++ return -EINVAL;
++ }
++ status_new = (status_old & ~mask) | val;
++
++ /* Only modify protection if it will not lock other areas */
++ if ((status_new & mask) >= (status_old & mask))
++ return -EINVAL;
++
++ cmd[0] = CMD_SPANSION_WRAR;
++ ret = spi_flash_cmd_write(flash->spi, cmd, 4, &status_new, 1);
++ if (ret)
++ return -EIO;
++
++ return 0;
++}
++#endif
+
+ #ifdef CONFIG_SPI_FLASH_MACRONIX
+ static int spi_flash_set_qeb_mxic(struct spi_flash *flash)
+@@ -1132,6 +1319,13 @@ int spi_flash_scan(struct spi_flash *flash)
+ flash->flash_is_locked = stm_is_locked;
+ #endif
+ break;
++#if defined(CONFIG_SPI_FLASH_SPANSION)
++ case SPI_FLASH_CFI_MFR_SPANSION:
++ flash->flash_lock = spansion_lock;
++ flash->flash_unlock = spansion_unlock;
++ flash->flash_is_locked = spansion_is_locked;
++#endif
++ break;
+ default:
+ debug("SF: Lock ops not supported for %02x flash\n", idcode[0]);
+ }
+--
+1.7.9.5
+