Skip to content

Commit fa56dab

Browse files
committed
feat: flash driver
1 parent f450a9a commit fa56dab

1 file changed

Lines changed: 165 additions & 10 deletions

File tree

src/fw/drivers/flash/sf32lb52_int_flash.c

Lines changed: 165 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,33 @@
77
#include "system/status_codes.h"
88
#include "util/math.h"
99

10+
#include "board/board.h"
11+
12+
static QSPI_FLASH_CTX_T spi_flash_handle;
13+
static DMA_HandleTypeDef spi_flash_dma_handle;
14+
15+
#define FLASH2_IRQHandler DMAC1_CH2_IRQHandler
16+
#define FLASH2_DMA_INSTANCE DMA1_Channel2
17+
#define FLASH2_DMA_REQUEST DMA_REQUEST_1
18+
#define FLASH2_DMA_IRQ DMAC1_CH2_IRQn
19+
20+
#define FLASH2_CONFIG \
21+
{ \
22+
.Instance = FLASH2, \
23+
.line = 2, \
24+
.base = FLASH2_BASE_ADDR, \
25+
.msize = 4, \
26+
.SpiMode = 0, \
27+
}
28+
29+
#define FLASH2_DMA_CONFIG \
30+
{ \
31+
.dma_irq_prio = 0, \
32+
.Instance = FLASH2_DMA_INSTANCE, \
33+
.dma_irq = FLASH2_DMA_IRQ, \
34+
.request = FLASH2_DMA_REQUEST, \
35+
}
36+
1037
bool flash_check_whoami(void) { return true; }
1138

