2
0

spiflash.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. #define MODULE "spiflash"
  2. #define DEBUG 1
  3. #include "common.h"
  4. #include "spiflash.h"
  5. #include "spz.h"
  6. #include "fw.h"
  7. #include "jtag.h"
  8. /*
  9. * SPI flash parameters
  10. */
  11. #define JTAG_SPIFLASH_HZ 10000000 /* Max 26 MHz due to ESP32 */
  12. static const struct jtag_config jtag_config_spiflash = {
  13. .hz = JTAG_SPIFLASH_HZ,
  14. .pin_tms = 10, /* CS# */
  15. .pin_tdi = 12, /* MOSI */
  16. .pin_tdo = 13, /* MISO */
  17. .pin_tck = 11, /* SCLK */
  18. .be = true /* Bit order within bytes */
  19. };
  20. /*
  21. * Set up a command header with an address according to the SPI
  22. * addressing mode. Returns a pointer to the first byte past the
  23. * address.
  24. */
  25. static void *spiflash_setup_addrcmd(uint32_t addr,
  26. uint8_t cmd24, uint8_t cmd32,
  27. void *cmdbuf)
  28. {
  29. enum spiflash_addr_mode mode = SPIFLASH_ADDR_DYNAMIC;
  30. uint8_t *cmd = cmdbuf;
  31. if (!mode)
  32. mode = addr < (1 << 24) ? SPIFLASH_ADDR_24BIT : SPIFLASH_ADDR_32BIT;
  33. if (mode == SPIFLASH_ADDR_24BIT) {
  34. *cmd++ = cmd24;
  35. } else {
  36. *cmd++ = cmd32;
  37. *cmd++ = addr >> 24;
  38. }
  39. *cmd++ = addr >> 16;
  40. *cmd++ = addr >> 8;
  41. *cmd++ = addr;
  42. return cmd;
  43. }
  44. # define SHOW_COMMAND() \
  45. do { \
  46. MSG("command: ", cmdbuf, cmdlen); \
  47. for (size_t i = 0; i < cmdlen; i++) \
  48. CMSG(" %02x", ((const uint8_t *)cmdbuf)[i]); \
  49. CMSG("\n"); \
  50. } while(0)
  51. static int spiflash_simple_command(uint32_t cmd)
  52. {
  53. jtag_io(8, JIO_CS, &cmd, NULL);
  54. return 0;
  55. }
  56. static int spiflash_plain_command(const void *cmdbuf, size_t cmdlen)
  57. {
  58. #if DEBUG > 1
  59. MSG("plain: cmdbuf = %p (%zu), databuf = %p (%zu)\n",
  60. cmdbuf, cmdlen);
  61. SHOW_COMMAND();
  62. #endif
  63. jtag_io(cmdlen << 3, JIO_CS, cmdbuf, NULL);
  64. return 0;
  65. }
  66. static int spiflash_output_command(const void *cmdbuf, size_t cmdlen,
  67. const void *databuf, size_t datalen)
  68. {
  69. if (!datalen)
  70. return spiflash_plain_command(cmdbuf, cmdlen);
  71. #if DEBUG > 1
  72. MSG("output: cmdbuf = %p (%zu), databuf = %p (%zu)\n",
  73. cmdbuf, cmdlen, databuf, datalen);
  74. SHOW_COMMAND();
  75. #endif
  76. jtag_io(cmdlen << 3, 0, cmdbuf, NULL);
  77. jtag_io(datalen << 3, JIO_CS, databuf, NULL);
  78. return 0;
  79. }
  80. static int spiflash_input_command(const void *cmdbuf, size_t cmdlen,
  81. void *databuf, size_t datalen)
  82. {
  83. if (!datalen)
  84. return spiflash_plain_command(cmdbuf, cmdlen);
  85. #if DEBUG > 1
  86. MSG("input: cmdbuf = %p (%zu), databuf = %p (%zu)\n",
  87. cmdbuf, cmdlen, databuf, datalen);
  88. SHOW_COMMAND();
  89. #endif
  90. jtag_io(cmdlen << 3, 0, cmdbuf, NULL);
  91. jtag_io(datalen << 3, JIO_CS, NULL, databuf);
  92. return 0;
  93. }
  94. static int spiflash_read_status(uint32_t reg)
  95. {
  96. uint32_t val = 0;
  97. jtag_io(8, 0, (const uint8_t *)&reg, NULL);
  98. jtag_io(8, JIO_CS, NULL, (uint8_t *)&val);
  99. return val;
  100. }
  101. /* This needs a timeout function */
  102. static int spiflash_wait_status(uint8_t mask, uint8_t val)
  103. {
  104. unsigned int wait_loops = 100000;
  105. #if DEBUG > 1
  106. MSG("waiting for status %02x/%02x... ", mask, val);
  107. #endif
  108. while (wait_loops--) {
  109. uint8_t sr1 = spiflash_read_status(ROM_READ_SR1);
  110. if ((sr1 & mask) == val) {
  111. #if DEBUG > 1
  112. CMSG("ok\n");
  113. #endif
  114. return 0;
  115. }
  116. yield();
  117. }
  118. #if DEBUG > 1
  119. CMSG("timeout\n");
  120. #endif
  121. return -1;
  122. }
  123. static int spiflash_read(uint32_t addr, void *buffer, size_t len)
  124. {
  125. uint32_t cmdbuf[2];
  126. uint8_t *cmd = (uint8_t *)cmdbuf;
  127. const uint8_t cmd24 = ROM_FAST_READ;
  128. const uint8_t cmd32 = ROM_FAST_READ_32BIT;
  129. const size_t max_read_len = -1;
  130. int rv;
  131. while (len) {
  132. size_t clen = len;
  133. if (clen > max_read_len)
  134. clen = max_read_len;
  135. cmd = spiflash_setup_addrcmd(addr, cmd24, cmd32, cmdbuf);
  136. *cmd++ = 0; /* Dummy cycles */
  137. rv = spiflash_input_command(cmdbuf, cmd - (uint8_t *)cmdbuf,
  138. buffer, clen);
  139. if (rv)
  140. return rv;
  141. addr += clen;
  142. buffer = (uint8_t *)buffer + clen;
  143. len -= clen;
  144. }
  145. return 0;
  146. }
  147. static int spiflash_write_enable(void)
  148. {
  149. uint8_t sr1;
  150. int rv;
  151. rv = spiflash_wait_status(1, 0);
  152. if (rv)
  153. return rv;
  154. spiflash_simple_command(ROM_WRITE_ENABLE);
  155. return spiflash_wait_status(3, 2);
  156. }
  157. static int spiflash_program_sector(uint32_t addr, const void *buffer)
  158. {
  159. uint32_t cmdbuf[2];
  160. uint8_t *cmd = (uint8_t *)cmdbuf;
  161. const uint8_t cmd24 = ROM_PAGE_PROGRAM;
  162. const uint8_t cmd32 = ROM_PAGE_PROGRAM_32BIT;
  163. int rv;
  164. int loops = SPIFLASH_SECTOR_SIZE / SPIFLASH_PAGE_SIZE;
  165. const char *p = buffer;
  166. while (loops--) {
  167. rv = spiflash_write_enable();
  168. if (rv)
  169. return rv;
  170. cmd = spiflash_setup_addrcmd(addr, cmd24, cmd32, cmdbuf);
  171. spiflash_output_command(cmdbuf, cmd - (uint8_t *)cmdbuf,
  172. p, SPIFLASH_PAGE_SIZE);
  173. rv = spiflash_wait_status(3, 0);
  174. if (rv)
  175. return rv;
  176. addr += SPIFLASH_PAGE_SIZE;
  177. p += SPIFLASH_PAGE_SIZE;
  178. }
  179. return 0;
  180. }
  181. static int spiflash_erase_sector(uint32_t addr)
  182. {
  183. uint32_t cmdbuf[2];
  184. uint8_t *cmd = (uint8_t *)cmdbuf;
  185. const uint8_t cmd24 = ROM_ERASE_4K;
  186. const uint8_t cmd32 = ROM_ERASE_4K_32BIT;
  187. int rv;
  188. rv = spiflash_write_enable();
  189. if (rv)
  190. return rv;
  191. cmd = spiflash_setup_addrcmd(addr, cmd24, cmd32, cmdbuf);
  192. spiflash_plain_command(cmdbuf, cmd - (uint8_t *)cmdbuf);
  193. return spiflash_wait_status(3, 0);
  194. }
  195. /*
  196. * from: current flash contents
  197. * to: desired flash contents
  198. *
  199. * These are assumed to be aligned full block buffers
  200. */
  201. enum flashmem_status {
  202. FMS_DONE, /* All done, no programming needed */
  203. FMS_PROGRAM, /* Can be programmed */
  204. FMS_ERASE, /* Needs erase before programming */
  205. FMS_NOTCHECKED /* Not checked yet */
  206. };
  207. static enum flashmem_status
  208. spiflash_memcmp(const void *from, const void *to, size_t len)
  209. {
  210. const uint32_t *pf = from;
  211. const uint32_t *pt = to;
  212. const uint32_t *pfend = (const uint32_t *)((const char *)from + len);
  213. uint32_t doprog = 0;
  214. uint32_t doerase = 0;
  215. while (pf < pfend) {
  216. uint32_t f = *pf++;
  217. uint32_t t = *pt++;
  218. doprog += !!(f ^ t); /* Need programming if any data mismatch */
  219. doerase += !!(~f & t); /* Need erasing if any 0 -> 1 */
  220. }
  221. return doerase ? FMS_ERASE : doprog ? FMS_PROGRAM : FMS_DONE;
  222. }
  223. static int spiflash_write_sector(spz_stream *spz, unsigned int addr)
  224. {
  225. enum flashmem_status status = FMS_NOTCHECKED;
  226. MSG("flash sector at 0x%06x: ", addr);
  227. while (1) {
  228. enum flashmem_status oldstatus = status;
  229. status = spiflash_memcmp(spz->vbuf, spz->dbuf, SPIFLASH_SECTOR_SIZE);
  230. if (status >= oldstatus) {
  231. CMSG("X [%u>%u]", oldstatus, status);
  232. break;
  233. } else if (status == FMS_DONE) {
  234. CMSG("V");
  235. break;
  236. } else if (status == FMS_ERASE) {
  237. CMSG("E");
  238. if (spiflash_erase_sector(addr))
  239. break;
  240. } else if (status == FMS_PROGRAM) {
  241. CMSG("P");
  242. if (spiflash_program_sector(addr, spz->dbuf))
  243. break;
  244. }
  245. memset(spz->vbuf, 0xdd, SPIFLASH_SECTOR_SIZE);
  246. spiflash_read(addr, spz->vbuf, SPIFLASH_SECTOR_SIZE);
  247. }
  248. int rv;
  249. if (status == FMS_DONE) {
  250. CMSG(" OK\n");
  251. rv = 0;
  252. } else {
  253. CMSG(" FAILED\n");
  254. rv = (status == FMS_PROGRAM)
  255. ? FWUPDATE_ERR_PROGRAM_FAILED : FWUPDATE_ERR_ERASE_FAILED;
  256. }
  257. if (!spz->err)
  258. spz->err = rv;
  259. return rv;
  260. }
  261. static int spiflash_read_jedec_id(void)
  262. {
  263. const uint32_t cmd = ROM_JEDEC_ID;
  264. uint32_t jid = 0;
  265. spiflash_input_command((uint8_t *)&cmd, 1, (uint8_t *)&jid, 3);
  266. MSG("JEDEC ID: vendor %02x type %02x capacity %02x\n",
  267. (uint8_t)jid, (uint8_t)(jid >> 8), (uint8_t)(jid >> 16));
  268. return 0;
  269. }
  270. static void spiflash_show_status(void)
  271. {
  272. MSG("status regs: %02x %02x %02x\n",
  273. spiflash_read_status(ROM_READ_SR1),
  274. spiflash_read_status(ROM_READ_SR2),
  275. spiflash_read_status(ROM_READ_SR3));
  276. }
  277. #define PIN_FPGA_READY 9
  278. #define PIN_FPGA_BOARD_ID 1
  279. /* Set data and data_len if the data to be written is not from the spz */
  280. int spiflash_write_spz(spz_stream *spz,
  281. const void *data, unsigned int data_left)
  282. {
  283. esp_err_t rv;
  284. const uint8_t *dptr = data;
  285. unsigned int addr = spz->header.addr;
  286. if (!dptr)
  287. data_left = spz->header.len;
  288. if (!data_left || spz->err)
  289. return spz->err;
  290. pinMode(PIN_FPGA_READY, INPUT);
  291. pinMode(PIN_FPGA_BOARD_ID, INPUT);
  292. MSG("waiting for FPGA bypass to be ready..");
  293. while (digitalRead(PIN_FPGA_READY) != LOW) {
  294. CMSG(".");
  295. yield();
  296. }
  297. CMSG("\n");
  298. MSG("FPGA bypass ready, board version v%c.\n",
  299. digitalRead(PIN_FPGA_BOARD_ID) ? '1' : '2');
  300. jtag_enable(&jtag_config_spiflash);
  301. spiflash_read_jedec_id();
  302. spiflash_show_status();
  303. while (data_left && !spz->err) {
  304. unsigned int pre_padding = addr & (SPIFLASH_SECTOR_SIZE-1);
  305. unsigned int post_padding;
  306. unsigned int bytes;
  307. bytes = SPIFLASH_SECTOR_SIZE - pre_padding;
  308. post_padding = 0;
  309. if (bytes > data_left) {
  310. post_padding = bytes - data_left;
  311. bytes = data_left;
  312. }
  313. addr -= pre_padding;
  314. /* Read the current content of this block into vbuf */
  315. memset(spz->vbuf, 0xee, SPIFLASH_SECTOR_SIZE);
  316. rv = spiflash_read(addr, spz->vbuf, SPIFLASH_SECTOR_SIZE);
  317. if (rv)
  318. goto err;
  319. /* Copy any invariant chunk */
  320. if (pre_padding)
  321. memcpy(spz->dbuf, spz->vbuf, pre_padding);
  322. if (post_padding)
  323. memcpy(spz->dbuf+SPIFLASH_SECTOR_SIZE-post_padding,
  324. spz->vbuf+SPIFLASH_SECTOR_SIZE-post_padding,
  325. post_padding);
  326. if (dptr) {
  327. memcpy(spz->dbuf+pre_padding, dptr, bytes);
  328. dptr += bytes;
  329. } else {
  330. rv = spz_read_data(spz, spz->dbuf+pre_padding, bytes);
  331. if (rv != (int)bytes) {
  332. MSG("needed %u bytes got %d\n", bytes, rv);
  333. rv = Z_DATA_ERROR;
  334. goto err;
  335. }
  336. }
  337. rv = spiflash_write_sector(spz, addr);
  338. if (rv) {
  339. spz->err = rv;
  340. goto err;
  341. }
  342. addr += pre_padding + bytes;
  343. data_left -= bytes;
  344. }
  345. rv = 0;
  346. err:
  347. if (!spz->err)
  348. spz->err = rv;
  349. jtag_disable(NULL);
  350. return spz->err;
  351. }