You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
12 KiB

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