1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2005, Intec Automation Inc.
4 * Copyright (C) 2014, Freescale Semiconductor, Inc.
7 #include <linux/mtd/spi-nor.h>
11 /* SST flash_info mfr_flag. Used to specify SST byte programming. */
12 #define SST_WRITE BIT(0)
14 #define SST26VF_CR_BPNV BIT(3)
16 static int sst26vf_nor_lock(struct spi_nor *nor, loff_t ofs, u64 len)
21 static int sst26vf_nor_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
25 /* We only support unlocking the entire flash array. */
26 if (ofs != 0 || len != nor->params->size)
29 ret = spi_nor_read_cr(nor, nor->bouncebuf);
33 if (!(nor->bouncebuf[0] & SST26VF_CR_BPNV)) {
34 dev_dbg(nor->dev, "Any block has been permanently locked\n");
38 return spi_nor_global_block_unlock(nor);
41 static int sst26vf_nor_is_locked(struct spi_nor *nor, loff_t ofs, u64 len)
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,
52 static int sst26vf_nor_late_init(struct spi_nor *nor)
54 nor->params->locking_ops = &sst26vf_nor_locking_ops;
59 static const struct spi_nor_fixups sst26vf_nor_fixups = {
60 .late_init = sst26vf_nor_late_init,
63 static const struct flash_info sst_nor_parts[] = {
65 .id = SNOR_ID(0x62, 0x16, 0x12),
66 .name = "sst25wf020a",
68 .flags = SPI_NOR_HAS_LOCK,
69 .no_sfdp_flags = SECT_4K,
71 .id = SNOR_ID(0x62, 0x16, 0x13),
72 .name = "sst25wf040b",
74 .flags = SPI_NOR_HAS_LOCK,
75 .no_sfdp_flags = SECT_4K,
77 .id = SNOR_ID(0xbf, 0x25, 0x01),
80 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
81 .no_sfdp_flags = SECT_4K,
82 .mfr_flags = SST_WRITE,
84 .id = SNOR_ID(0xbf, 0x25, 0x02),
87 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
88 .no_sfdp_flags = SECT_4K,
89 .mfr_flags = SST_WRITE,
91 .id = SNOR_ID(0xbf, 0x25, 0x03),
94 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
95 .no_sfdp_flags = SECT_4K,
96 .mfr_flags = SST_WRITE,
98 .id = SNOR_ID(0xbf, 0x25, 0x04),
101 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
102 .no_sfdp_flags = SECT_4K,
103 .mfr_flags = SST_WRITE,
105 .id = SNOR_ID(0xbf, 0x25, 0x05),
106 .name = "sst25wf080",
108 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
109 .no_sfdp_flags = SECT_4K,
110 .mfr_flags = SST_WRITE,
112 .id = SNOR_ID(0xbf, 0x25, 0x41),
113 .name = "sst25vf016b",
115 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
116 .no_sfdp_flags = SECT_4K,
117 .mfr_flags = SST_WRITE,
119 .id = SNOR_ID(0xbf, 0x25, 0x4a),
120 .name = "sst25vf032b",
122 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
123 .no_sfdp_flags = SECT_4K,
124 .mfr_flags = SST_WRITE,
126 .id = SNOR_ID(0xbf, 0x25, 0x4b),
127 .name = "sst25vf064c",
129 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP | SPI_NOR_SWP_IS_VOLATILE,
130 .no_sfdp_flags = SECT_4K,
132 .id = SNOR_ID(0xbf, 0x25, 0x8d),
133 .name = "sst25vf040b",
135 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
136 .no_sfdp_flags = SECT_4K,
137 .mfr_flags = SST_WRITE,
139 .id = SNOR_ID(0xbf, 0x25, 0x8e),
140 .name = "sst25vf080b",
142 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
143 .no_sfdp_flags = SECT_4K,
144 .mfr_flags = SST_WRITE,
146 .id = SNOR_ID(0xbf, 0x26, 0x41),
147 .name = "sst26vf016b",
149 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ,
151 .id = SNOR_ID(0xbf, 0x26, 0x42),
152 .name = "sst26vf032b",
153 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
154 .fixups = &sst26vf_nor_fixups,
156 .id = SNOR_ID(0xbf, 0x26, 0x43),
157 .name = "sst26vf064b",
159 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE,
160 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
161 .fixups = &sst26vf_nor_fixups,
163 .id = SNOR_ID(0xbf, 0x26, 0x51),
164 .name = "sst26wf016b",
166 .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
170 static int sst_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
173 u8 op = (len == 1) ? SPINOR_OP_BP : SPINOR_OP_AAI_WP;
176 nor->program_opcode = op;
177 ret = spi_nor_write_data(nor, to, 1, buf);
180 WARN(ret != len, "While writing %zu byte written %i bytes\n", len, ret);
182 return spi_nor_wait_till_ready(nor);
185 static int sst_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
186 size_t *retlen, const u_char *buf)
188 struct spi_nor *nor = mtd_to_spi_nor(mtd);
192 dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
194 ret = spi_nor_prep_and_lock(nor);
198 ret = spi_nor_write_enable(nor);
202 nor->sst_write_second = false;
204 /* Start write from odd address. */
206 /* write one byte. */
207 ret = sst_nor_write_data(nor, to, 1, buf);
215 /* Write out most of the data here. */
216 for (; actual < len - 1; actual += 2) {
217 /* write two bytes. */
218 ret = sst_nor_write_data(nor, to, 2, buf + actual);
223 nor->sst_write_second = true;
225 nor->sst_write_second = false;
227 ret = spi_nor_write_disable(nor);
231 ret = spi_nor_wait_till_ready(nor);
235 /* Write out trailing byte if it exists. */
237 ret = spi_nor_write_enable(nor);
241 ret = sst_nor_write_data(nor, to, 1, buf + actual);
247 ret = spi_nor_write_disable(nor);
251 spi_nor_unlock_and_unprep(nor);
255 static int sst_nor_late_init(struct spi_nor *nor)
257 if (nor->info->mfr_flags & SST_WRITE)
258 nor->mtd._write = sst_nor_write;
263 static const struct spi_nor_fixups sst_nor_fixups = {
264 .late_init = sst_nor_late_init,
267 const struct spi_nor_manufacturer spi_nor_sst = {
269 .parts = sst_nor_parts,
270 .nparts = ARRAY_SIZE(sst_nor_parts),
271 .fixups = &sst_nor_fixups,