1239
FlashAddress flash_impl_get_sector_base_address(FlashAddress addr) {
@@ -25,27 +52,134 @@ status_t flash_impl_write_protect(FlashAddress start_sector, FlashAddress end_se
2552

2653
status_t flash_impl_unprotect(void) { return S_SUCCESS; }
2754

28-
status_t flash_impl_init(bool coredump_mode) { return S_SUCCESS; }
55+
status_t flash_impl_init(bool coredump_mode) {
56+
(void)coredump_mode;
57+
qspi_configure_t flash_cfg = FLASH2_CONFIG;
58+
struct dma_config flash_dma = FLASH2_DMA_CONFIG;
59+
60+
flash_cfg.line = HAL_FLASH_QMODE;
61+
HAL_Delay_us(0);
62+
spi_flash_handle.dual_mode = 1;
63+
spi_flash_handle.flash_mode = 0; // nor
64+
HAL_StatusTypeDef res = HAL_FLASH_Init(&spi_flash_handle, &flash_cfg, &spi_flash_dma_handle,
65+
&flash_dma, 1);
66+
67+
if (res != HAL_OK) {
68+
return E_ERROR;
69+
}
70+
return S_SUCCESS;
71+
}
72+
73+
status_t flash_impl_get_erase_status(void) {
74+
// A call to the HAL_QSPIEX_SECT_ERASE interface will always return success after the call
75+
return S_SUCCESS;
76+
}
77+
78+
static int prv_erase_nor(uint32_t addr, uint32_t size) {
79+
FLASH_HandleTypeDef *hflash;
80+
uint32_t taddr, remain;
81+
int res;
82+
83+
hflash = &spi_flash_handle.handle;
84+
85+
if ((addr < hflash->base) || (addr > (hflash->base + hflash->size))) return 1;
86+
87+
taddr = addr - hflash->base;
88+
remain = size;
89+
90+
if ((taddr & (QSPI_NOR_SECT_SIZE - 1)) != 0) return -1;
91+
if ((remain & (QSPI_NOR_SECT_SIZE - 1)) != 0) return -2;
92+
93+
while (remain > 0) {
94+
res = HAL_QSPIEX_SECT_ERASE(hflash, taddr);
95+
if (res != 0) return 1;
96+
97+
remain -= QSPI_NOR_SECT_SIZE;
98+
taddr += QSPI_NOR_SECT_SIZE;
99+
}
100+
101+
return 0;
102+
}
29103

30-
status_t flash_impl_get_erase_status(void) { return S_SUCCESS; }
104+
static int prv_write_nor(uint32_t addr, uint8_t *buf, uint32_t size) {
105+
FLASH_HandleTypeDef *hflash;
106+
uint32_t taddr, start, remain, fill;
107+
uint8_t *tbuf;
108+
int res;
109+
110+
hflash = &spi_flash_handle.handle;
111+
112+
if ((addr < hflash->base) || (addr > (hflash->base + hflash->size))) return 0;
113+
114+
taddr = addr - hflash->base;
115+
tbuf = (uint8_t *)buf;
116+
remain = size;
117+
118+
start = taddr & (QSPI_NOR_PAGE_SIZE - 1);
119+
if (start > 0) // start address not page aligned
120+
{
121+
fill = QSPI_NOR_PAGE_SIZE - start; // remained size in one page
122+
if (fill > size) // not over one page
123+
{
124+
fill = size;
125+
}
126+
res = HAL_QSPIEX_WRITE_PAGE(hflash, taddr, tbuf, fill);
127+
if ((uint32_t)res != fill) return 0;
128+
taddr += fill;
129+
tbuf += fill;
130+
remain -= fill;
131+
}
132+
while (remain > 0) {
133+
fill = remain > QSPI_NOR_PAGE_SIZE ? QSPI_NOR_PAGE_SIZE : remain;
134+
res = HAL_QSPIEX_WRITE_PAGE(hflash, taddr, tbuf, fill);
135+
if ((uint32_t)res != fill) return 0;
136+
taddr += fill;
137+
tbuf += fill;
138+
remain -= fill;
139+
}
140+
141+
return size;
142+
}
31143

32-
status_t flash_impl_erase_subsector_begin(FlashAddress subsector_addr) { return S_SUCCESS; }
33-
status_t flash_impl_erase_sector_begin(FlashAddress sector_addr) { return S_SUCCESS; }
144+
status_t flash_impl_erase_subsector_begin(FlashAddress subsector_addr) {
145+
if (prv_erase_nor(subsector_addr, SUBSECTOR_SIZE_BYTES) != 0) {
146+
return E_ERROR;
147+
}
148+
return S_SUCCESS;
149+
}
150+
status_t flash_impl_erase_sector_begin(FlashAddress sector_addr) {
151+
if (prv_erase_nor(sector_addr, SECTOR_SIZE_BYTES) != 0) {
152+
return E_ERROR;
153+
}
154+
return S_SUCCESS;
155+
}
34156

35-
status_t flash_impl_erase_suspend(FlashAddress sector_addr) { return S_SUCCESS; }
157+
status_t flash_impl_erase_suspend(FlashAddress sector_addr) {
158+
// Everything will be blocked during the erase process, so nothing will happen if you call this
159+
// function.
160+
return S_SUCCESS;
161+
}
36162

37-
status_t flash_impl_erase_resume(FlashAddress sector_addr) { return S_SUCCESS; }
163+
status_t flash_impl_erase_resume(FlashAddress sector_addr) {
164+
// Everything will be blocked during the erase process, so nothing will happen if you call this
165+
// function.
166+
return S_SUCCESS;
167+
}
38168

39169
status_t flash_impl_read_sync(void *buffer_ptr, FlashAddress start_addr, size_t buffer_size) {
40170
PBL_ASSERT(buffer_size > 0, "flash_impl_read_sync() called with 0 bytes to read");
171+
memcpy(buffer_ptr, (void *)(start_addr), buffer_size);
41172
return S_SUCCESS;
42173
}
43174

44175
int flash_impl_write_page_begin(const void *buffer, const FlashAddress start_addr, size_t len) {
45-
return len;
176+
return prv_write_nor(start_addr, (uint8_t *)buffer, len);
46177
}
47178

48-
status_t flash_impl_get_write_status(void) { return S_SUCCESS; }
179+
status_t flash_impl_get_write_status(void) {
180+
// It will be done in HAL_QSPIEX_WRITE_PAGE, so it must return success
181+
return S_SUCCESS;
182+
}
49183

50184
status_t flash_impl_enter_low_power_mode(void) { return S_SUCCESS; }
51185
status_t flash_impl_exit_low_power_mode(void) { return S_SUCCESS; }
@@ -55,8 +189,29 @@ status_t flash_impl_set_burst_mode(bool burst_mode) {
55189
return S_SUCCESS;
56190
}
57191

58-
status_t flash_impl_blank_check_sector(FlashAddress addr) { return S_SUCCESS; }
59-
status_t flash_impl_blank_check_subsector(FlashAddress addr) { return S_SUCCESS; }
192+
static bool prv_blank_check_poll(uint32_t addr, bool is_subsector) {
193+
const uint32_t size_bytes = is_subsector ? SUBSECTOR_SIZE_BYTES : SECTOR_SIZE_BYTES;
194+
const uint32_t BUF_SIZE_BYTES = 128;
195+
const uint32_t BUF_SIZE_WORDS = BUF_SIZE_BYTES / sizeof(uint32_t);
196+
const uint32_t FLASH_RESET_WORD_VALUE = 0xFFFFFFFF;
197+
uint32_t buffer[BUF_SIZE_WORDS];
198+
for (uint32_t offset = 0; offset < size_bytes; offset += BUF_SIZE_BYTES) {
199+
flash_impl_read_sync(buffer, addr + offset, BUF_SIZE_BYTES);
200+
for (uint32_t i = 0; i < BUF_SIZE_WORDS; ++i) {
201+
if (buffer[i] != FLASH_RESET_WORD_VALUE) {
202+
return false;
203+
}
204+
}
205+
}
206+
return true;
207+
}
208+
209+
status_t flash_impl_blank_check_sector(FlashAddress addr) {
210+
return prv_blank_check_poll(addr, false /* !is_subsector */);
211+
}
212+
status_t flash_impl_blank_check_subsector(FlashAddress addr) {
213+
return prv_blank_check_poll(addr, true /* !is_subsector */);
214+
}
60215

61216
uint32_t flash_impl_get_typical_sector_erase_duration_ms(void) { return 150; }
62217

0 commit comments

Comments
 (0)