1
1
//
2
- // Implementation of Pico stage 2 boot loader. This code is for the Winbond W25Q080
3
- // (as found in the Pico) from the official Pico SDK.
2
+ // Implementation of RP2040 stage 2 boot loader. This code is derived from the
3
+ // Winbond W25Q080 implementation (as found in the Pico) in the official Pico SDK.
4
4
//
5
5
// This implementation has been made 'stand-alone' by including necessary code /
6
6
// symbols from the included files in the reference implementation directly into
7
- // the source. Care has been taken to preserve ordering and it has been verified
8
- // the generated binary is byte-for-byte identical to the reference code binary.
7
+ // the source. It has also been modified to include the conditional logic from
8
+ // the CircuitPython implementation that supports additional flash chips. The
9
+ // CiruitPython source is here:
10
+ // https://github.com/adafruit/circuitpython/blob/main/ports/raspberrypi/stage2.c.jinja
11
+ //
12
+ // This file cannot be assembled directly, instead assemble the board-specific file
13
+ // (such as pico-boot-stage2.S) which defines the parameters specific to the flash
14
+ // chip included on that board.
15
+ //
16
+ // Care has been taken to preserve ordering and it has been verified the generated
17
+ // binary is byte-for-byte identical to the reference code binary when assembled for
18
+ // the Pico.
9
19
//
10
20
// Note: the stage 2 boot loader must be 256 bytes in length and have a checksum
11
21
// present. In TinyGo, the linker script is responsible for allocating 256 bytes
19
29
// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/boot_stage2/boot2_w25q080.S
20
30
//
21
31
22
- // Board Parameters
23
- #define PICO_FLASH_SPI_CLKDIV 2
24
-
25
-
26
32
27
33
// ----------------------------------------------------------------------------
28
34
// Second stage boot code
59
65
#define CMD_WRITE_ENABLE 0x06
60
66
#define CMD_READ_STATUS 0x05
61
67
#define CMD_READ_STATUS2 0x35
62
- #define CMD_WRITE_STATUS 0x01
68
+ #define CMD_WRITE_STATUS1 0x01
69
+ #define CMD_WRITE_STATUS2 0x31
63
70
#define SREG_DATA 0x02 // Enable quad-SPI mode
64
71
65
72
#define XIP_BASE 0x10000000
123
130
// The bootrom is very conservative with SPI frequency, but here we should be
124
131
// as aggressive as possible.
125
132
126
- #ifndef PICO_FLASH_SPI_CLKDIV
127
- #define PICO_FLASH_SPI_CLKDIV 4
128
- #endif
133
+ #define PICO_FLASH_SPI_CLKDIV BOARD_PICO_FLASH_SPI_CLKDIV
129
134
#if PICO_FLASH_SPI_CLKDIV & 1
130
135
#error PICO_FLASH_SPI_CLKDIV must be even
131
136
#endif
132
137
138
+ #if BOARD_QUAD_OK ==1
133
139
// Define interface width: single/dual/quad IO
134
- #define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
140
+ #define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_QUAD
141
+ #define TRANSACTION_TYPE SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A
142
+ // Note that the INST_L field is used to select what XIP data gets pushed into
143
+ // the TX FIFO:
144
+ // INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
145
+ // Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
146
+ #define INSTRUCTION_LENGTH SSI_SPI_CTRLR0_INST_L_VALUE_NONE
147
+ #define READ_INSTRUCTION MODE_CONTINUOUS_READ
148
+ #define ADDR_L 8 // 6 for address, 2 for mode
149
+ #else
150
+ #define FRAME_FORMAT SSI_CTRLR0_SPI_FRF_VALUE_STD
151
+ #define TRANSACTION_TYPE SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_1C1A
152
+ #define INSTRUCTION_LENGTH SSI_SPI_CTRLR0_INST_L_VALUE_8B
153
+ #define READ_INSTRUCTION BOARD_CMD_READ
154
+ #define ADDR_L 6 // * 4 = 24
155
+ #endif
135
156
136
- // For W25Q080 this is the "Read data fast quad IO" instruction:
137
- #define CMD_READ 0xeb
157
+ // The flash-chip specific read isntruction
158
+ #define CMD_READ BOARD_CMD_READ
138
159
139
160
// "Mode bits" are 8 special bits sent immediately after
140
161
// the address bits in a "Read Data Fast Quad I/O" command sequence.
141
162
// On W25Q080, the four LSBs are don't care, and if MSBs == 0xa, the
142
163
// next read does not require the 0xeb instruction prefix.
143
164
#define MODE_CONTINUOUS_READ 0xa0
144
165
145
- // The number of address + mode bits, divided by 4 (always 4, not function of
146
- // interface width).
147
- #define ADDR_L 8
148
-
149
166
// How many clocks of Hi-Z following the mode bits. For W25Q080, 4 dummy cycles
150
167
// are required.
151
- #define WAIT_CYCLES 4
168
+ #define WAIT_CYCLES BOARD_WAIT_CYCLES
169
+
152
170
153
171
// If defined, we will read status reg, compare to SREG_DATA, and overwrite
154
172
// with our value if the SR doesn't match.
@@ -184,10 +202,14 @@ _stage2_boot:
184
202
ldr r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
185
203
movs r1, #PADS_QSPI_GPIO_QSPI_SD0_SCHMITT_BITS
186
204
bics r0, r1
205
+ #if BOARD_QUAD_OK ==1
187
206
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD0_OFFSET]
207
+ #endif
188
208
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD1_OFFSET]
209
+ #if BOARD_QUAD_OK ==1
189
210
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD2_OFFSET]
190
211
str r0, [r3, #PADS_QSPI_GPIO_QSPI_SD3_OFFSET]
212
+ #endif
191
213
192
214
ldr r3, =XIP_SSI_BASE
193
215
@@ -225,9 +247,15 @@ program_sregs:
225
247
str r1, [r3, #SSI_SSIENR_OFFSET]
226
248
227
249
// Check whether SR needs updating
250
+ #if BOARD_QUAD_OK ==1
251
+ # if BOARD_QUAD_ENABLE_STATUS_BYTE ==1
252
+ movs r0, #CMD_READ_STATUS1
253
+ # elif BOARD_QUAD_ENABLE_STATUS_BYTE ==2
228
254
movs r0, #CMD_READ_STATUS2
255
+ # endif
256
+
229
257
bl read_flash_sreg
230
- movs r2, #SREG_DATA
258
+ movs r2, #BOARD_QUAD_ENABLE_BIT_MASK
231
259
cmp r0, r2
232
260
beq skip_sreg_programming
233
261
@@ -240,24 +268,45 @@ program_sregs:
240
268
ldr r1, [r3, #SSI_DR0_OFFSET]
241
269
242
270
// Send status write command followed by data bytes
243
- movs r1, #CMD_WRITE_STATUS
271
+ # if BOARD_SPLIT_STATUS_WRITE ==1
272
+ # if BOARD_QUAD_ENABLE_STATUS_BYTE ==1
273
+ movs r1, #CMD_WRITE_STATUS1
274
+ # elif BOARD_QUAD_ENABLE_STATUS_BYTE ==2
275
+ movs r1, #CMD_WRITE_STATUS2
276
+ # endif
277
+ str r1, [r3, #SSI_DR0_OFFSET]
278
+ str r2, [r3, #SSI_DR0_OFFSET]
279
+
280
+ bl wait_ssi_ready
281
+ //ldr r1, [r3, #SSI_DR0_OFFSET]
282
+ ldr r1, [r3, #SSI_DR0_OFFSET]
283
+ ldr r1, [r3, #SSI_DR0_OFFSET]
284
+
285
+ # else
286
+ movs r1, #CMD_WRITE_STATUS1
244
287
str r1, [r3, #SSI_DR0_OFFSET]
288
+ # if BOARD_QUAD_ENABLE_STATUS_BYTE ==2
245
289
movs r0, #0
246
290
str r0, [r3, #SSI_DR0_OFFSET]
291
+ # endif
247
292
str r2, [r3, #SSI_DR0_OFFSET]
248
293
249
294
bl wait_ssi_ready
250
295
ldr r1, [r3, #SSI_DR0_OFFSET]
251
296
ldr r1, [r3, #SSI_DR0_OFFSET]
297
+ # if BOARD_QUAD_ENABLE_STATUS_BYTE ==2
252
298
ldr r1, [r3, #SSI_DR0_OFFSET]
299
+ # endif
253
300
301
+ # endif
254
302
// Poll status register for write completion
255
303
1:
256
304
movs r0, #CMD_READ_STATUS
257
305
bl read_flash_sreg
258
306
movs r1, #1
259
307
tst r0, r1
260
308
bne 1b
309
+ #endif
261
310
262
311
skip_sreg_programming:
263
312
@@ -286,6 +335,7 @@ dummy_read:
286
335
movs r1, #0x0 // NDF=0 (single 32b read)
287
336
str r1, [r3, #SSI_CTRLR1_OFFSET]
288
337
338
+ #if BOARD_QUAD_OK ==1
289
339
#define SPI_CTRLR0_ENTER_XIP \
290
340
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Address + mode bits */ \
291
341
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
@@ -315,20 +365,21 @@ dummy_read:
315
365
316
366
movs r1, #0
317
367
str r1, [r3, #SSI_SSIENR_OFFSET] // Disable SSI (and clear FIFO) to allow further config
368
+ #endif
318
369
319
370
// Note that the INST_L field is used to select what XIP data gets pushed into
320
371
// the TX FIFO:
321
372
// INST_L_0_BITS {ADDR[23:0],XIP_CMD[7:0]} Load "mode bits" into XIP_CMD
322
373
// Anything else {XIP_CMD[7:0],ADDR[23:0]} Load SPI command into XIP_CMD
323
374
configure_ssi:
324
375
#define SPI_CTRLR0_XIP \
325
- (MODE_CONTINUOUS_READ /* Mode bits to keep flash in continuous read mode */ \
376
+ (READ_INSTRUCTION /* Mode bits to keep flash in continuous read mode */ \
326
377
<< SSI_SPI_CTRLR0_XIP_CMD_LSB) | \
327
378
(ADDR_L << SSI_SPI_CTRLR0_ADDR_L_LSB) | /* Total number of address + mode bits */ \
328
379
(WAIT_CYCLES << SSI_SPI_CTRLR0_WAIT_CYCLES_LSB) | /* Hi-Z dummy clocks following address + mode */ \
329
- (SSI_SPI_CTRLR0_INST_L_VALUE_NONE /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
380
+ (INSTRUCTION_LENGTH /* Do not send a command, instead send XIP_CMD as mode bits after address */ \
330
381
<< SSI_SPI_CTRLR0_INST_L_LSB) | \
331
- (SSI_SPI_CTRLR0_TRANS_TYPE_VALUE_2C2A /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
382
+ (TRANSACTION_TYPE /* Send Address in Quad I/O mode (and Command but that is zero bits long) */ \
332
383
<< SSI_SPI_CTRLR0_TRANS_TYPE_LSB)
333
384
334
385
ldr r1, =(SPI_CTRLR0_XIP)
0 commit comments