1919#define CYW43_SLEEP_CHECK_MS 50
2020#endif
2121
22- static async_context_t * cyw43_async_context ;
22+ static async_context_t * cyw43_async_context = NULL ;
23+
24+ #if CYW43_USE_FIRMWARE_PARTITION
25+ #include "pico/bootrom.h"
26+ #include "hardware/flash.h"
27+ #include "boot/picobin.h"
28+ #include <stdlib.h>
29+
30+ int32_t cyw43_wifi_fw_len ;
31+ int32_t cyw43_clm_len ;
32+ uintptr_t fw_data ;
33+ #endif
2334
2435static void cyw43_sleep_timeout_reached (async_context_t * context , async_at_time_worker_t * worker );
2536static void cyw43_do_poll (async_context_t * context , async_when_pending_worker_t * worker );
@@ -104,6 +115,87 @@ static void cyw43_sleep_timeout_reached(async_context_t *context, __unused async
104115}
105116
106117bool cyw43_driver_init (async_context_t * context ) {
118+ #if CYW43_USE_FIRMWARE_PARTITION
119+ uint32_t buffer [(16 * 4 ) + 1 ] = {}; // maximum of 16 partitions, each with maximum of 4 words returned, plus 1
120+ int ret = rom_get_partition_table_info (buffer , count_of (buffer ), PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_PARTITION_ID );
121+
122+ assert (buffer [0 ] == (PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_PARTITION_ID ));
123+
124+ if (ret > 0 ) {
125+ int i = 1 ;
126+ int p = 0 ;
127+ int picked_p = -1 ;
128+ while (i < ret ) {
129+ i ++ ;
130+ uint32_t flags_and_permissions = buffer [i ++ ];
131+ bool has_id = (flags_and_permissions & PICOBIN_PARTITION_FLAGS_HAS_ID_BITS );
132+ if (has_id ) {
133+ uint64_t id = 0 ;
134+ id |= buffer [i ++ ];
135+ id |= ((uint64_t )(buffer [i ++ ]) << 32ull );
136+ if (id == CYW43_FIRMWARE_PARTITION_ID ) {
137+ picked_p = p ;
138+ break ;
139+ }
140+ }
141+
142+ p ++ ;
143+ }
144+
145+ if (picked_p >= 0 ) {
146+ #ifdef __riscv
147+ // Increased bootrom stack is required for this function
148+ bootrom_stack_t stack = {
149+ .base = malloc (0x400 ),
150+ .size = 0x400
151+ };
152+ rom_set_bootrom_stack (& stack );
153+ #endif
154+ uint32_t * workarea = malloc (0x1000 );
155+ picked_p = rom_pick_ab_update_partition (workarea , 0x1000 , picked_p );
156+ free (workarea );
157+ #ifdef __riscv
158+ // Reset bootrom stack
159+ rom_set_bootrom_stack (& stack );
160+ free (stack .base );
161+ #endif
162+
163+ if (picked_p < 0 ) {
164+ if (picked_p == BOOTROM_ERROR_NOT_FOUND ) {
165+ CYW43_DEBUG ("Chosen CYW43 firmware partition was not verified\n" );
166+ } else if (picked_p == BOOTROM_ERROR_NOT_PERMITTED ) {
167+ CYW43_DEBUG ("Too many update boots going on at once\n" );
168+ }
169+ return false;
170+ }
171+
172+ CYW43_DEBUG ("Chosen CYW43 firmware in partition %d\n" , picked_p );
173+ int ret = rom_get_partition_table_info (buffer , count_of (buffer ), PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION | (picked_p << 24 ));
174+ assert (buffer [0 ] == (PT_INFO_PARTITION_LOCATION_AND_FLAGS | PT_INFO_SINGLE_PARTITION ));
175+ assert (ret == 3 );
176+
177+ uint32_t location_and_permissions = buffer [1 ];
178+ uint32_t saddr = ((location_and_permissions >> PICOBIN_PARTITION_LOCATION_FIRST_SECTOR_LSB ) & 0x1fffu ) * FLASH_SECTOR_SIZE ;
179+ uint32_t eaddr = (((location_and_permissions >> PICOBIN_PARTITION_LOCATION_LAST_SECTOR_LSB ) & 0x1fffu ) + 1 ) * FLASH_SECTOR_SIZE ;
180+ // Starts with metadata block
181+ while (saddr < eaddr && * (uint32_t * )(XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr ) != PICOBIN_BLOCK_MARKER_END ) {
182+ saddr += 4 ;
183+ }
184+ saddr += 4 ;
185+ // Now onto data
186+ cyw43_wifi_fw_len = * (uint32_t * )(XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr );
187+ cyw43_clm_len = * (uint32_t * )(XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr + 4 );
188+ fw_data = XIP_NOCACHE_NOALLOC_NOTRANSLATE_BASE + saddr + 8 ;
189+ } else {
190+ CYW43_DEBUG ("No CYW43 firmware partition found, so cannot get firmware from partition\n" );
191+ return false;
192+ }
193+ } else {
194+ CYW43_DEBUG ("No partition table, so cannot get firmware from partition - get_partition_table_info returned %d\n" , ret );
195+ return false;
196+ }
197+
198+ #endif
107199 cyw43_init (& cyw43_state );
108200 cyw43_async_context = context ;
109201 // we need the IRQ to be on the same core as the context, because we need to be able to enable/disable the IRQ
@@ -114,13 +206,15 @@ bool cyw43_driver_init(async_context_t *context) {
114206}
115207
116208void cyw43_driver_deinit (async_context_t * context ) {
117- assert (context == cyw43_async_context );
118- async_context_remove_at_time_worker (context , & sleep_timeout_worker );
119- async_context_remove_when_pending_worker (context , & cyw43_poll_worker );
120- // the IRQ IS on the same core as the context, so must be de-initialized there
121- async_context_execute_sync (context , cyw43_irq_deinit , NULL );
122- cyw43_deinit (& cyw43_state );
123- cyw43_async_context = NULL ;
209+ if (cyw43_async_context != NULL ) {
210+ assert (context == cyw43_async_context );
211+ async_context_remove_at_time_worker (context , & sleep_timeout_worker );
212+ async_context_remove_when_pending_worker (context , & cyw43_poll_worker );
213+ // the IRQ IS on the same core as the context, so must be de-initialized there
214+ async_context_execute_sync (context , cyw43_irq_deinit , NULL );
215+ cyw43_deinit (& cyw43_state );
216+ cyw43_async_context = NULL ;
217+ }
124218}
125219
126220// todo maybe add an #ifdef in cyw43_driver
0 commit comments