logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

flash_spi.c (11962B)


  1. // Copyright 2021 Westberry Technology (ChangZhou) Corp., Ltd
  2. // Copyright 2024 Nick Brassel (@tzarc)
  3. // SPDX-License-Identifier: GPL-2.0-or-later
  4. #include <string.h>
  5. #include "flash.h"
  6. #include "util.h"
  7. #include "wait.h"
  8. #include "debug.h"
  9. #include "timer.h"
  10. #include "flash_spi.h"
  11. #include "spi_master.h"
  12. /*
  13. The time-out time of spi flash transmission.
  14. */
  15. #ifndef EXTERNAL_FLASH_SPI_TIMEOUT
  16. # define EXTERNAL_FLASH_SPI_TIMEOUT 1000
  17. #endif
  18. /* ID comands */
  19. #define FLASH_CMD_RDID 0x9F /* RDID (Read Identification) */
  20. #define FLASH_CMD_RES 0xAB /* RES (Read Electronic ID) */
  21. #define FLASH_CMD_REMS 0x90 /* REMS (Read Electronic & Device ID) */
  22. /* register comands */
  23. #define FLASH_CMD_WRSR 0x01 /* WRSR (Write Status register) */
  24. #define FLASH_CMD_RDSR 0x05 /* RDSR (Read Status register) */
  25. /* READ comands */
  26. #define FLASH_CMD_READ 0x03 /* READ (1 x I/O) */
  27. #define FLASH_CMD_FASTREAD 0x0B /* FAST READ (Fast read data) */
  28. #define FLASH_CMD_DREAD 0x3B /* DREAD (1In/2 Out fast read) */
  29. /* Program comands */
  30. #define FLASH_CMD_WREN 0x06 /* WREN (Write Enable) */
  31. #define FLASH_CMD_WRDI 0x04 /* WRDI (Write Disable) */
  32. #define FLASH_CMD_PP 0x02 /* PP (page program) */
  33. /* Erase comands */
  34. #define FLASH_CMD_SE 0x20 /* SE (Sector Erase) */
  35. #define FLASH_CMD_BE 0xD8 /* BE (Block Erase) */
  36. #define FLASH_CMD_CE 0x60 /* CE (Chip Erase) hex code: 60 or C7 */
  37. /* Mode setting comands */
  38. #define FLASH_CMD_DP 0xB9 /* DP (Deep Power Down) */
  39. #define FLASH_CMD_RDP 0xAB /* RDP (Release from Deep Power Down) */
  40. /* Status register */
  41. #define FLASH_FLAG_WIP 0x01 /* Write in progress bit */
  42. #define FLASH_FLAG_WEL 0x02 /* Write enable latch bit */
  43. // #define DEBUG_FLASH_SPI_OUTPUT
  44. static bool spi_flash_start(void) {
  45. return spi_start(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN, EXTERNAL_FLASH_SPI_LSBFIRST, EXTERNAL_FLASH_SPI_MODE, EXTERNAL_FLASH_SPI_CLOCK_DIVISOR);
  46. }
  47. static flash_status_t spi_flash_wait_while_busy_multiplier(int multiplier) {
  48. flash_status_t response = FLASH_STATUS_SUCCESS;
  49. uint32_t deadline = timer_read32() + ((EXTERNAL_FLASH_SPI_TIMEOUT)*multiplier);
  50. do {
  51. if (timer_read32() >= deadline) {
  52. response = FLASH_STATUS_TIMEOUT;
  53. break;
  54. }
  55. response = flash_is_busy();
  56. } while (response == FLASH_STATUS_BUSY);
  57. return response;
  58. }
  59. static flash_status_t spi_flash_wait_while_busy(void) {
  60. return spi_flash_wait_while_busy_multiplier(1);
  61. }
  62. flash_status_t flash_is_busy(void) {
  63. bool res = spi_flash_start();
  64. if (!res) {
  65. dprint("Failed to start SPI! [spi flash wait while busy]\n");
  66. return FLASH_STATUS_ERROR;
  67. }
  68. spi_write(FLASH_CMD_RDSR);
  69. spi_status_t status = spi_read();
  70. spi_stop();
  71. if (status < 0) {
  72. return status;
  73. }
  74. uint8_t sr = (uint8_t)status;
  75. return (sr & FLASH_FLAG_WIP) ? FLASH_STATUS_BUSY : FLASH_STATUS_SUCCESS;
  76. }
  77. static flash_status_t spi_flash_write_enable(void) {
  78. bool res = spi_flash_start();
  79. if (!res) {
  80. dprint("Failed to start SPI! [spi flash write enable]\n");
  81. return FLASH_STATUS_ERROR;
  82. }
  83. spi_write(FLASH_CMD_WREN);
  84. spi_stop();
  85. return FLASH_STATUS_SUCCESS;
  86. }
  87. static flash_status_t spi_flash_write_disable(void) {
  88. bool res = spi_flash_start();
  89. if (!res) {
  90. dprint("Failed to start SPI! [spi flash write disable]\n");
  91. return FLASH_STATUS_ERROR;
  92. }
  93. spi_write(FLASH_CMD_WRDI);
  94. spi_stop();
  95. return FLASH_STATUS_SUCCESS;
  96. }
  97. /* This function is used for read transfer, write transfer and erase transfer. */
  98. static flash_status_t spi_flash_transaction(uint8_t cmd, uint32_t addr, uint8_t *data, size_t len) {
  99. flash_status_t response = FLASH_STATUS_SUCCESS;
  100. uint8_t buffer[EXTERNAL_FLASH_ADDRESS_SIZE + 1];
  101. buffer[0] = cmd;
  102. for (int i = 0; i < EXTERNAL_FLASH_ADDRESS_SIZE; ++i) {
  103. buffer[EXTERNAL_FLASH_ADDRESS_SIZE - i] = addr & 0xFF;
  104. addr >>= 8;
  105. }
  106. bool res = spi_flash_start();
  107. if (!res) {
  108. dprint("Failed to start SPI! [spi flash transmit]\n");
  109. return FLASH_STATUS_ERROR;
  110. }
  111. response = spi_transmit(buffer, sizeof(buffer));
  112. if ((!response) && (data != NULL)) {
  113. switch (cmd) {
  114. case FLASH_CMD_READ:
  115. response = spi_receive(data, len);
  116. break;
  117. case FLASH_CMD_PP:
  118. response = spi_transmit(data, len);
  119. break;
  120. default:
  121. response = FLASH_STATUS_ERROR;
  122. break;
  123. }
  124. }
  125. spi_stop();
  126. return response;
  127. }
  128. void flash_init(void) {
  129. spi_init();
  130. }
  131. flash_status_t flash_begin_erase_chip(void) {
  132. flash_status_t response = FLASH_STATUS_SUCCESS;
  133. /* Wait for the write-in-progress bit to be cleared. */
  134. response = spi_flash_wait_while_busy();
  135. if (response != FLASH_STATUS_SUCCESS) {
  136. dprint("Failed to check WIP flag! [spi flash erase chip]\n");
  137. return response;
  138. }
  139. /* Enable writes. */
  140. response = spi_flash_write_enable();
  141. if (response != FLASH_STATUS_SUCCESS) {
  142. dprint("Failed to write-enable! [spi flash erase chip]\n");
  143. return response;
  144. }
  145. /* Erase Chip. */
  146. bool res = spi_flash_start();
  147. if (!res) {
  148. dprint("Failed to start SPI! [spi flash erase chip]\n");
  149. return FLASH_STATUS_ERROR;
  150. }
  151. spi_write(FLASH_CMD_CE);
  152. spi_stop();
  153. return FLASH_STATUS_SUCCESS;
  154. }
  155. flash_status_t flash_wait_erase_chip(void) {
  156. flash_status_t response = spi_flash_wait_while_busy_multiplier(250); // Chip erase can take a long time, wait 250x the usual timeout
  157. if (response != FLASH_STATUS_SUCCESS) {
  158. dprint("Failed to check WIP flag! [spi flash erase chip]\n");
  159. return response;
  160. }
  161. return response;
  162. }
  163. flash_status_t flash_erase_chip(void) {
  164. flash_status_t response = flash_begin_erase_chip();
  165. if (response != FLASH_STATUS_SUCCESS) {
  166. dprint("Failed to begin erase chip! [spi flash erase chip]\n");
  167. return response;
  168. }
  169. return flash_wait_erase_chip();
  170. }
  171. flash_status_t flash_erase_sector(uint32_t addr) {
  172. flash_status_t response = FLASH_STATUS_SUCCESS;
  173. /* Check that the address exceeds the limit. */
  174. if ((addr + (EXTERNAL_FLASH_SECTOR_SIZE)) >= (EXTERNAL_FLASH_SIZE) || ((addr % (EXTERNAL_FLASH_SECTOR_SIZE)) != 0)) {
  175. dprintf("Flash erase sector address over limit! [addr:0x%lx]\n", (uint32_t)addr);
  176. return FLASH_STATUS_ERROR;
  177. }
  178. /* Wait for the write-in-progress bit to be cleared. */
  179. response = spi_flash_wait_while_busy();
  180. if (response != FLASH_STATUS_SUCCESS) {
  181. dprint("Failed to check WIP flag! [spi flash erase sector]\n");
  182. return response;
  183. }
  184. /* Enable writes. */
  185. response = spi_flash_write_enable();
  186. if (response != FLASH_STATUS_SUCCESS) {
  187. dprint("Failed to write-enable! [spi flash erase sector]\n");
  188. return response;
  189. }
  190. /* Erase Sector. */
  191. response = spi_flash_transaction(FLASH_CMD_SE, addr, NULL, 0);
  192. if (response != FLASH_STATUS_SUCCESS) {
  193. dprint("Failed to erase sector! [spi flash erase sector]\n");
  194. return response;
  195. }
  196. /* Wait for the write-in-progress bit to be cleared.*/
  197. response = spi_flash_wait_while_busy();
  198. if (response != FLASH_STATUS_SUCCESS) {
  199. dprint("Failed to check WIP flag! [spi flash erase sector]\n");
  200. return response;
  201. }
  202. return response;
  203. }
  204. flash_status_t flash_erase_block(uint32_t addr) {
  205. flash_status_t response = FLASH_STATUS_SUCCESS;
  206. /* Check that the address exceeds the limit. */
  207. if ((addr + (EXTERNAL_FLASH_BLOCK_SIZE)) >= (EXTERNAL_FLASH_SIZE) || ((addr % (EXTERNAL_FLASH_BLOCK_SIZE)) != 0)) {
  208. dprintf("Flash erase block address over limit! [addr:0x%lx]\n", (uint32_t)addr);
  209. return FLASH_STATUS_ERROR;
  210. }
  211. /* Wait for the write-in-progress bit to be cleared. */
  212. response = spi_flash_wait_while_busy();
  213. if (response != FLASH_STATUS_SUCCESS) {
  214. dprint("Failed to check WIP flag! [spi flash erase block]\n");
  215. return response;
  216. }
  217. /* Enable writes. */
  218. response = spi_flash_write_enable();
  219. if (response != FLASH_STATUS_SUCCESS) {
  220. dprint("Failed to write-enable! [spi flash erase block]\n");
  221. return response;
  222. }
  223. /* Erase Block. */
  224. response = spi_flash_transaction(FLASH_CMD_BE, addr, NULL, 0);
  225. if (response != FLASH_STATUS_SUCCESS) {
  226. dprint("Failed to erase block! [spi flash erase block]\n");
  227. return response;
  228. }
  229. /* Wait for the write-in-progress bit to be cleared.*/
  230. response = spi_flash_wait_while_busy();
  231. if (response != FLASH_STATUS_SUCCESS) {
  232. dprint("Failed to check WIP flag! [spi flash erase block]\n");
  233. return response;
  234. }
  235. return response;
  236. }
  237. flash_status_t flash_read_range(uint32_t addr, void *buf, size_t len) {
  238. flash_status_t response = FLASH_STATUS_SUCCESS;
  239. uint8_t * read_buf = (uint8_t *)buf;
  240. /* Wait for the write-in-progress bit to be cleared. */
  241. response = spi_flash_wait_while_busy();
  242. if (response != FLASH_STATUS_SUCCESS) {
  243. dprint("Failed to check WIP flag! [spi flash read block]\n");
  244. memset(read_buf, 0, len);
  245. return response;
  246. }
  247. /* Perform read. */
  248. response = spi_flash_transaction(FLASH_CMD_READ, addr, read_buf, len);
  249. if (response != FLASH_STATUS_SUCCESS) {
  250. dprint("Failed to read block! [spi flash read block]\n");
  251. memset(read_buf, 0, len);
  252. return response;
  253. }
  254. #if defined(CONSOLE_ENABLE) && defined(DEBUG_FLASH_SPI_OUTPUT)
  255. dprintf("[SPI FLASH R] 0x%08lx: ", addr);
  256. for (size_t i = 0; i < len; ++i) {
  257. dprintf(" %02X", (int)(((uint8_t *)read_buf)[i]));
  258. }
  259. dprintf("\n");
  260. #endif // DEBUG_FLASH_SPI_OUTPUT
  261. return response;
  262. }
  263. flash_status_t flash_write_range(uint32_t addr, const void *buf, size_t len) {
  264. flash_status_t response = FLASH_STATUS_SUCCESS;
  265. uint8_t * write_buf = (uint8_t *)buf;
  266. while (len > 0) {
  267. uint32_t page_offset = addr % EXTERNAL_FLASH_PAGE_SIZE;
  268. size_t write_length = EXTERNAL_FLASH_PAGE_SIZE - page_offset;
  269. if (write_length > len) {
  270. write_length = len;
  271. }
  272. /* Wait for the write-in-progress bit to be cleared. */
  273. response = spi_flash_wait_while_busy();
  274. if (response != FLASH_STATUS_SUCCESS) {
  275. dprint("Failed to check WIP flag! [spi flash write block]\n");
  276. return response;
  277. }
  278. /* Enable writes. */
  279. response = spi_flash_write_enable();
  280. if (response != FLASH_STATUS_SUCCESS) {
  281. dprint("Failed to write-enable! [spi flash write block]\n");
  282. return response;
  283. }
  284. #if defined(CONSOLE_ENABLE) && defined(DEBUG_FLASH_SPI_OUTPUT)
  285. dprintf("[SPI FLASH W] 0x%08lx: ", addr);
  286. for (size_t i = 0; i < write_length; i++) {
  287. dprintf(" %02X", (int)(uint8_t)(write_buf[i]));
  288. }
  289. dprintf("\n");
  290. #endif // DEBUG_FLASH_SPI_OUTPUT
  291. /* Perform the write. */
  292. response = spi_flash_transaction(FLASH_CMD_PP, addr, write_buf, write_length);
  293. if (response != FLASH_STATUS_SUCCESS) {
  294. dprint("Failed to write block! [spi flash write block]\n");
  295. return response;
  296. }
  297. write_buf += write_length;
  298. addr += write_length;
  299. len -= write_length;
  300. }
  301. /* Wait for the write-in-progress bit to be cleared. */
  302. response = spi_flash_wait_while_busy();
  303. if (response != FLASH_STATUS_SUCCESS) {
  304. dprint("Failed to check WIP flag! [spi flash write block]\n");
  305. return response;
  306. }
  307. /* Disable writes. */
  308. response = spi_flash_write_disable();
  309. if (response != FLASH_STATUS_SUCCESS) {
  310. dprint("Failed to write-disable! [spi flash write block]\n");
  311. return response;
  312. }
  313. return response;
  314. }