0027-mtd-m25p80-add-support-of-dual-and-quad-spi-protocol.patch 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. From 8b4f14b2f8ed819a6b9e371128259271e8d88841 Mon Sep 17 00:00:00 2001
  2. From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
  3. Date: Fri, 8 Jan 2016 17:10:54 +0100
  4. Subject: [PATCH 27/33] mtd: m25p80: add support of dual and quad spi protocols
  5. to all commands
  6. Before this patch, m25p80_read() supported few SPI protocols:
  7. - regular SPI 1-1-1
  8. - SPI Dual Output 1-1-2
  9. - SPI Quad Output 1-1-4
  10. On the other hand, all other m25p80_*() hooks only supported SPI 1-1-1.
  11. However once their Quad mode enabled, Micron and Macronix spi-nor memories
  12. expect all commands to use the SPI 4-4-4 protocol.
  13. Also, once their Dual mode enabled, Micron spi-nor memories expect all
  14. commands to use the SPI-2-2-2 protocol.
  15. So this patch adds support to all currently existing SPI protocols to
  16. cover as many protocols as possible.
  17. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
  18. ---
  19. drivers/mtd/devices/m25p80.c | 192 ++++++++++++++++++++++++++++++++++---------
  20. 1 file changed, 151 insertions(+), 41 deletions(-)
  21. diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
  22. index bc7a802..e3e2708 100644
  23. --- a/drivers/mtd/devices/m25p80.c
  24. +++ b/drivers/mtd/devices/m25p80.c
  25. @@ -27,22 +27,64 @@
  26. #include <linux/spi/flash.h>
  27. #include <linux/mtd/spi-nor.h>
  28. -#define MAX_CMD_SIZE 6
  29. +#define MAX_CMD_SIZE 16
  30. struct m25p {
  31. struct spi_device *spi;
  32. struct spi_nor spi_nor;
  33. u8 command[MAX_CMD_SIZE];
  34. };
  35. +static inline int m25p80_proto2nbits(enum spi_nor_protocol proto,
  36. + unsigned *code_nbits,
  37. + unsigned *addr_nbits,
  38. + unsigned *data_nbits)
  39. +{
  40. + if (code_nbits)
  41. + *code_nbits = SNOR_PROTO_CMD_FROM_PROTO(proto);
  42. + if (addr_nbits)
  43. + *addr_nbits = SNOR_PROTO_ADDR_FROM_PROTO(proto);
  44. + if (data_nbits)
  45. + *data_nbits = SNOR_PROTO_DATA_FROM_PROTO(proto);
  46. +
  47. + return 0;
  48. +}
  49. +
  50. static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
  51. {
  52. struct m25p *flash = nor->priv;
  53. struct spi_device *spi = flash->spi;
  54. + unsigned code_nbits, data_nbits;
  55. + struct spi_transfer xfers[2];
  56. int ret;
  57. - ret = spi_write_then_read(spi, &code, 1, val, len);
  58. + /* Check the total length of command op code and data. */
  59. + if (len + 1 > MAX_CMD_SIZE)
  60. + return -EINVAL;
  61. +
  62. + /* Get transfer protocols (addr_nbits is not relevant here). */
  63. + ret = m25p80_proto2nbits(nor->reg_proto,
  64. + &code_nbits, NULL, &data_nbits);
  65. + if (ret < 0)
  66. + return ret;
  67. +
  68. + /* Set up transfers. */
  69. + memset(xfers, 0, sizeof(xfers));
  70. +
  71. + flash->command[0] = code;
  72. + xfers[0].len = 1;
  73. + xfers[0].tx_buf = flash->command;
  74. + xfers[0].tx_nbits = code_nbits;
  75. +
  76. + xfers[1].len = len;
  77. + xfers[1].rx_buf = &flash->command[1];
  78. + xfers[1].rx_nbits = data_nbits;
  79. +
  80. + /* Process command. */
  81. + ret = spi_sync_transfer(spi, xfers, 2);
  82. if (ret < 0)
  83. dev_err(&spi->dev, "error %d reading %x\n", ret, code);
  84. + else
  85. + memcpy(val, &flash->command[1], len);
  86. return ret;
  87. }
  88. @@ -65,12 +107,42 @@ static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
  89. {
  90. struct m25p *flash = nor->priv;
  91. struct spi_device *spi = flash->spi;
  92. + unsigned code_nbits, data_nbits, num_xfers = 1;
  93. + struct spi_transfer xfers[2];
  94. + int ret;
  95. +
  96. + /* Check the total length of command op code and data. */
  97. + if (buf && (len + 1 > MAX_CMD_SIZE))
  98. + return -EINVAL;
  99. +
  100. + /* Get transfer protocols (addr_nbits is not relevant here). */
  101. + ret = m25p80_proto2nbits(nor->reg_proto,
  102. + &code_nbits, NULL, &data_nbits);
  103. + if (ret < 0)
  104. + return ret;
  105. +
  106. + /* Set up transfer(s). */
  107. + memset(xfers, 0, sizeof(xfers));
  108. flash->command[0] = opcode;
  109. - if (buf)
  110. + xfers[0].len = 1;
  111. + xfers[0].tx_buf = flash->command;
  112. + xfers[0].tx_nbits = code_nbits;
  113. +
  114. + if (buf) {
  115. memcpy(&flash->command[1], buf, len);
  116. + if (data_nbits == code_nbits) {
  117. + xfers[0].len += len;
  118. + } else {
  119. + xfers[1].len = len;
  120. + xfers[1].tx_buf = &flash->command[1];
  121. + xfers[1].tx_nbits = data_nbits;
  122. + num_xfers++;
  123. + }
  124. + }
  125. - return spi_write(spi, flash->command, len + 1);
  126. + /* Process command. */
  127. + return spi_sync_transfer(spi, xfers, num_xfers);
  128. }
  129. static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
  130. @@ -78,43 +150,54 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
  131. {
  132. struct m25p *flash = nor->priv;
  133. struct spi_device *spi = flash->spi;
  134. - struct spi_transfer t[2] = {};
  135. + unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
  136. + struct spi_transfer xfers[3];
  137. struct spi_message m;
  138. - int cmd_sz = m25p_cmdsz(nor);
  139. -
  140. - spi_message_init(&m);
  141. + int ret, cmd_sz = m25p_cmdsz(nor);
  142. if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
  143. cmd_sz = 1;
  144. - flash->command[0] = nor->program_opcode;
  145. - m25p_addr2cmd(nor, to, flash->command);
  146. + /* Get transfer protocols. */
  147. + ret = m25p80_proto2nbits(nor->write_proto,
  148. + &code_nbits, &addr_nbits, &data_nbits);
  149. + if (ret < 0) {
  150. + *retlen = 0;
  151. + return;
  152. + }
  153. - t[0].tx_buf = flash->command;
  154. - t[0].len = cmd_sz;
  155. - spi_message_add_tail(&t[0], &m);
  156. + /* Set up transfers. */
  157. + memset(xfers, 0, sizeof(xfers));
  158. +
  159. + flash->command[0] = nor->program_opcode;
  160. + xfers[0].len = 1;
  161. + xfers[0].tx_buf = flash->command;
  162. + xfers[0].tx_nbits = code_nbits;
  163. +
  164. + if (cmd_sz > 1) {
  165. + m25p_addr2cmd(nor, to, flash->command);
  166. + if (addr_nbits == code_nbits) {
  167. + xfers[0].len += nor->addr_width;
  168. + } else {
  169. + xfers[1].len = nor->addr_width;
  170. + xfers[1].tx_buf = &flash->command[1];
  171. + xfers[1].tx_nbits = addr_nbits;
  172. + num_xfers++;
  173. + }
  174. + }
  175. - t[1].tx_buf = buf;
  176. - t[1].len = len;
  177. - spi_message_add_tail(&t[1], &m);
  178. + xfers[num_xfers].len = len;
  179. + xfers[num_xfers].tx_buf = buf;
  180. + xfers[num_xfers].tx_nbits = data_nbits;
  181. + num_xfers++;
  182. + /* Process command. */
  183. + spi_message_init_with_transfers(&m, xfers, num_xfers);
  184. spi_sync(spi, &m);
  185. *retlen += m.actual_length - cmd_sz;
  186. }
  187. -static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
  188. -{
  189. - switch (nor->flash_read) {
  190. - case SPI_NOR_DUAL:
  191. - return 2;
  192. - case SPI_NOR_QUAD:
  193. - return 4;
  194. - default:
  195. - return 0;
  196. - }
  197. -}
  198. -
  199. /*
  200. * Read an address range from the nor chip. The address range
  201. * may be any size provided it is within the physical boundaries.
  202. @@ -124,28 +207,55 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
  203. {
  204. struct m25p *flash = nor->priv;
  205. struct spi_device *spi = flash->spi;
  206. - struct spi_transfer t[2];
  207. - struct spi_message m;
  208. + unsigned code_nbits, addr_nbits, data_nbits, num_xfers = 1;
  209. unsigned int dummy = nor->read_dummy;
  210. + struct spi_transfer xfers[3];
  211. + struct spi_message m;
  212. + int ret;
  213. +
  214. + /* Get transfer protocols. */
  215. + ret = m25p80_proto2nbits(nor->read_proto,
  216. + &code_nbits, &addr_nbits, &data_nbits);
  217. + if (ret < 0) {
  218. + *retlen = 0;
  219. + return ret;
  220. + }
  221. /* convert the dummy cycles to the number of bytes */
  222. - dummy /= 8;
  223. + dummy = (dummy * addr_nbits) / 8;
  224. - spi_message_init(&m);
  225. - memset(t, 0, (sizeof t));
  226. + /* Set up transfers. */
  227. + memset(xfers, 0, sizeof(xfers));
  228. flash->command[0] = nor->read_opcode;
  229. - m25p_addr2cmd(nor, from, flash->command);
  230. + xfers[0].len = 1;
  231. + xfers[0].tx_buf = flash->command;
  232. + xfers[0].tx_nbits = code_nbits;
  233. - t[0].tx_buf = flash->command;
  234. - t[0].len = m25p_cmdsz(nor) + dummy;
  235. - spi_message_add_tail(&t[0], &m);
  236. + m25p_addr2cmd(nor, from, flash->command);
  237. + /*
  238. + * Clear all dummy/mode cycle bits to avoid sending some manufacturer
  239. + * specific pattern, which might make the memory enter its Continuous
  240. + * Read mode by mistake.
  241. + */
  242. + memset(flash->command + 1 + nor->addr_width, 0, dummy);
  243. +
  244. + if (addr_nbits == code_nbits) {
  245. + xfers[0].len += nor->addr_width + dummy;
  246. + } else {
  247. + xfers[1].len = nor->addr_width + dummy;
  248. + xfers[1].tx_buf = &flash->command[1];
  249. + xfers[1].tx_nbits = addr_nbits;
  250. + num_xfers++;
  251. + }
  252. - t[1].rx_buf = buf;
  253. - t[1].rx_nbits = m25p80_rx_nbits(nor);
  254. - t[1].len = len;
  255. - spi_message_add_tail(&t[1], &m);
  256. + xfers[num_xfers].len = len;
  257. + xfers[num_xfers].rx_buf = buf;
  258. + xfers[num_xfers].rx_nbits = data_nbits;
  259. + num_xfers++;
  260. + /* Process command. */
  261. + spi_message_init_with_transfers(&m, xfers, num_xfers);
  262. spi_sync(spi, &m);
  263. *retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
  264. --
  265. 2.8.1