0001
0002
0003
0004
0005
0006
0007 #include <linux/mtd/spi-nor.h>
0008
0009 #include "core.h"
0010
0011
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
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
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
0140 if (to % 2) {
0141 nor->program_opcode = SPINOR_OP_BP;
0142
0143
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
0157 for (; actual < len - 1; actual += 2) {
0158 nor->program_opcode = SPINOR_OP_AAI_WP;
0159
0160
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
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 };