Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2005, Intec Automation Inc.
0004  * Copyright (C) 2014, Freescale Semiconductor, Inc.
0005  */
0006 
0007 #include <linux/mtd/spi-nor.h>
0008 
0009 #include "core.h"
0010 
0011 /* SST flash_info mfr_flag. Used to specify SST byte programming. */
0012 #define SST_WRITE       BIT(0)
0013 
0014 #define SST26VF_CR_BPNV     BIT(3)
0015 
0016 static int sst26vf_nor_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
0017 {
0018     return -EOPNOTSUPP;
0019 }
0020 
0021 static int sst26vf_nor_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
0022 {
0023     int ret;
0024 
0025     /* We only support unlocking the entire flash array. */
0026     if (ofs != 0 || len != nor->params->size)
0027         return -EINVAL;
0028 
0029     ret = spi_nor_read_cr(nor, nor->bouncebuf);
0030     if (ret)
0031         return ret;
0032 
0033     if (!(nor->bouncebuf[0] & SST26VF_CR_BPNV)) {
0034         dev_dbg(nor->dev, "Any block has been permanently locked\n");
0035         return -EINVAL;
0036     }
0037 
0038     return spi_nor_global_block_unlock(nor);
0039 }
0040 
0041 static int sst26vf_nor_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
0042 {
0043     return -EOPNOTSUPP;
0044 }
0045 
0046 static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = {
0047     .lock = sst26vf_nor_lock,
0048     .unlock = sst26vf_nor_unlock,
0049     .is_locked = sst26vf_nor_is_locked,
0050 };
0051 
0052 static void sst26vf_nor_late_init(struct spi_nor *nor)
0053 {
0054     nor->params->locking_ops = &sst26vf_nor_locking_ops;
0055 }
0056 
0057 static const struct spi_nor_fixups sst26vf_nor_fixups = {
0058     .late_init = sst26vf_nor_late_init,
0059 };
0060 
0061 static const struct flash_info sst_nor_parts[] = {
0062     /* SST -- large erase sizes are "overlays", "sectors" are 4K */
0063     { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8)
0064         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0065         NO_SFDP_FLAGS(SECT_4K)
0066         MFR_FLAGS(SST_WRITE) },
0067     { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16)
0068         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0069         NO_SFDP_FLAGS(SECT_4K)
0070         MFR_FLAGS(SST_WRITE) },
0071     { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32)
0072         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0073         NO_SFDP_FLAGS(SECT_4K)
0074         MFR_FLAGS(SST_WRITE) },
0075     { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64)
0076         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0077         NO_SFDP_FLAGS(SECT_4K)
0078         MFR_FLAGS(SST_WRITE) },
0079     { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128)
0080         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP |
0081               SPI_NOR_SWP_IS_VOLATILE)
0082         NO_SFDP_FLAGS(SECT_4K) },
0083     { "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1)
0084         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0085         NO_SFDP_FLAGS(SECT_4K)
0086         MFR_FLAGS(SST_WRITE) },
0087     { "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2)
0088         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0089         NO_SFDP_FLAGS(SECT_4K)
0090         MFR_FLAGS(SST_WRITE) },
0091     { "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4)
0092         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0093         NO_SFDP_FLAGS(SECT_4K)
0094         MFR_FLAGS(SST_WRITE) },
0095     { "sst25wf020a", INFO(0x621612, 0, 64 * 1024,  4)
0096         FLAGS(SPI_NOR_HAS_LOCK)
0097         NO_SFDP_FLAGS(SECT_4K) },
0098     { "sst25wf040b", INFO(0x621613, 0, 64 * 1024,  8)
0099         FLAGS(SPI_NOR_HAS_LOCK)
0100         NO_SFDP_FLAGS(SECT_4K) },
0101     { "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8)
0102         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0103         NO_SFDP_FLAGS(SECT_4K)
0104         MFR_FLAGS(SST_WRITE) },
0105     { "sst25wf080",  INFO(0xbf2505, 0, 64 * 1024, 16)
0106         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0107         NO_SFDP_FLAGS(SECT_4K)
0108         MFR_FLAGS(SST_WRITE) },
0109     { "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32)
0110         NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
0111                   SPI_NOR_QUAD_READ) },
0112     { "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32)
0113         NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
0114     { "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128)
0115         FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0116         NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
0117         .fixups = &sst26vf_nor_fixups },
0118 };
0119 
0120 static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
0121              size_t *retlen, const u_char *buf)
0122 {
0123     struct spi_nor *nor = mtd_to_spi_nor(mtd);
0124     size_t actual = 0;
0125     int ret;
0126 
0127     dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
0128 
0129     ret = spi_nor_lock_and_prep(nor);
0130     if (ret)
0131         return ret;
0132 
0133     ret = spi_nor_write_enable(nor);
0134     if (ret)
0135         goto out;
0136 
0137     nor->sst_write_second = false;
0138 
0139     /* Start write from odd address. */
0140     if (to % 2) {
0141         nor->program_opcode = SPINOR_OP_BP;
0142 
0143         /* write one byte. */
0144         ret = spi_nor_write_data(nor, to, 1, buf);
0145         if (ret < 0)
0146             goto out;
0147         WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
0148         ret = spi_nor_wait_till_ready(nor);
0149         if (ret)
0150             goto out;
0151 
0152         to++;
0153         actual++;
0154     }
0155 
0156     /* Write out most of the data here. */
0157     for (; actual < len - 1; actual += 2) {
0158         nor->program_opcode = SPINOR_OP_AAI_WP;
0159 
0160         /* write two bytes. */
0161         ret = spi_nor_write_data(nor, to, 2, buf + actual);
0162         if (ret < 0)
0163             goto out;
0164         WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret);
0165         ret = spi_nor_wait_till_ready(nor);
0166         if (ret)
0167             goto out;
0168         to += 2;
0169         nor->sst_write_second = true;
0170     }
0171     nor->sst_write_second = false;
0172 
0173     ret = spi_nor_write_disable(nor);
0174     if (ret)
0175         goto out;
0176 
0177     ret = spi_nor_wait_till_ready(nor);
0178     if (ret)
0179         goto out;
0180 
0181     /* Write out trailing byte if it exists. */
0182     if (actual != len) {
0183         ret = spi_nor_write_enable(nor);
0184         if (ret)
0185             goto out;
0186 
0187         nor->program_opcode = SPINOR_OP_BP;
0188         ret = spi_nor_write_data(nor, to, 1, buf + actual);
0189         if (ret < 0)
0190             goto out;
0191         WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret);
0192         ret = spi_nor_wait_till_ready(nor);
0193         if (ret)
0194             goto out;
0195 
0196         actual += 1;
0197 
0198         ret = spi_nor_write_disable(nor);
0199     }
0200 out:
0201     *retlen += actual;
0202     spi_nor_unlock_and_unprep(nor);
0203     return ret;
0204 }
0205 
0206 static void sst_nor_late_init(struct spi_nor *nor)
0207 {
0208     if (nor->info->mfr_flags & SST_WRITE)
0209         nor->mtd._write = sst_nor_write;
0210 }
0211 
0212 static const struct spi_nor_fixups sst_nor_fixups = {
0213     .late_init = sst_nor_late_init,
0214 };
0215 
0216 const struct spi_nor_manufacturer spi_nor_sst = {
0217     .name = "sst",
0218     .parts = sst_nor_parts,
0219     .nparts = ARRAY_SIZE(sst_nor_parts),
0220     .fixups = &sst_nor_fixups,
0221 };