1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2005, Intec Automation Inc. 4 * Copyright (C) 2014, Freescale Semiconductor, Inc. 5 */ 6 7 #include <linux/mtd/spi-nor.h> 8 9 #include "core.h" 10 11 /* SST flash_info mfr_flag. Used to specify SST byte programming. */ 12 #define SST_WRITE BIT(0) 13 14 #define SST26VF_CR_BPNV BIT(3) 15 16 static int sst26vf_nor_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) 17 { 18 return -EOPNOTSUPP; 19 } 20 21 static int sst26vf_nor_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) 22 { 23 int ret; 24 25 /* We only support unlocking the entire flash array. */ 26 if (ofs != 0 || len != nor->params->size) 27 return -EINVAL; 28 29 ret = spi_nor_read_cr(nor, nor->bouncebuf); 30 if (ret) 31 return ret; 32 33 if (!(nor->bouncebuf[0] & SST26VF_CR_BPNV)) { 34 dev_dbg(nor->dev, "Any block has been permanently locked\n"); 35 return -EINVAL; 36 } 37 38 return spi_nor_global_block_unlock(nor); 39 } 40 41 static int sst26vf_nor_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) 42 { 43 return -EOPNOTSUPP; 44 } 45 46 static const struct spi_nor_locking_ops sst26vf_nor_locking_ops = { 47 .lock = sst26vf_nor_lock, 48 .unlock = sst26vf_nor_unlock, 49 .is_locked = sst26vf_nor_is_locked, 50 }; 51 52 static int sst26vf_nor_late_init(struct spi_nor *nor) 53 { 54 nor->params->locking_ops = &sst26vf_nor_locking_ops; 55 56 return 0; 57 } 58 59 static const struct spi_nor_fixups sst26vf_nor_fixups = { 60 .late_init = sst26vf_nor_late_init, 61 }; 62 63 static const struct flash_info sst_nor_parts[] = { 64 /* SST -- large erase sizes are "overlays", "sectors" are 4K */ 65 { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8) 66 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 67 NO_SFDP_FLAGS(SECT_4K) 68 MFR_FLAGS(SST_WRITE) }, 69 { "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16) 70 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 71 NO_SFDP_FLAGS(SECT_4K) 72 MFR_FLAGS(SST_WRITE) }, 73 { "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32) 74 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 75 NO_SFDP_FLAGS(SECT_4K) 76 MFR_FLAGS(SST_WRITE) }, 77 { "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64) 78 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 79 NO_SFDP_FLAGS(SECT_4K) 80 MFR_FLAGS(SST_WRITE) }, 81 { "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128) 82 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP | 83 SPI_NOR_SWP_IS_VOLATILE) 84 NO_SFDP_FLAGS(SECT_4K) }, 85 { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1) 86 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 87 NO_SFDP_FLAGS(SECT_4K) 88 MFR_FLAGS(SST_WRITE) }, 89 { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2) 90 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 91 NO_SFDP_FLAGS(SECT_4K) 92 MFR_FLAGS(SST_WRITE) }, 93 { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4) 94 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 95 NO_SFDP_FLAGS(SECT_4K) 96 MFR_FLAGS(SST_WRITE) }, 97 { "sst25wf020a", INFO(0x621612, 0, 64 * 1024, 4) 98 FLAGS(SPI_NOR_HAS_LOCK) 99 NO_SFDP_FLAGS(SECT_4K) }, 100 { "sst25wf040b", INFO(0x621613, 0, 64 * 1024, 8) 101 FLAGS(SPI_NOR_HAS_LOCK) 102 NO_SFDP_FLAGS(SECT_4K) }, 103 { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8) 104 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 105 NO_SFDP_FLAGS(SECT_4K) 106 MFR_FLAGS(SST_WRITE) }, 107 { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16) 108 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 109 NO_SFDP_FLAGS(SECT_4K) 110 MFR_FLAGS(SST_WRITE) }, 111 { "sst26wf016b", INFO(0xbf2651, 0, 64 * 1024, 32) 112 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | 113 SPI_NOR_QUAD_READ) }, 114 { "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32) 115 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) }, 116 { "sst26vf032b", INFO(0xbf2642, 0, 0, 0) 117 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 118 PARSE_SFDP 119 .fixups = &sst26vf_nor_fixups }, 120 { "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128) 121 FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE) 122 NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) 123 .fixups = &sst26vf_nor_fixups }, 124 }; 125 126 static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len, 127 size_t *retlen, const u_char *buf) 128 { 129 struct spi_nor *nor = mtd_to_spi_nor(mtd); 130 size_t actual = 0; 131 int ret; 132 133 dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len); 134 135 ret = spi_nor_prep_and_lock(nor); 136 if (ret) 137 return ret; 138 139 ret = spi_nor_write_enable(nor); 140 if (ret) 141 goto out; 142 143 nor->sst_write_second = false; 144 145 /* Start write from odd address. */ 146 if (to % 2) { 147 nor->program_opcode = SPINOR_OP_BP; 148 149 /* write one byte. */ 150 ret = spi_nor_write_data(nor, to, 1, buf); 151 if (ret < 0) 152 goto out; 153 WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); 154 ret = spi_nor_wait_till_ready(nor); 155 if (ret) 156 goto out; 157 158 to++; 159 actual++; 160 } 161 162 /* Write out most of the data here. */ 163 for (; actual < len - 1; actual += 2) { 164 nor->program_opcode = SPINOR_OP_AAI_WP; 165 166 /* write two bytes. */ 167 ret = spi_nor_write_data(nor, to, 2, buf + actual); 168 if (ret < 0) 169 goto out; 170 WARN(ret != 2, "While writing 2 bytes written %i bytes\n", ret); 171 ret = spi_nor_wait_till_ready(nor); 172 if (ret) 173 goto out; 174 to += 2; 175 nor->sst_write_second = true; 176 } 177 nor->sst_write_second = false; 178 179 ret = spi_nor_write_disable(nor); 180 if (ret) 181 goto out; 182 183 ret = spi_nor_wait_till_ready(nor); 184 if (ret) 185 goto out; 186 187 /* Write out trailing byte if it exists. */ 188 if (actual != len) { 189 ret = spi_nor_write_enable(nor); 190 if (ret) 191 goto out; 192 193 nor->program_opcode = SPINOR_OP_BP; 194 ret = spi_nor_write_data(nor, to, 1, buf + actual); 195 if (ret < 0) 196 goto out; 197 WARN(ret != 1, "While writing 1 byte written %i bytes\n", ret); 198 ret = spi_nor_wait_till_ready(nor); 199 if (ret) 200 goto out; 201 202 actual += 1; 203 204 ret = spi_nor_write_disable(nor); 205 } 206 out: 207 *retlen += actual; 208 spi_nor_unlock_and_unprep(nor); 209 return ret; 210 } 211 212 static int sst_nor_late_init(struct spi_nor *nor) 213 { 214 if (nor->info->mfr_flags & SST_WRITE) 215 nor->mtd._write = sst_nor_write; 216 217 return 0; 218 } 219 220 static const struct spi_nor_fixups sst_nor_fixups = { 221 .late_init = sst_nor_late_init, 222 }; 223 224 const struct spi_nor_manufacturer spi_nor_sst = { 225 .name = "sst", 226 .parts = sst_nor_parts, 227 .nparts = ARRAY_SIZE(sst_nor_parts), 228 .fixups = &sst_nor_fixups, 229 }; 230