2 * Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
4 * SPDX-License-Identifier: BSD-3-Clause
7 #include "pico/btstack_flash_bank.h"
8 #include "pico/flash.h"
9 #include "hardware/sync.h"
10 #include "hardware/flash.h"
14 static_assert(PICO_FLASH_BANK_TOTAL_SIZE
% (FLASH_SECTOR_SIZE
* 2) == 0, "PICO_FLASH_BANK_TOTAL_SIZE invalid");
15 static_assert(PICO_FLASH_BANK_TOTAL_SIZE
<= PICO_FLASH_SIZE_BYTES
, "PICO_FLASH_BANK_TOTAL_SIZE too big");
18 #define PICO_FLASH_BANK_SIZE (PICO_FLASH_BANK_TOTAL_SIZE / 2)
21 #define DEBUG_PRINT(format,args...) printf(format, ## args)
23 #define DEBUG_PRINT(...)
26 static uint32_t pico_flash_bank_get_size(void * context
) {
28 return PICO_FLASH_BANK_SIZE
;
31 static uint32_t pico_flash_bank_get_alignment(void * context
) {
40 } mutation_operation_t
;
42 static void pico_flash_bank_perform_flash_mutation_operation(void *param
) {
43 const mutation_operation_t
*mop
= (const mutation_operation_t
*)param
;
44 if (mop
->op_is_erase
) {
45 flash_range_erase(mop
->p0
, PICO_FLASH_BANK_SIZE
);
47 flash_range_program(mop
->p0
, (const uint8_t *)mop
->p1
, FLASH_PAGE_SIZE
);
51 #ifndef pico_flash_bank_get_storage_offset_func
52 static inline uint32_t pico_flash_bank_get_fixed_storage_offset(void) {
53 static_assert(PICO_FLASH_BANK_STORAGE_OFFSET
+ PICO_FLASH_BANK_TOTAL_SIZE
<= PICO_FLASH_SIZE_BYTES
, "PICO_FLASH_BANK_TOTAL_SIZE too big");
55 // Check we're not overlapping the binary in flash
56 extern char __flash_binary_end
;
57 assert(((uintptr_t)&__flash_binary_end
- XIP_BASE
<= PICO_FLASH_BANK_STORAGE_OFFSET
));
59 return PICO_FLASH_BANK_STORAGE_OFFSET
;
61 #define pico_flash_bank_get_storage_offset_func pico_flash_bank_get_fixed_storage_offset
63 extern uint32_t pico_flash_bank_get_storage_offset_func(void);
66 static void pico_flash_bank_erase(void * context
, int bank
) {
68 DEBUG_PRINT("erase: bank %d\n", bank
);
69 mutation_operation_t mop
= {
71 .p0
= pico_flash_bank_get_storage_offset_func() + (PICO_FLASH_BANK_SIZE
* bank
),
73 // todo choice of timeout and check return code... currently we have no way to return an error
74 // to the caller anyway. flash_safe_execute asserts by default on problem other than timeout,
75 // so that's fine for now, and UINT32_MAX is a timeout of 49 days which seems long enough
76 flash_safe_execute(pico_flash_bank_perform_flash_mutation_operation
, &mop
, UINT32_MAX
);
79 static void pico_flash_bank_read(void *context
, int bank
, uint32_t offset
, uint8_t *buffer
, uint32_t size
) {
81 DEBUG_PRINT("read: bank %d offset %u size %u\n", bank
, offset
, size
);
86 assert(offset
< PICO_FLASH_BANK_SIZE
);
87 if (offset
>= PICO_FLASH_BANK_SIZE
) return;
89 assert((offset
+ size
) <= PICO_FLASH_BANK_SIZE
);
90 if ((offset
+ size
) > PICO_FLASH_BANK_SIZE
) return;
93 memcpy(buffer
, (void *)(XIP_BASE
+ pico_flash_bank_get_storage_offset_func() + (PICO_FLASH_BANK_SIZE
* bank
) + offset
), size
);
96 static void pico_flash_bank_write(void * context
, int bank
, uint32_t offset
, const uint8_t *data
, uint32_t size
) {
98 DEBUG_PRINT("write: bank %d offset %u size %u\n", bank
, offset
, size
);
101 if (bank
> 1) return;
103 assert(offset
< PICO_FLASH_BANK_SIZE
);
104 if (offset
>= PICO_FLASH_BANK_SIZE
) return;
106 assert((offset
+ size
) <= PICO_FLASH_BANK_SIZE
);
107 if ((offset
+ size
) > PICO_FLASH_BANK_SIZE
) return;
109 if (size
== 0) return;
111 // calc bank start position
112 const uint32_t bank_start_pos
= pico_flash_bank_get_storage_offset_func() + (PICO_FLASH_BANK_SIZE
* bank
);
114 // Calculate first and last page in the bank
115 const uint32_t first_page
= offset
/ FLASH_PAGE_SIZE
;
116 const uint32_t last_page
= (offset
+ size
+ FLASH_PAGE_SIZE
- 1) / FLASH_PAGE_SIZE
;
118 // Now we only care about the offset in the first page
119 offset
%= FLASH_PAGE_SIZE
;
121 // Amount of data we've copied
122 uint32_t data_pos
= 0;
123 uint32_t size_left
= size
;
125 // Write all the pages required
126 for(uint32_t page
= first_page
; page
< last_page
; page
++) {
127 uint8_t page_data
[FLASH_PAGE_SIZE
];
129 assert(data_pos
< size
&& size_left
<= size
);
131 // Copy data we're not going to overwrite in the first page
132 if (page
== first_page
&& offset
> 0) {
134 (void *)(XIP_BASE
+ bank_start_pos
+ (page
* FLASH_PAGE_SIZE
)),
138 // Copy the data we're not going to overwrite in the last page
139 if (page
== last_page
- 1 && (offset
+ size_left
) < FLASH_PAGE_SIZE
) {
140 memcpy(page_data
+ offset
+ size_left
,
141 (void *)(XIP_BASE
+ bank_start_pos
+ (page
* FLASH_PAGE_SIZE
) + offset
+ size_left
),
142 FLASH_PAGE_SIZE
- offset
- size_left
);
145 // Now copy the new data into the page
146 const uint32_t size_to_copy
= MIN(size_left
, FLASH_PAGE_SIZE
- offset
);
147 memcpy(page_data
+ offset
, data
+ data_pos
, size_to_copy
);
149 data_pos
+= size_to_copy
;
150 size_left
-= size_to_copy
;
152 // zero offset for the following pages
155 // Now program the entire page
156 mutation_operation_t mop
= {
157 .op_is_erase
= false,
158 .p0
= bank_start_pos
+ (page
* FLASH_PAGE_SIZE
),
159 .p1
= (uintptr_t)page_data
161 // todo choice of timeout and check return code... currently we have no way to return an error
162 // to the caller anyway. flash_safe_execute asserts by default on problem other than timeout,
163 // so that's fine for now, and UINT32_MAX is a timeout of 49 days which seems long enough
164 flash_safe_execute(pico_flash_bank_perform_flash_mutation_operation
, &mop
, UINT32_MAX
);
168 static const hal_flash_bank_t pico_flash_bank_instance_obj
= {
169 /* uint32_t (*get_size)(..) */ &pico_flash_bank_get_size
,
170 /* uint32_t (*get_alignment)(..); */ &pico_flash_bank_get_alignment
,
171 /* void (*erase)(..); */ &pico_flash_bank_erase
,
172 /* void (*read)(..); */ &pico_flash_bank_read
,
173 /* void (*write)(..); */ &pico_flash_bank_write
,
176 const hal_flash_bank_t
*pico_flash_bank_instance(void) {
177 return &pico_flash_bank_instance_obj
;