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+
1037bool flash_check_whoami (void ) { return true; }
1138
1239FlashAddress 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
2653status_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
39169status_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
44175int 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
50184status_t flash_impl_enter_low_power_mode (void ) { return S_SUCCESS ; }
51185status_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
61216uint32_t flash_impl_get_typical_sector_erase_duration_ms (void ) { return 150 ; }
62217
0 commit comments