0053-mtd-spi-nor-add-w25q256-3b-mode-switch.patch 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. mtd: spi-nor: add support for switching between 3-byte and 4-byte addressing on w25q256 flash
  2. On some devices the flash chip needs to be in 3-byte addressing mode during
  3. reboot, otherwise the boot loader will fail to start.
  4. This mode however does not allow regular reads/writes onto the upper 16M
  5. half. W25Q256 has separate read commands for reading from >16M, however
  6. it does not have any separate write commands.
  7. This patch changes the code to leave the chip in 3-byte mode most of the
  8. time and only switch during erase/write cycles that go to >16M
  9. addresses.
  10. Signed-off-by: Felix Fietkau <[email protected]>
  11. ---
  12. --- a/drivers/mtd/spi-nor/spi-nor.c
  13. +++ b/drivers/mtd/spi-nor/spi-nor.c
  14. @@ -89,6 +89,10 @@ struct flash_info {
  15. #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
  16. #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
  17. #define USE_CLSR BIT(14) /* use CLSR command */
  18. +#define SPI_NOR_4B_READ_OP BIT(15) /*
  19. + * Like SPI_NOR_4B_OPCODES, but for read
  20. + * op code only.
  21. + */
  22. };
  23. #define JEDEC_MFR(info) ((info)->id[0])
  24. @@ -240,6 +244,15 @@ static inline u8 spi_nor_convert_3to4_er
  25. ARRAY_SIZE(spi_nor_3to4_erase));
  26. }
  27. +static void spi_nor_set_4byte_read(struct spi_nor *nor,
  28. + const struct flash_info *info)
  29. +{
  30. + nor->addr_width = 3;
  31. + nor->ext_addr = 0;
  32. + nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode);
  33. + nor->flags |= SNOR_F_4B_EXT_ADDR;
  34. +}
  35. +
  36. static void spi_nor_set_4byte_opcodes(struct spi_nor *nor,
  37. const struct flash_info *info)
  38. {
  39. @@ -467,6 +480,36 @@ static int spi_nor_erase_sector(struct s
  40. return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width);
  41. }
  42. +static int spi_nor_check_ext_addr(struct spi_nor *nor, u32 addr)
  43. +{
  44. + bool ext_addr;
  45. + int ret;
  46. + u8 cmd;
  47. +
  48. + if (!(nor->flags & SNOR_F_4B_EXT_ADDR))
  49. + return 0;
  50. +
  51. + ext_addr = !!(addr & 0xff000000);
  52. + if (nor->ext_addr == ext_addr)
  53. + return 0;
  54. +
  55. + cmd = ext_addr ? SPINOR_OP_EN4B : SPINOR_OP_EX4B;
  56. + write_enable(nor);
  57. + ret = nor->write_reg(nor, cmd, NULL, 0);
  58. + if (ret)
  59. + return ret;
  60. +
  61. + cmd = 0;
  62. + ret = nor->write_reg(nor, SPINOR_OP_WREAR, &cmd, 1);
  63. + if (ret)
  64. + return ret;
  65. +
  66. + nor->addr_width = 3 + ext_addr;
  67. + nor->ext_addr = ext_addr;
  68. + write_disable(nor);
  69. + return 0;
  70. +}
  71. +
  72. /*
  73. * Erase an address range on the nor chip. The address range may extend
  74. * one or more erase sectors. Return an error is there is a problem erasing.
  75. @@ -492,6 +535,10 @@ static int spi_nor_erase(struct mtd_info
  76. if (ret)
  77. return ret;
  78. + ret = spi_nor_check_ext_addr(nor, addr + len);
  79. + if (ret)
  80. + return ret;
  81. +
  82. /* whole-chip erase? */
  83. if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
  84. unsigned long timeout;
  85. @@ -542,6 +589,7 @@ static int spi_nor_erase(struct mtd_info
  86. write_disable(nor);
  87. erase_err:
  88. + spi_nor_check_ext_addr(nor, 0);
  89. spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE);
  90. instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
  91. @@ -834,7 +882,9 @@ static int spi_nor_lock(struct mtd_info
  92. if (ret)
  93. return ret;
  94. + spi_nor_check_ext_addr(nor, ofs + len);
  95. ret = nor->flash_lock(nor, ofs, len);
  96. + spi_nor_check_ext_addr(nor, 0);
  97. spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
  98. return ret;
  99. @@ -849,7 +899,9 @@ static int spi_nor_unlock(struct mtd_inf
  100. if (ret)
  101. return ret;
  102. + spi_nor_check_ext_addr(nor, ofs + len);
  103. ret = nor->flash_unlock(nor, ofs, len);
  104. + spi_nor_check_ext_addr(nor, 0);
  105. spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
  106. return ret;
  107. @@ -1177,7 +1229,7 @@ static const struct flash_info spi_nor_i
  108. { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
  109. { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
  110. { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
  111. - { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
  112. + { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_READ_OP) },
  113. { "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
  114. SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
  115. @@ -1237,6 +1289,9 @@ static int spi_nor_read(struct mtd_info
  116. if (ret)
  117. return ret;
  118. + if (nor->flags & SNOR_F_4B_EXT_ADDR)
  119. + nor->addr_width = 4;
  120. +
  121. while (len) {
  122. loff_t addr = from;
  123. @@ -1261,6 +1316,18 @@ static int spi_nor_read(struct mtd_info
  124. ret = 0;
  125. read_err:
  126. + if (nor->flags & SNOR_F_4B_EXT_ADDR) {
  127. + u8 val = 0;
  128. +
  129. + if ((from + len) & 0xff000000) {
  130. + write_enable(nor);
  131. + nor->write_reg(nor, SPINOR_OP_WREAR, &val, 1);
  132. + write_disable(nor);
  133. + }
  134. +
  135. + nor->addr_width = 3;
  136. + }
  137. +
  138. spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ);
  139. return ret;
  140. }
  141. @@ -1362,6 +1429,10 @@ static int spi_nor_write(struct mtd_info
  142. if (ret)
  143. return ret;
  144. + ret = spi_nor_check_ext_addr(nor, to + len);
  145. + if (ret < 0)
  146. + return ret;
  147. +
  148. for (i = 0; i < len; ) {
  149. ssize_t written;
  150. loff_t addr = to + i;
  151. @@ -1402,6 +1473,7 @@ static int spi_nor_write(struct mtd_info
  152. }
  153. write_err:
  154. + spi_nor_check_ext_addr(nor, 0);
  155. spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE);
  156. return ret;
  157. }
  158. @@ -2818,8 +2890,10 @@ int spi_nor_scan(struct spi_nor *nor, co
  159. } else if (mtd->size > 0x1000000) {
  160. /* enable 4-byte addressing if the device exceeds 16MiB */
  161. nor->addr_width = 4;
  162. - if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
  163. - info->flags & SPI_NOR_4B_OPCODES)
  164. + if (info->flags & SPI_NOR_4B_READ_OP)
  165. + spi_nor_set_4byte_read(nor, info);
  166. + else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION ||
  167. + info->flags & SPI_NOR_4B_OPCODES)
  168. spi_nor_set_4byte_opcodes(nor, info);
  169. else
  170. set_4byte(nor, info, 1);
  171. --- a/include/linux/mtd/spi-nor.h
  172. +++ b/include/linux/mtd/spi-nor.h
  173. @@ -102,6 +102,7 @@
  174. /* Used for Macronix and Winbond flashes. */
  175. #define SPINOR_OP_EN4B 0xb7 /* Enter 4-byte mode */
  176. #define SPINOR_OP_EX4B 0xe9 /* Exit 4-byte mode */
  177. +#define SPINOR_OP_WREAR 0xc5 /* Write extended address register */
  178. /* Used for Spansion flashes only. */
  179. #define SPINOR_OP_BRWR 0x17 /* Bank register write */
  180. @@ -229,6 +230,7 @@ enum spi_nor_option_flags {
  181. SNOR_F_S3AN_ADDR_DEFAULT = BIT(3),
  182. SNOR_F_READY_XSR_RDY = BIT(4),
  183. SNOR_F_USE_CLSR = BIT(5),
  184. + SNOR_F_4B_EXT_ADDR = BIT(6),
  185. };
  186. /**
  187. @@ -280,6 +282,7 @@ struct spi_nor {
  188. enum spi_nor_protocol reg_proto;
  189. bool sst_write_second;
  190. u32 flags;
  191. + u8 ext_addr;
  192. u8 cmd_buf[SPI_NOR_MAX_CMD_SIZE];
  193. int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);