0001
0002
0003
0004
0005
0006
0007 #include <linux/mtd/spi-nor.h>
0008
0009 #include "core.h"
0010
0011 #define ATMEL_SR_GLOBAL_PROTECT_MASK GENMASK(5, 2)
0012
0013
0014
0015
0016
0017
0018
0019 static int at25fs_nor_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
0020 {
0021 return -EOPNOTSUPP;
0022 }
0023
0024 static int at25fs_nor_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
0025 {
0026 int ret;
0027
0028
0029 if (ofs || len != nor->params->size)
0030 return -EINVAL;
0031
0032
0033 ret = spi_nor_write_sr_and_check(nor, 0);
0034 if (ret)
0035 dev_dbg(nor->dev, "unable to clear BP bits, WP# asserted?\n");
0036
0037 return ret;
0038 }
0039
0040 static int at25fs_nor_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
0041 {
0042 return -EOPNOTSUPP;
0043 }
0044
0045 static const struct spi_nor_locking_ops at25fs_nor_locking_ops = {
0046 .lock = at25fs_nor_lock,
0047 .unlock = at25fs_nor_unlock,
0048 .is_locked = at25fs_nor_is_locked,
0049 };
0050
0051 static void at25fs_nor_late_init(struct spi_nor *nor)
0052 {
0053 nor->params->locking_ops = &at25fs_nor_locking_ops;
0054 }
0055
0056 static const struct spi_nor_fixups at25fs_nor_fixups = {
0057 .late_init = at25fs_nor_late_init,
0058 };
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 static int atmel_nor_set_global_protection(struct spi_nor *nor, loff_t ofs,
0070 uint64_t len, bool is_protect)
0071 {
0072 int ret;
0073 u8 sr;
0074
0075
0076 if (ofs || len != nor->params->size)
0077 return -EINVAL;
0078
0079 ret = spi_nor_read_sr(nor, nor->bouncebuf);
0080 if (ret)
0081 return ret;
0082
0083 sr = nor->bouncebuf[0];
0084
0085
0086 if (sr & SR_SRWD) {
0087 sr &= ~SR_SRWD;
0088 ret = spi_nor_write_sr_and_check(nor, sr);
0089 if (ret) {
0090 dev_dbg(nor->dev, "unable to clear SRWD bit, WP# asserted?\n");
0091 return ret;
0092 }
0093 }
0094
0095 if (is_protect) {
0096 sr |= ATMEL_SR_GLOBAL_PROTECT_MASK;
0097
0098
0099
0100
0101
0102
0103
0104 sr |= SR_SRWD;
0105 } else {
0106 sr &= ~ATMEL_SR_GLOBAL_PROTECT_MASK;
0107 }
0108
0109 nor->bouncebuf[0] = sr;
0110
0111
0112
0113
0114
0115
0116 return spi_nor_write_sr(nor, nor->bouncebuf, 1);
0117 }
0118
0119 static int atmel_nor_global_protect(struct spi_nor *nor, loff_t ofs,
0120 uint64_t len)
0121 {
0122 return atmel_nor_set_global_protection(nor, ofs, len, true);
0123 }
0124
0125 static int atmel_nor_global_unprotect(struct spi_nor *nor, loff_t ofs,
0126 uint64_t len)
0127 {
0128 return atmel_nor_set_global_protection(nor, ofs, len, false);
0129 }
0130
0131 static int atmel_nor_is_global_protected(struct spi_nor *nor, loff_t ofs,
0132 uint64_t len)
0133 {
0134 int ret;
0135
0136 if (ofs >= nor->params->size || (ofs + len) > nor->params->size)
0137 return -EINVAL;
0138
0139 ret = spi_nor_read_sr(nor, nor->bouncebuf);
0140 if (ret)
0141 return ret;
0142
0143 return ((nor->bouncebuf[0] & ATMEL_SR_GLOBAL_PROTECT_MASK) == ATMEL_SR_GLOBAL_PROTECT_MASK);
0144 }
0145
0146 static const struct spi_nor_locking_ops atmel_nor_global_protection_ops = {
0147 .lock = atmel_nor_global_protect,
0148 .unlock = atmel_nor_global_unprotect,
0149 .is_locked = atmel_nor_is_global_protected,
0150 };
0151
0152 static void atmel_nor_global_protection_late_init(struct spi_nor *nor)
0153 {
0154 nor->params->locking_ops = &atmel_nor_global_protection_ops;
0155 }
0156
0157 static const struct spi_nor_fixups atmel_nor_global_protection_fixups = {
0158 .late_init = atmel_nor_global_protection_late_init,
0159 };
0160
0161 static const struct flash_info atmel_nor_parts[] = {
0162
0163 { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4)
0164 FLAGS(SPI_NOR_HAS_LOCK)
0165 NO_SFDP_FLAGS(SECT_4K)
0166 .fixups = &at25fs_nor_fixups },
0167 { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8)
0168 FLAGS(SPI_NOR_HAS_LOCK)
0169 NO_SFDP_FLAGS(SECT_4K)
0170 .fixups = &at25fs_nor_fixups },
0171 { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8)
0172 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0173 NO_SFDP_FLAGS(SECT_4K)
0174 .fixups = &atmel_nor_global_protection_fixups },
0175 { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64)
0176 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0177 NO_SFDP_FLAGS(SECT_4K)
0178 .fixups = &atmel_nor_global_protection_fixups },
0179 { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64)
0180 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0181 NO_SFDP_FLAGS(SECT_4K)
0182 .fixups = &atmel_nor_global_protection_fixups },
0183 { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128)
0184 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0185 NO_SFDP_FLAGS(SECT_4K)
0186 .fixups = &atmel_nor_global_protection_fixups },
0187 { "at25sl321", INFO(0x1f4216, 0, 64 * 1024, 64)
0188 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
0189 { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8)
0190 NO_SFDP_FLAGS(SECT_4K) },
0191 { "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16)
0192 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0193 NO_SFDP_FLAGS(SECT_4K)
0194 .fixups = &atmel_nor_global_protection_fixups },
0195 { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32)
0196 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0197 NO_SFDP_FLAGS(SECT_4K)
0198 .fixups = &atmel_nor_global_protection_fixups },
0199 { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64)
0200 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
0201 NO_SFDP_FLAGS(SECT_4K)
0202 .fixups = &atmel_nor_global_protection_fixups },
0203 { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16)
0204 NO_SFDP_FLAGS(SECT_4K) },
0205 };
0206
0207 const struct spi_nor_manufacturer spi_nor_atmel = {
0208 .name = "atmel",
0209 .parts = atmel_nor_parts,
0210 .nparts = ARRAY_SIZE(atmel_nor_parts),
0211 };