7bc3eef8cc262e12b0f823ba4c92cf97ca3dc1fa

Author
Nick Brassel <nick@tzarc.org>
Committer
GitHub <noreply@github.com>
Date

Message

SPI flash API cleanup, add async erase capability. (#23894)

Diff

This diff is truncated to protect this page.

  1diff --git a/builddefs/common_features.mk b/builddefs/common_features.mk
  2index 68f9a1dd08a8f03ad311768d49af0f9afef81aa3..498614dd2641f47c65492275e115e14aff2e2d91 100644
  3--- a/builddefs/common_features.mk
  4+++ b/builddefs/common_features.mk
  5@@ -282,18 +282,17 @@ ifneq ($(strip $(WEAR_LEVELING_DRIVER)),none)
  6   endif
  7 endif
  8 
  9-VALID_FLASH_DRIVER_TYPES := spi
 10+VALID_FLASH_DRIVER_TYPES := spi custom
 11 FLASH_DRIVER ?= none
 12 ifneq ($(strip $(FLASH_DRIVER)), none)
 13     ifeq ($(filter $(FLASH_DRIVER),$(VALID_FLASH_DRIVER_TYPES)),)
 14         $(call CATASTROPHIC_ERROR,Invalid FLASH_DRIVER,FLASH_DRIVER="$(FLASH_DRIVER)" is not a valid flash driver)
 15     else
 16-        OPT_DEFS += -DFLASH_ENABLE
 17+        OPT_DEFS += -DFLASH_ENABLE -DFLASH_DRIVER -DFLASH_DRIVER_$(strip $(shell echo $(FLASH_DRIVER) | tr '[:lower:]' '[:upper:]'))
 18+		COMMON_VPATH += $(DRIVER_PATH)/flash
 19         ifeq ($(strip $(FLASH_DRIVER)),spi)
 20-            SPI_DRIVER_REQUIRED = yes
 21-            OPT_DEFS += -DFLASH_DRIVER -DFLASH_SPI
 22-            COMMON_VPATH += $(DRIVER_PATH)/flash
 23             SRC += flash_spi.c
 24+            SPI_DRIVER_REQUIRED = yes
 25         endif
 26     endif
 27 endif
 28diff --git a/drivers/flash/flash.h b/drivers/flash/flash.h
 29new file mode 100644
 30index 0000000000000000000000000000000000000000..4d6247513987c748994361c3b95c971e25d70f06
 31--- /dev/null
 32+++ b/drivers/flash/flash.h
 33@@ -0,0 +1,126 @@
 34+// Copyright 2024 Nick Brassel (@tzarc)
 35+// SPDX-License-Identifier: GPL-2.0-or-later
 36+#pragma once
 37+
 38+#ifdef __cplusplus
 39+extern "C" {
 40+#endif
 41+
 42+#include <stdint.h>
 43+#include <stdlib.h>
 44+#include <stdbool.h>
 45+
 46+/**
 47+ * @brief The status of a flash operation.
 48+ */
 49+enum {
 50+    FLASH_STATUS_SUCCESS     = 0,  //< The operation completed successfully.
 51+    FLASH_STATUS_ERROR       = -1, //< An error occurred during the operation.
 52+    FLASH_STATUS_TIMEOUT     = -2, //< The operation timed out.
 53+    FLASH_STATUS_BAD_ADDRESS = -3, //< The address is out of bounds.
 54+    FLASH_STATUS_BUSY        = -4, //< The flash is busy.
 55+};
 56+
 57+/**
 58+ * @brief The status of a flash operation.
 59+ */
 60+typedef int16_t flash_status_t;
 61+
 62+/**
 63+ * @brief Initializes the flash driver.
 64+ *
 65+ * This function initializes the flash driver and prepares it for use.
 66+ * It should be called before any other flash-related functions are used.
 67+ */
 68+void flash_init(void);
 69+
 70+/**
 71+ * @brief Checks if the flash is busy.
 72+ *
 73+ * This function checks if the flash is currently busy with an operation.
 74+ *
 75+ * @return FLASH_STATUS_SUCCESS if the flash is not busy, FLASH_STATUS_BUSY if the flash is busy, or FLASH_STATUS_ERROR if an error occurred.
 76+ */
 77+flash_status_t flash_is_busy(void);
 78+
 79+/**
 80+ * @brief Initiates a chip erase operation.
 81+ *
 82+ * This function does not wait for the flash to become ready.
 83+ *
 84+ * @return FLASH_STATUS_SUCCESS if the erase command was successfully sent, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred.
 85+ */
 86+flash_status_t flash_begin_erase_chip(void);
 87+
 88+/**
 89+ * @brief Waits for the chip erase operation to complete.
 90+ *
 91+ * This function waits for the chip erase operation to complete.
 92+ *
 93+ * @return FLASH_STATUS_SUCCESS if the chip erase operation completed successfully, FLASH_STATUS_TIMEOUT if the flash was still busy, or FLASH_STATUS_ERROR if an error occurred.
 94+ */
 95+flash_status_t flash_wait_erase_chip(void);
 96+
 97+/**
 98+ * @brief Erases the entire flash memory chip.
 99+ *
100+ * This function initiates an erase operation to erase the entire flash memory chip.
101+ * It waits for the operation to complete.
102+ *
103+ * @return FLASH_STATUS_SUCCESS if the erase was successfully executed, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred.
104+ */
105+flash_status_t flash_erase_chip(void);
106+
107+/**
108+ * @brief Erases a block of flash memory.
109+ *
110+ * This function initiates an erase operation to erase a block of flash memory.
111+ * It waits for the operation to complete.
112+ *
113+ * @param addr The address of the block to erase.
114+ *
115+ * @return FLASH_STATUS_SUCCESS if the erase was successfully executed, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred.
116+ */
117+flash_status_t flash_erase_block(uint32_t addr);
118+
119+/**
120+ * @brief Erases a sector of flash memory.
121+ *
122+ * This function initiates an erase operation to erase a sector of flash memory.
123+ * It waits for the operation to complete.
124+ *
125+ * @param addr The address of the sector to erase.
126+ *
127+ * @return FLASH_STATUS_SUCCESS if the erase was successfully executed, FLASH_STATUS_TIMEOUT if the flash is busy, or FLASH_STATUS_ERROR if an error occurred.
128+ */
129+flash_status_t flash_erase_sector(uint32_t addr);
130+
131+/**
132+ * @brief Reads a range of flash memory.
133diff --git a/drivers/flash/flash_spi.c b/drivers/flash/flash_spi.c
134index 0c0eb8a99e5bb58e0aad072d5dc82c444c9e51e6..7226773ff41236337375db75ade22b60a363b04e 100644
135--- a/drivers/flash/flash_spi.c
136+++ b/drivers/flash/flash_spi.c
137@@ -1,22 +1,10 @@
138-/*
139-Copyright (C) 2021 Westberry Technology (ChangZhou) Corp., Ltd
140-
141-This program is free software: you can redistribute it and/or modify
142-it under the terms of the GNU General Public License as published by
143-the Free Software Foundation, either version 2 of the License, or
144-(at your option) any later version.
145-
146-This program is distributed in the hope that it will be useful,
147-but WITHOUT ANY WARRANTY; without even the implied warranty of
148-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
149-GNU General Public License for more details.
150-
151-You should have received a copy of the GNU General Public License
152-along with this program.  If not, see <http://www.gnu.org/licenses/>.
153-*/
154+// Copyright 2021 Westberry Technology (ChangZhou) Corp., Ltd
155+// Copyright 2024 Nick Brassel (@tzarc)
156+// SPDX-License-Identifier: GPL-2.0-or-later
157 
158 #include <string.h>
159 
160+#include "flash.h"
161 #include "util.h"
162 #include "wait.h"
163 #include "debug.h"
164@@ -69,33 +57,43 @@ static bool spi_flash_start(void) {
165     return spi_start(EXTERNAL_FLASH_SPI_SLAVE_SELECT_PIN, EXTERNAL_FLASH_SPI_LSBFIRST, EXTERNAL_FLASH_SPI_MODE, EXTERNAL_FLASH_SPI_CLOCK_DIVISOR);
166 }
167 
168-static flash_status_t spi_flash_wait_while_busy(void) {
169-    uint32_t       deadline = timer_read32() + EXTERNAL_FLASH_SPI_TIMEOUT;
170+static flash_status_t spi_flash_wait_while_busy_multiplier(int multiplier) {
171     flash_status_t response = FLASH_STATUS_SUCCESS;
172-    uint8_t        retval;
173-
174+    uint32_t       deadline = timer_read32() + ((EXTERNAL_FLASH_SPI_TIMEOUT)*multiplier);
175     do {
176-        bool res = spi_flash_start();
177-        if (!res) {
178-            dprint("Failed to start SPI! [spi flash wait while busy]\n");
179-            return FLASH_STATUS_ERROR;
180-        }
181-
182-        spi_write(FLASH_CMD_RDSR);
183-
184-        retval = (uint8_t)spi_read();
185-
186-        spi_stop();
187-
188         if (timer_read32() >= deadline) {
189             response = FLASH_STATUS_TIMEOUT;
190             break;
191         }
192-    } while (retval & FLASH_FLAG_WIP);
193 
194+        response = flash_is_busy();
195+    } while (response == FLASH_STATUS_BUSY);
196     return response;
197 }
198 
199+static flash_status_t spi_flash_wait_while_busy(void) {
200+    return spi_flash_wait_while_busy_multiplier(1);
201+}
202+
203+flash_status_t flash_is_busy(void) {
204+    bool res = spi_flash_start();
205+    if (!res) {
206+        dprint("Failed to start SPI! [spi flash wait while busy]\n");
207+        return FLASH_STATUS_ERROR;
208+    }
209+
210+    spi_write(FLASH_CMD_RDSR);
211+    spi_status_t status = spi_read();
212+    spi_stop();
213+
214+    if (status < 0) {
215+        return status;
216+    }
217+
218+    uint8_t sr = (uint8_t)status;
219+    return (sr & FLASH_FLAG_WIP) ? FLASH_STATUS_BUSY : FLASH_STATUS_SUCCESS;
220+}
221+
222 static flash_status_t spi_flash_write_enable(void) {
223     bool res = spi_flash_start();
224     if (!res) {
225@@ -104,7 +102,6 @@ static flash_status_t spi_flash_write_enable(void) {
226     }
227 
228     spi_write(FLASH_CMD_WREN);
229-
230     spi_stop();
231 
232     return FLASH_STATUS_SUCCESS;
233@@ -118,7 +115,6 @@ static flash_status_t spi_flash_write_disable(void) {
234     }
235 
236     spi_write(FLASH_CMD_WRDI);
237diff --git a/drivers/flash/flash_spi.h b/drivers/flash/flash_spi.h
238index 87460fc210ee6aec69a1c0200be9a0a373e1671d..7a979daf0f70fb1b1282daeba493b7fdd2e9c31d 100644
239--- a/drivers/flash/flash_spi.h
240+++ b/drivers/flash/flash_spi.h
241@@ -17,6 +17,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
242 
243 #pragma once
244 
245+#include "flash.h"
246+
247 /* All the following default configurations are based on MX25L4006E Nor FLASH. */
248 
249 /*
250@@ -105,32 +107,3 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
251     The page count of the FLASH, calculated by total FLASH size and page size.
252 */
253 #define EXTERNAL_FLASH_PAGE_COUNT ((EXTERNAL_FLASH_SIZE) / (EXTERNAL_FLASH_PAGE_SIZE))
254-
255-typedef int16_t flash_status_t;
256-
257-#define FLASH_STATUS_SUCCESS (0)
258-#define FLASH_STATUS_ERROR (-1)
259-#define FLASH_STATUS_TIMEOUT (-2)
260-#define FLASH_STATUS_BAD_ADDRESS (-3)
261-
262-#ifdef __cplusplus
263-extern "C" {
264-#endif
265-
266-#include <stdint.h>
267-
268-void flash_init(void);
269-
270-flash_status_t flash_erase_chip(void);
271-
272-flash_status_t flash_erase_block(uint32_t addr);
273-
274-flash_status_t flash_erase_sector(uint32_t addr);
275-
276-flash_status_t flash_read_block(uint32_t addr, void *buf, size_t len);
277-
278-flash_status_t flash_write_block(uint32_t addr, const void *buf, size_t len);
279-
280-#ifdef __cplusplus
281-}
282-#endif
283diff --git a/drivers/wear_leveling/wear_leveling_flash_spi.c b/drivers/wear_leveling/wear_leveling_flash_spi.c
284index 6191f8bf09582a246753ca2c23707cdcb53643d9..304aed1641fb56dbdc0ba4ef2dd80a5306e94daf 100644
285--- a/drivers/wear_leveling/wear_leveling_flash_spi.c
286+++ b/drivers/wear_leveling/wear_leveling_flash_spi.c
287@@ -58,7 +58,7 @@ bool backing_store_read(uint32_t address, backing_store_int_t *value) {
288 bool backing_store_read_bulk(uint32_t address, backing_store_int_t *values, size_t item_count) {
289     bs_dprintf("Read  ");
290     uint32_t       offset = (WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET) * (EXTERNAL_FLASH_BLOCK_SIZE) + address;
291-    flash_status_t status = flash_read_block(offset, values, sizeof(backing_store_int_t) * item_count);
292+    flash_status_t status = flash_read_range(offset, values, sizeof(backing_store_int_t) * item_count);
293     if (status == FLASH_STATUS_SUCCESS) {
294         for (size_t i = 0; i < item_count; ++i) {
295             values[i] = ~values[i];
296@@ -88,7 +88,7 @@ bool backing_store_write_bulk(uint32_t address, backing_store_int_t *values, siz
297         }
298 
299         // Write out the block
300-        if (flash_write_block(offset, temp, sizeof(backing_store_int_t) * this_loop) != FLASH_STATUS_SUCCESS) {
301+        if (flash_write_range(offset, temp, sizeof(backing_store_int_t) * this_loop) != FLASH_STATUS_SUCCESS) {
302             return false;
303         }
304