sst.c 5.7 KB

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