-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathflash.h
More file actions
285 lines (257 loc) · 11.7 KB
/
flash.h
File metadata and controls
285 lines (257 loc) · 11.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _HARDWARE_FLASH_H
#define _HARDWARE_FLASH_H
#include "pico.h"
/** \file flash.h
* \defgroup hardware_flash hardware_flash
*
* \brief Low level flash programming and erase API
*
* Note these functions are *unsafe* if you are using both cores, and the other
* is executing from flash concurrently with the operation. In this case, you
* must perform your own synchronisation to make sure that no XIP accesses take
* place during flash programming. One option is to use the
* \ref multicore_lockout functions.
*
* Likewise they are *unsafe* if you have interrupt handlers or an interrupt
* vector table in flash, so you must disable interrupts before calling in
* this case.
*
* If PICO_NO_FLASH=1 is not defined (i.e. if the program is built to run from
* flash) then these functions will make a static copy of the second stage
* bootloader in SRAM, and use this to reenter execute-in-place mode after
* programming or erasing flash, so that they can safely be called from
* flash-resident code.
*
* \subsection flash_example Example
* \include flash_program.c
*/
// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_FLASH, Enable/disable assertions in the hardware_flash module, type=bool, default=0, group=hardware_flash
#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_FLASH
#ifdef PARAM_ASSERTIONS_ENABLED_FLASH // backwards compatibility with SDK < 2.0.0
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_FLASH PARAM_ASSERTIONS_ENABLED_FLASH
#else
#define PARAM_ASSERTIONS_ENABLED_HARDWARE_FLASH 0
#endif
#endif
#define FLASH_PAGE_SIZE (1u << 8)
#define FLASH_SECTOR_SIZE (1u << 12)
#define FLASH_BLOCK_SIZE (1u << 16)
#ifndef FLASH_UNIQUE_ID_SIZE_BYTES
#define FLASH_UNIQUE_ID_SIZE_BYTES 8
#endif
// PICO_CONFIG: PICO_FLASH_SIZE_BYTES, size of primary flash in bytes, type=int, default=Usually provided via board header, group=hardware_flash
// PICO_CONFIG: PICO_INCLUDE_FLASH_FUNCTIONS, Force inclusion of flash functions in PICO_NO_FLASH binaries. Has no effect in flash binaries, type=bool, default=0, group=hardware_flash
#ifndef PICO_INCLUDE_FLASH_FUNCTIONS
#define PICO_INCLUDE_FLASH_FUNCTIONS 0
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*! \brief Initialise QSPI interface and external QSPI devices for execute-in-place
* \ingroup hardware_flash
*
* This function performs the same first-time flash setup that would normally occur over the course
* of the bootrom locating a flash binary and booting it, and that flash binary executing the SDK
* crt0. Specifically:
*
* * Initialise QSPI pads to their default states, and (non-RP2040) disable pad isolation latches
* * Issue a hardcoded sequence to attached QSPI devices to return them to a serial command state
* * Flush the XIP cache
* * Configure the QSPI interface for low-speed 03h reads
* * If this is not a PICO_NO_FLASH=1 binary:
* * (RP2040) load a boot2 stage from the first 256 bytes of RAM and execute it
* * (non-RP2040) execute an XIP setup function stored in boot RAM by either the bootrom or by crt0
*
* This is mostly useful for initialising flash on a PICO_NO_FLASH=1 binary. (In spite of the name,
* this binary type really means "preloaded to RAM" and there may still be a flash device.)
*
* This function does not preserve the QSPI interface state or pad state. This is in contrast to
* most other functions in this library, which preserve at least the QSPI pad state. However, on
* RP2350 it does preserve the QMI window 1 configuration if you have not opted into bootrom CS1
* support via FLASH_DEVINFO.
*/
void flash_start_xip(void);
/*! \brief Erase areas of flash
* \ingroup hardware_flash
*
* \param flash_offs Offset into flash, in bytes, to start the erase. Must be aligned to a 4096-byte flash sector.
* \param count Number of bytes to be erased. Must be a multiple of 4096 bytes (one sector).
*
* @note Erasing a flash sector sets all the bits in all the pages in that sector to one.
* You can then "program" flash pages in the sector to turn some of the bits to zero.
* Once a bit is set to zero it can only be changed back to one by erasing the whole sector again.
*/
void flash_range_erase(uint32_t flash_offs, size_t count);
/*! \brief Program flash
* \ingroup hardware_flash
*
* \param flash_offs Flash address of the first byte to be programmed. Must be aligned to a 256-byte flash page.
* \param data Pointer to the data to program into flash
* \param count Number of bytes to program. Must be a multiple of 256 bytes (one page).
*
* @note: Programming a flash page effectively changes some of the bits from one to zero.
* The only way to change a zero bit back to one is to "erase" the whole sector that the page resides in.
* So you may need to make sure you have called flash_range_erase before calling flash_range_program.
*/
void flash_range_program(uint32_t flash_offs, const uint8_t *data, size_t count);
/*! \brief Get flash unique 64 bit identifier
* \ingroup hardware_flash
*
* Use a standard 4Bh RUID instruction to retrieve the 64 bit unique
* identifier from a flash device attached to the QSPI interface. Since there
* is a 1:1 association between the MCU and this flash, this also serves as a
* unique identifier for the board.
*
* \param id_out Pointer to an 8-byte buffer to which the ID will be written
*/
void flash_get_unique_id(uint8_t *id_out);
/*! \brief Execute bidirectional flash command
* \ingroup hardware_flash
*
* Low-level function to execute a serial command on a flash device attached
* to the QSPI interface. Bytes are simultaneously transmitted and received
* from txbuf and to rxbuf. Therefore, both buffers must be the same length,
* count, which is the length of the overall transaction. This is useful for
* reading metadata from the flash chip, such as device ID or SFDP
* parameters.
*
* The XIP cache is flushed following each command, in case flash state
* has been modified. Like other hardware_flash functions, the flash is not
* accessible for execute-in-place transfers whilst the command is in
* progress, so entering a flash-resident interrupt handler or executing flash
* code on the second core concurrently will be fatal. To avoid these pitfalls
* it is recommended that this function only be used to extract flash metadata
* during startup, before the main application begins to run: see the
* implementation of pico_get_unique_id() for an example of this.
*
* \param txbuf Pointer to a byte buffer which will be transmitted to the flash
* \param rxbuf Pointer to a byte buffer where data received from the flash will be written. txbuf and rxbuf may be the same buffer.
* \param count Length in bytes of txbuf and of rxbuf
*/
void flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count);
void flash_flush_cache(void);
#if !PICO_RP2040
typedef enum {
FLASH_DEVINFO_SIZE_NONE = 0x0,
FLASH_DEVINFO_SIZE_8K = 0x1,
FLASH_DEVINFO_SIZE_16K = 0x2,
FLASH_DEVINFO_SIZE_32K = 0x3,
FLASH_DEVINFO_SIZE_64K = 0x4,
FLASH_DEVINFO_SIZE_128K = 0x5,
FLASH_DEVINFO_SIZE_256K = 0x6,
FLASH_DEVINFO_SIZE_512K = 0x7,
FLASH_DEVINFO_SIZE_1M = 0x8,
FLASH_DEVINFO_SIZE_2M = 0x9,
FLASH_DEVINFO_SIZE_4M = 0xa,
FLASH_DEVINFO_SIZE_8M = 0xb,
FLASH_DEVINFO_SIZE_16M = 0xc,
FLASH_DEVINFO_SIZE_MAX = 0xc
} flash_devinfo_size_t;
/*! \brief Convert a flash/PSRAM size enum to an integer size in bytes
* \ingroup hardware_flash
*/
static inline uint32_t flash_devinfo_size_to_bytes(flash_devinfo_size_t size) {
if (size == FLASH_DEVINFO_SIZE_NONE) {
return 0;
} else {
return 4096u << (uint)size;
}
}
/*! \brief Convert an integer flash/PSRAM size in bytes to a size enum, as
! stored in OTP and used by the ROM.
* \ingroup hardware_flash
*/
static inline flash_devinfo_size_t flash_devinfo_bytes_to_size(uint32_t bytes) {
// Must be zero or a power of two
valid_params_if(HARDWARE_FLASH, (bytes & (bytes - 1)) == 0u);
uint sectors = bytes / 4096u;
if (sectors <= 1u) {
return FLASH_DEVINFO_SIZE_NONE;
} else {
return (flash_devinfo_size_t) __builtin_ctz(sectors);
}
}
/*! \brief Get the size of the QSPI device attached to chip select cs, according to FLASH_DEVINFO
* \ingroup hardware_flash
*
* \param cs Chip select index: 0 is QMI chip select 0 (QSPI CS pin), 1 is QMI chip select 1.
*
* The bootrom reads the FLASH_DEVINFO OTP data entry from OTP into boot RAM during startup. This
* contains basic information about the flash device which can be queried without communicating
* with the external device.(There are several methods to determine the size of a QSPI device over
* QSPI, but none are universally supported.)
*
* Since the FLASH_DEVINFO information is stored in boot RAM at runtime, it can be updated. Updates
* made in this way persist until the next reboot. The ROM uses this device information to control
* some low-level flash API behaviour, such as issuing an XIP exit sequence to CS 1 if its size is
* nonzero.
*
* If the macro PICO_FLASH_SIZE_BYTES is specified, this overrides the value for chip select 0. This
* can be specified in a board header if a board is always equipped with the same size of flash.
*/
flash_devinfo_size_t flash_devinfo_get_cs_size(uint cs);
/*! \brief Update the size of the QSPI device attached to chip select cs in the runtime copy
* of FLASH_DEVINFO.
*
* \ingroup hardware_flash
*
* \param cs Chip select index: 0 is QMI chip select 0 (QSPI CS pin), 1 is QMI chip select 1.
*
* \param size The size of the attached device, or FLASH_DEVINFO_SIZE_NONE if there is none on this
* chip select.
*
* The bootrom maintains a copy in boot RAM of the FLASH_DEVINFO information read from OTP during
* startup. This function updates that copy to reflect runtime information about the sizes of
* attached QSPI devices.
*
* This controls the behaviour of some ROM flash APIs, such as bounds checking addresses for
* erase/programming in the checked_flash_op() API, or issuing an XIP exit sequence to CS 1 in
* flash_exit_xip() if the size is nonzero.
*/
void flash_devinfo_set_cs_size(uint cs, flash_devinfo_size_t size);
/*! \brief Check whether all attached devices support D8h block erase with 64k size, according to
* FLASH_DEVINFO.
*
* \ingroup hardware_flash
*
* This controls whether checked_flash_op() ROM API uses D8h 64k block erase where possible, for
* faster erase times. If not, this ROM API always uses 20h 4k sector erase.
*
* The bootrom loads this flag from the OTP FLASH_DEVINFO data entry during startup, and stores it
* in boot RAM. You can update the boot RAM copy based on runtime knowledge of the attached QSPI
* devices.
*/
bool flash_devinfo_get_d8h_erase_supported(void);
/*! \brief Specify whether all attached devices support D8h block erase with 64k size, in the
* runtime copy of FLASH_DEVINFO
*
* \ingroup hardware_flash
*
* This function updates the boot RAM copy of OTP FLASH_DEVINFO. The flag passed here is visible to
* ROM APIs, and is also returned in the next call to flash_devinfo_get_d8h_erase_supported()
*/
void flash_devinfo_set_d8h_erase_supported(bool supported);
/*! \brief Check the GPIO allocated for each chip select, according to FLASH_DEVINFO
* \ingroup hardware_flash
*
* \param cs Chip select index (only the value 1 is supported on RP2350)
*/
uint flash_devinfo_get_cs_gpio(uint cs);
/*! \brief Update the GPIO allocated for each chip select in the runtime copy of FLASH_DEVINFO
* \ingroup hardware_flash
*
* \param cs Chip select index (only the value 1 is supported on RP2350)
*
* \param gpio GPIO index (must be less than NUM_BANK0_GPIOS)
*/
void flash_devinfo_set_cs_gpio(uint cs, uint gpio);
#endif // !PICO_RP2040
#ifdef __cplusplus
}
#endif
#endif