1 /*
2 * Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "pico/btstack_flash_bank.h"
8 #include "pico/flash.h"
9 #include "hardware/sync.h"
10 #include <string.h>
11
12 // Check sizes
13 static_assert(PICO_FLASH_BANK_TOTAL_SIZE % (FLASH_SECTOR_SIZE * 2) == 0, "PICO_FLASH_BANK_TOTAL_SIZE invalid");
14 static_assert(PICO_FLASH_BANK_TOTAL_SIZE <= PICO_FLASH_SIZE_BYTES, "PICO_FLASH_BANK_TOTAL_SIZE too big");
15
16 // Size of one bank
17 #define PICO_FLASH_BANK_SIZE (PICO_FLASH_BANK_TOTAL_SIZE / 2)
18
19 #if 0
20 #define DEBUG_PRINT(format,args...) printf(format, ## args)
21 #else
22 #define DEBUG_PRINT(...)
23 #endif
24
pico_flash_bank_get_size(void * context)25 static uint32_t pico_flash_bank_get_size(void * context) {
26 (void)(context);
27 return PICO_FLASH_BANK_SIZE;
28 }
29
pico_flash_bank_get_alignment(void * context)30 static uint32_t pico_flash_bank_get_alignment(void * context) {
31 (void)(context);
32 return 1;
33 }
34
35 typedef struct {
36 bool op_is_erase;
37 uintptr_t p0;
38 uintptr_t p1;
39 } mutation_operation_t;
40
pico_flash_bank_perform_flash_mutation_operation(void * param)41 static void pico_flash_bank_perform_flash_mutation_operation(void *param) {
42 const mutation_operation_t *mop = (const mutation_operation_t *)param;
43 if (mop->op_is_erase) {
44 flash_range_erase(mop->p0, PICO_FLASH_BANK_SIZE);
45 } else {
46 flash_range_program(mop->p0, (const uint8_t *)mop->p1, FLASH_PAGE_SIZE);
47 }
48 }
49
50 #ifndef pico_flash_bank_get_storage_offset_func
pico_flash_bank_get_fixed_storage_offset(void)51 static inline uint32_t pico_flash_bank_get_fixed_storage_offset(void) {
52 static_assert(PICO_FLASH_BANK_STORAGE_OFFSET + PICO_FLASH_BANK_TOTAL_SIZE <= PICO_FLASH_SIZE_BYTES, "PICO_FLASH_BANK_TOTAL_SIZE too big");
53 #ifndef NDEBUG
54 // Check we're not overlapping the binary in flash
55 extern char __flash_binary_end;
56 assert(((uintptr_t)&__flash_binary_end - XIP_BASE <= PICO_FLASH_BANK_STORAGE_OFFSET));
57 #endif
58 return PICO_FLASH_BANK_STORAGE_OFFSET;
59 }
60 #define pico_flash_bank_get_storage_offset_func pico_flash_bank_get_fixed_storage_offset
61 #else
62 extern uint32_t pico_flash_bank_get_storage_offset_func(void);
63 #endif
64
pico_flash_bank_erase(void * context,int bank)65 static void pico_flash_bank_erase(void * context, int bank) {
66 (void)(context);
67 DEBUG_PRINT("erase: bank %d\n", bank);
68 mutation_operation_t mop = {
69 .op_is_erase = true,
70 .p0 = pico_flash_bank_get_storage_offset_func() + (PICO_FLASH_BANK_SIZE * bank),
71 };
72 // todo choice of timeout and check return code... currently we have no way to return an error
73 // to the caller anyway. flash_safe_execute asserts by default on problem other than timeout,
74 // so that's fine for now, and UINT32_MAX is a timeout of 49 days which seems long enough
75 flash_safe_execute(pico_flash_bank_perform_flash_mutation_operation, &mop, UINT32_MAX);
76 }
77
pico_flash_bank_read(void * context,int bank,uint32_t offset,uint8_t * buffer,uint32_t size)78 static void pico_flash_bank_read(void *context, int bank, uint32_t offset, uint8_t *buffer, uint32_t size) {
79 (void)(context);
80 DEBUG_PRINT("read: bank %d offset %u size %u\n", bank, offset, size);
81
82 assert(bank <= 1);
83 if (bank > 1) return;
84
85 assert(offset < PICO_FLASH_BANK_SIZE);
86 if (offset >= PICO_FLASH_BANK_SIZE) return;
87
88 assert((offset + size) <= PICO_FLASH_BANK_SIZE);
89 if ((offset + size) > PICO_FLASH_BANK_SIZE) return;
90
91 // Flash is xip
92 memcpy(buffer, (void *)(XIP_BASE + pico_flash_bank_get_storage_offset_func() + (PICO_FLASH_BANK_SIZE * bank) + offset), size);
93 }
94
pico_flash_bank_write(void * context,int bank,uint32_t offset,const uint8_t * data,uint32_t size)95 static void pico_flash_bank_write(void * context, int bank, uint32_t offset, const uint8_t *data, uint32_t size) {
96 (void)(context);
97 DEBUG_PRINT("write: bank %d offset %u size %u\n", bank, offset, size);
98
99 assert(bank <= 1);
100 if (bank > 1) return;
101
102 assert(offset < PICO_FLASH_BANK_SIZE);
103 if (offset >= PICO_FLASH_BANK_SIZE) return;
104
105 assert((offset + size) <= PICO_FLASH_BANK_SIZE);
106 if ((offset + size) > PICO_FLASH_BANK_SIZE) return;
107
108 if (size == 0) return;
109
110 // calc bank start position
111 const uint32_t bank_start_pos = pico_flash_bank_get_storage_offset_func() + (PICO_FLASH_BANK_SIZE * bank);
112
113 // Calculate first and last page in the bank
114 const uint32_t first_page = offset / FLASH_PAGE_SIZE;
115 const uint32_t last_page = (offset + size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
116
117 // Now we only care about the offset in the first page
118 offset %= FLASH_PAGE_SIZE;
119
120 // Amount of data we've copied
121 uint32_t data_pos = 0;
122 uint32_t size_left = size;
123
124 // Write all the pages required
125 for(uint32_t page = first_page; page < last_page; page++) {
126 uint8_t page_data[FLASH_PAGE_SIZE];
127
128 assert(data_pos < size && size_left <= size);
129
130 // Copy data we're not going to overwrite in the first page
131 if (page == first_page && offset > 0) {
132 memcpy(page_data,
133 (void *)(XIP_BASE + bank_start_pos + (page * FLASH_PAGE_SIZE)),
134 offset);
135 }
136
137 // Copy the data we're not going to overwrite in the last page
138 if (page == last_page - 1 && (offset + size_left) < FLASH_PAGE_SIZE) {
139 memcpy(page_data + offset + size_left,
140 (void *)(XIP_BASE + bank_start_pos + (page * FLASH_PAGE_SIZE) + offset + size_left),
141 FLASH_PAGE_SIZE - offset - size_left);
142 }
143
144 // Now copy the new data into the page
145 const uint32_t size_to_copy = MIN(size_left, FLASH_PAGE_SIZE - offset);
146 memcpy(page_data + offset, data + data_pos, size_to_copy);
147
148 data_pos += size_to_copy;
149 size_left -= size_to_copy;
150
151 // zero offset for the following pages
152 offset = 0;
153
154 // Now program the entire page
155 mutation_operation_t mop = {
156 .op_is_erase = false,
157 .p0 = bank_start_pos + (page * FLASH_PAGE_SIZE),
158 .p1 = (uintptr_t)page_data
159 };
160 // todo choice of timeout and check return code... currently we have no way to return an error
161 // to the caller anyway. flash_safe_execute asserts by default on problem other than timeout,
162 // so that's fine for now, and UINT32_MAX is a timeout of 49 days which seems long enough
163 flash_safe_execute(pico_flash_bank_perform_flash_mutation_operation, &mop, UINT32_MAX);
164 }
165 }
166
167 static const hal_flash_bank_t pico_flash_bank_instance_obj = {
168 /* uint32_t (*get_size)(..) */ &pico_flash_bank_get_size,
169 /* uint32_t (*get_alignment)(..); */ &pico_flash_bank_get_alignment,
170 /* void (*erase)(..); */ &pico_flash_bank_erase,
171 /* void (*read)(..); */ &pico_flash_bank_read,
172 /* void (*write)(..); */ &pico_flash_bank_write,
173 };
174
pico_flash_bank_instance(void)175 const hal_flash_bank_t *pico_flash_bank_instance(void) {
176 return &pico_flash_bank_instance_obj;
177 }
178