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