Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * SPI NOR Software Write Protection logic.
0004  *
0005  * Copyright (C) 2005, Intec Automation Inc.
0006  * Copyright (C) 2014, Freescale Semiconductor, Inc.
0007  */
0008 #include <linux/mtd/mtd.h>
0009 #include <linux/mtd/spi-nor.h>
0010 
0011 #include "core.h"
0012 
0013 static u8 spi_nor_get_sr_bp_mask(struct spi_nor *nor)
0014 {
0015     u8 mask = SR_BP2 | SR_BP1 | SR_BP0;
0016 
0017     if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6)
0018         return mask | SR_BP3_BIT6;
0019 
0020     if (nor->flags & SNOR_F_HAS_4BIT_BP)
0021         return mask | SR_BP3;
0022 
0023     return mask;
0024 }
0025 
0026 static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor)
0027 {
0028     if (nor->flags & SNOR_F_HAS_SR_TB_BIT6)
0029         return SR_TB_BIT6;
0030     else
0031         return SR_TB_BIT5;
0032 }
0033 
0034 static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
0035 {
0036     unsigned int bp_slots, bp_slots_needed;
0037     u8 mask = spi_nor_get_sr_bp_mask(nor);
0038 
0039     /* Reserved one for "protect none" and one for "protect all". */
0040     bp_slots = (1 << hweight8(mask)) - 2;
0041     bp_slots_needed = ilog2(nor->info->n_sectors);
0042 
0043     if (bp_slots_needed > bp_slots)
0044         return nor->info->sector_size <<
0045             (bp_slots_needed - bp_slots);
0046     else
0047         return nor->info->sector_size;
0048 }
0049 
0050 static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
0051                     uint64_t *len)
0052 {
0053     struct mtd_info *mtd = &nor->mtd;
0054     u64 min_prot_len;
0055     u8 mask = spi_nor_get_sr_bp_mask(nor);
0056     u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
0057     u8 bp, val = sr & mask;
0058 
0059     if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6)
0060         val = (val & ~SR_BP3_BIT6) | SR_BP3;
0061 
0062     bp = val >> SR_BP_SHIFT;
0063 
0064     if (!bp) {
0065         /* No protection */
0066         *ofs = 0;
0067         *len = 0;
0068         return;
0069     }
0070 
0071     min_prot_len = spi_nor_get_min_prot_length_sr(nor);
0072     *len = min_prot_len << (bp - 1);
0073 
0074     if (*len > mtd->size)
0075         *len = mtd->size;
0076 
0077     if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)
0078         *ofs = 0;
0079     else
0080         *ofs = mtd->size - *len;
0081 }
0082 
0083 /*
0084  * Return true if the entire region is locked (if @locked is true) or unlocked
0085  * (if @locked is false); false otherwise.
0086  */
0087 static bool spi_nor_check_lock_status_sr(struct spi_nor *nor, loff_t ofs,
0088                      uint64_t len, u8 sr, bool locked)
0089 {
0090     loff_t lock_offs, lock_offs_max, offs_max;
0091     uint64_t lock_len;
0092 
0093     if (!len)
0094         return true;
0095 
0096     spi_nor_get_locked_range_sr(nor, sr, &lock_offs, &lock_len);
0097 
0098     lock_offs_max = lock_offs + lock_len;
0099     offs_max = ofs + len;
0100 
0101     if (locked)
0102         /* Requested range is a sub-range of locked range */
0103         return (offs_max <= lock_offs_max) && (ofs >= lock_offs);
0104     else
0105         /* Requested range does not overlap with locked range */
0106         return (ofs >= lock_offs_max) || (offs_max <= lock_offs);
0107 }
0108 
0109 static bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, uint64_t len,
0110                  u8 sr)
0111 {
0112     return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true);
0113 }
0114 
0115 static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs,
0116                    uint64_t len, u8 sr)
0117 {
0118     return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false);
0119 }
0120 
0121 /*
0122  * Lock a region of the flash. Compatible with ST Micro and similar flash.
0123  * Supports the block protection bits BP{0,1,2}/BP{0,1,2,3} in the status
0124  * register
0125  * (SR). Does not support these features found in newer SR bitfields:
0126  *   - SEC: sector/block protect - only handle SEC=0 (block protect)
0127  *   - CMP: complement protect - only support CMP=0 (range is not complemented)
0128  *
0129  * Support for the following is provided conditionally for some flash:
0130  *   - TB: top/bottom protect
0131  *
0132  * Sample table portion for 8MB flash (Winbond w25q64fw):
0133  *
0134  *   SEC  |  TB   |  BP2  |  BP1  |  BP0  |  Prot Length  | Protected Portion
0135  *  --------------------------------------------------------------------------
0136  *    X   |   X   |   0   |   0   |   0   |  NONE         | NONE
0137  *    0   |   0   |   0   |   0   |   1   |  128 KB       | Upper 1/64
0138  *    0   |   0   |   0   |   1   |   0   |  256 KB       | Upper 1/32
0139  *    0   |   0   |   0   |   1   |   1   |  512 KB       | Upper 1/16
0140  *    0   |   0   |   1   |   0   |   0   |  1 MB         | Upper 1/8
0141  *    0   |   0   |   1   |   0   |   1   |  2 MB         | Upper 1/4
0142  *    0   |   0   |   1   |   1   |   0   |  4 MB         | Upper 1/2
0143  *    X   |   X   |   1   |   1   |   1   |  8 MB         | ALL
0144  *  ------|-------|-------|-------|-------|---------------|-------------------
0145  *    0   |   1   |   0   |   0   |   1   |  128 KB       | Lower 1/64
0146  *    0   |   1   |   0   |   1   |   0   |  256 KB       | Lower 1/32
0147  *    0   |   1   |   0   |   1   |   1   |  512 KB       | Lower 1/16
0148  *    0   |   1   |   1   |   0   |   0   |  1 MB         | Lower 1/8
0149  *    0   |   1   |   1   |   0   |   1   |  2 MB         | Lower 1/4
0150  *    0   |   1   |   1   |   1   |   0   |  4 MB         | Lower 1/2
0151  *
0152  * Returns negative on errors, 0 on success.
0153  */
0154 static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
0155 {
0156     struct mtd_info *mtd = &nor->mtd;
0157     u64 min_prot_len;
0158     int ret, status_old, status_new;
0159     u8 mask = spi_nor_get_sr_bp_mask(nor);
0160     u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
0161     u8 pow, val;
0162     loff_t lock_len;
0163     bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
0164     bool use_top;
0165 
0166     ret = spi_nor_read_sr(nor, nor->bouncebuf);
0167     if (ret)
0168         return ret;
0169 
0170     status_old = nor->bouncebuf[0];
0171 
0172     /* If nothing in our range is unlocked, we don't need to do anything */
0173     if (spi_nor_is_locked_sr(nor, ofs, len, status_old))
0174         return 0;
0175 
0176     /* If anything below us is unlocked, we can't use 'bottom' protection */
0177     if (!spi_nor_is_locked_sr(nor, 0, ofs, status_old))
0178         can_be_bottom = false;
0179 
0180     /* If anything above us is unlocked, we can't use 'top' protection */
0181     if (!spi_nor_is_locked_sr(nor, ofs + len, mtd->size - (ofs + len),
0182                   status_old))
0183         can_be_top = false;
0184 
0185     if (!can_be_bottom && !can_be_top)
0186         return -EINVAL;
0187 
0188     /* Prefer top, if both are valid */
0189     use_top = can_be_top;
0190 
0191     /* lock_len: length of region that should end up locked */
0192     if (use_top)
0193         lock_len = mtd->size - ofs;
0194     else
0195         lock_len = ofs + len;
0196 
0197     if (lock_len == mtd->size) {
0198         val = mask;
0199     } else {
0200         min_prot_len = spi_nor_get_min_prot_length_sr(nor);
0201         pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;
0202         val = pow << SR_BP_SHIFT;
0203 
0204         if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
0205             val = (val & ~SR_BP3) | SR_BP3_BIT6;
0206 
0207         if (val & ~mask)
0208             return -EINVAL;
0209 
0210         /* Don't "lock" with no region! */
0211         if (!(val & mask))
0212             return -EINVAL;
0213     }
0214 
0215     status_new = (status_old & ~mask & ~tb_mask) | val;
0216 
0217     /* Disallow further writes if WP pin is asserted */
0218     status_new |= SR_SRWD;
0219 
0220     if (!use_top)
0221         status_new |= tb_mask;
0222 
0223     /* Don't bother if they're the same */
0224     if (status_new == status_old)
0225         return 0;
0226 
0227     /* Only modify protection if it will not unlock other areas */
0228     if ((status_new & mask) < (status_old & mask))
0229         return -EINVAL;
0230 
0231     return spi_nor_write_sr_and_check(nor, status_new);
0232 }
0233 
0234 /*
0235  * Unlock a region of the flash. See spi_nor_sr_lock() for more info
0236  *
0237  * Returns negative on errors, 0 on success.
0238  */
0239 static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
0240 {
0241     struct mtd_info *mtd = &nor->mtd;
0242     u64 min_prot_len;
0243     int ret, status_old, status_new;
0244     u8 mask = spi_nor_get_sr_bp_mask(nor);
0245     u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
0246     u8 pow, val;
0247     loff_t lock_len;
0248     bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;
0249     bool use_top;
0250 
0251     ret = spi_nor_read_sr(nor, nor->bouncebuf);
0252     if (ret)
0253         return ret;
0254 
0255     status_old = nor->bouncebuf[0];
0256 
0257     /* If nothing in our range is locked, we don't need to do anything */
0258     if (spi_nor_is_unlocked_sr(nor, ofs, len, status_old))
0259         return 0;
0260 
0261     /* If anything below us is locked, we can't use 'top' protection */
0262     if (!spi_nor_is_unlocked_sr(nor, 0, ofs, status_old))
0263         can_be_top = false;
0264 
0265     /* If anything above us is locked, we can't use 'bottom' protection */
0266     if (!spi_nor_is_unlocked_sr(nor, ofs + len, mtd->size - (ofs + len),
0267                     status_old))
0268         can_be_bottom = false;
0269 
0270     if (!can_be_bottom && !can_be_top)
0271         return -EINVAL;
0272 
0273     /* Prefer top, if both are valid */
0274     use_top = can_be_top;
0275 
0276     /* lock_len: length of region that should remain locked */
0277     if (use_top)
0278         lock_len = mtd->size - (ofs + len);
0279     else
0280         lock_len = ofs;
0281 
0282     if (lock_len == 0) {
0283         val = 0; /* fully unlocked */
0284     } else {
0285         min_prot_len = spi_nor_get_min_prot_length_sr(nor);
0286         pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;
0287         val = pow << SR_BP_SHIFT;
0288 
0289         if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
0290             val = (val & ~SR_BP3) | SR_BP3_BIT6;
0291 
0292         /* Some power-of-two sizes are not supported */
0293         if (val & ~mask)
0294             return -EINVAL;
0295     }
0296 
0297     status_new = (status_old & ~mask & ~tb_mask) | val;
0298 
0299     /* Don't protect status register if we're fully unlocked */
0300     if (lock_len == 0)
0301         status_new &= ~SR_SRWD;
0302 
0303     if (!use_top)
0304         status_new |= tb_mask;
0305 
0306     /* Don't bother if they're the same */
0307     if (status_new == status_old)
0308         return 0;
0309 
0310     /* Only modify protection if it will not lock other areas */
0311     if ((status_new & mask) > (status_old & mask))
0312         return -EINVAL;
0313 
0314     return spi_nor_write_sr_and_check(nor, status_new);
0315 }
0316 
0317 /*
0318  * Check if a region of the flash is (completely) locked. See spi_nor_sr_lock()
0319  * for more info.
0320  *
0321  * Returns 1 if entire region is locked, 0 if any portion is unlocked, and
0322  * negative on errors.
0323  */
0324 static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
0325 {
0326     int ret;
0327 
0328     ret = spi_nor_read_sr(nor, nor->bouncebuf);
0329     if (ret)
0330         return ret;
0331 
0332     return spi_nor_is_locked_sr(nor, ofs, len, nor->bouncebuf[0]);
0333 }
0334 
0335 static const struct spi_nor_locking_ops spi_nor_sr_locking_ops = {
0336     .lock = spi_nor_sr_lock,
0337     .unlock = spi_nor_sr_unlock,
0338     .is_locked = spi_nor_sr_is_locked,
0339 };
0340 
0341 void spi_nor_init_default_locking_ops(struct spi_nor *nor)
0342 {
0343     nor->params->locking_ops = &spi_nor_sr_locking_ops;
0344 }
0345 
0346 static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
0347 {
0348     struct spi_nor *nor = mtd_to_spi_nor(mtd);
0349     int ret;
0350 
0351     ret = spi_nor_lock_and_prep(nor);
0352     if (ret)
0353         return ret;
0354 
0355     ret = nor->params->locking_ops->lock(nor, ofs, len);
0356 
0357     spi_nor_unlock_and_unprep(nor);
0358     return ret;
0359 }
0360 
0361 static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
0362 {
0363     struct spi_nor *nor = mtd_to_spi_nor(mtd);
0364     int ret;
0365 
0366     ret = spi_nor_lock_and_prep(nor);
0367     if (ret)
0368         return ret;
0369 
0370     ret = nor->params->locking_ops->unlock(nor, ofs, len);
0371 
0372     spi_nor_unlock_and_unprep(nor);
0373     return ret;
0374 }
0375 
0376 static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
0377 {
0378     struct spi_nor *nor = mtd_to_spi_nor(mtd);
0379     int ret;
0380 
0381     ret = spi_nor_lock_and_prep(nor);
0382     if (ret)
0383         return ret;
0384 
0385     ret = nor->params->locking_ops->is_locked(nor, ofs, len);
0386 
0387     spi_nor_unlock_and_unprep(nor);
0388     return ret;
0389 }
0390 
0391 /**
0392  * spi_nor_try_unlock_all() - Tries to unlock the entire flash memory array.
0393  * @nor:    pointer to a 'struct spi_nor'.
0394  *
0395  * Some SPI NOR flashes are write protected by default after a power-on reset
0396  * cycle, in order to avoid inadvertent writes during power-up. Backward
0397  * compatibility imposes to unlock the entire flash memory array at power-up
0398  * by default.
0399  *
0400  * Unprotecting the entire flash array will fail for boards which are hardware
0401  * write-protected. Thus any errors are ignored.
0402  */
0403 void spi_nor_try_unlock_all(struct spi_nor *nor)
0404 {
0405     int ret;
0406 
0407     if (!(nor->flags & SNOR_F_HAS_LOCK))
0408         return;
0409 
0410     dev_dbg(nor->dev, "Unprotecting entire flash array\n");
0411 
0412     ret = spi_nor_unlock(&nor->mtd, 0, nor->params->size);
0413     if (ret)
0414         dev_dbg(nor->dev, "Failed to unlock the entire flash memory array\n");
0415 }
0416 
0417 void spi_nor_set_mtd_locking_ops(struct spi_nor *nor)
0418 {
0419     struct mtd_info *mtd = &nor->mtd;
0420 
0421     if (!nor->params->locking_ops)
0422         return;
0423 
0424     mtd->_lock = spi_nor_lock;
0425     mtd->_unlock = spi_nor_unlock;
0426     mtd->_is_locked = spi_nor_is_locked;
0427 }