Software APIs
spi_device.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/silicon_creator/lib/drivers/spi_device.h"
6 
7 #include "dt/dt_spi_device.h"
11 #include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
12 #include "sw/device/silicon_creator/lib/error.h"
13 
14 #include "flash_ctrl_regs.h"
15 #include "spi_device_regs.h"
16 
17 static const dt_spi_device_t kSpiDeviceDt = kDtSpiDevice;
18 
19 /**
20  * Base address of the spi_device registers.
21  */
22 static inline uint32_t spi_device_reg_base(void) {
23  return dt_spi_device_primary_reg_block(kSpiDeviceDt);
24 }
25 
26 enum {
27  /**
28  * Start address of the SFDP space in spi_device buffer.
29  */
30  kSfdpAreaStartOff =
31  SPI_DEVICE_EGRESS_BUFFER_REG_OFFSET + kSpiDeviceSfdpAreaOffset,
32  /**
33  * End address (exclusive) of the SFDP space in spi_device buffer.
34  */
35  kSfdpAreaEndOff = SPI_DEVICE_EGRESS_BUFFER_REG_OFFSET +
36  kSpiDeviceSfdpAreaOffset + kSpiDeviceSfdpAreaNumBytes,
37  /**
38  * Flash data partition size in bits.
39  */
40  kFlashBitCount =
41  FLASH_CTRL_PARAM_REG_NUM_BANKS * FLASH_CTRL_PARAM_BYTES_PER_BANK * 8,
42  /**
43  * 32-bit SFDP signature that indicates the presence of a SFDP table
44  * (JESD216F 6.2.1).
45  */
46  kSfdpSignature = 0x50444653,
47  /**
48  * Number of parameter headers in the SFDP data structure (JESD216F 6.2.2).
49  *
50  * This number is zero-based. OpenTitan currently only has a single parameter
51  * header for the Basic Flash Parameters Table (BFPT).
52  */
53  kSfdpParamCount = 0,
54  /**
55  * SFDP major revision number (JESD216F 6.2.2).
56  */
57  kSfdpMajorRevision = 0x01,
58  /**
59  * SFDP minor revision number (JESD216F 6.2.2).
60  */
61  kSfdpMinorRevision = 0x0a,
62  /**
63  * 3-byte addressing for SFDP_READ command, 8 wait states (JESD216F 6.2.3).
64  */
65  kSfdpAccessProtocol = 0xff,
66  /**
67  * BFPT major revision number (JESD216F 6.4.1).
68  */
69  kBfptMajorRevision = 0x01,
70  /**
71  * BFPT minor revision number (JESD216F 6.4.1).
72  */
73  kBfptMinorRevision = 0x07,
74  /**
75  * LSB of BFPT's parameter ID (JESD216F 6.4.1).
76  */
77  kBfptParamIdLsb = 0x00,
78  /**
79  * MSB of BFPT's parameter ID (JESD216F 6.4.2).
80  */
81  kBfptParamIdMsb = 0xff,
82  /**
83  * Offset of the Basic Flash Parameter Table (BFPT) in the SFDP table.
84  */
85  kBfptTablePointer = offsetof(spi_device_sfdp_table_t, bfpt),
86  /**
87  * Value used for BFPT fields that are not supported.
88  *
89  * Note: A handful of BFPT fields, e.g. Msb of the 14th word of BFPT, use 1
90  * instead. Such fields should be defined according to JESD216F instead of
91  * using this value.
92  */
93  kBfptNotSupported = 0,
94 };
95 
96 static_assert(kBfptTablePointer % sizeof(uint32_t) == 0,
97  "BFPT must be word-aligned");
98 
99 /**
100  * Computes the width of a field in a Basic Flash Parameters Table (BFPT) word.
101  *
102  * @param upper Upper (start) bit of the field (inclusive).
103  * @param lower Lower (end) bit of the field (inclusive).
104  */
105 #define BFPT_FIELD_WIDTH(upper, lower) ((upper) - (lower) + 1)
106 
107 /**
108  * Computes the mask for a field in a BFPT word.
109  *
110  * @param upper Upper (start) bit of the field (inclusive).
111  * @param lower Lower (end) bit of the field (inclusive).
112  */
113 #define BFPT_FIELD_MASK(upper, lower) \
114  (((UINT64_C(1) << BFPT_FIELD_WIDTH(upper, lower)) - 1) << (lower))
115 
116 /**
117  * Computes the value of a field in a BFPT word.
118  *
119  * Bits outside the field are left as 1s. This macro is intended for expanding a
120  * list of fields, e.g. `BFPT_WORD_1`, to compute the value of a BFPT word using
121  * bitwise AND.
122  *
123  * @param upper Upper (start) bit of the field (inclusive).
124  * @param lower Lower (end) bit of the field (inclusive).
125  * @param value Value of the field.
126  */
127 #define BFPT_FIELD_VALUE(upper, lower, value) \
128  ((uint32_t)~BFPT_FIELD_MASK(upper, lower) | \
129  (BFPT_FIELD_MASK(upper, lower) & ((uint32_t)(value) << (uint32_t)(lower))))
130 
131 // Note: Words below are numbered starting from 1 to match JESD216F. Some fields
132 // that are not supported by OpenTitan are merged for the sake of conciseness.
133 // Unused/reserved fields that should be set to all 1s are ommitted due to the
134 // definition of `BFPT_FIELD_VALUE()` above. See JESD216F for more details.
135 
136 // clang-format off
137 /**
138  * BFPT 1st Word
139  * -------------
140  * [31:23]: Unused
141  * [22:19]: (1S-1S-4S) (1S-4S-4S) (1S-2S-2S) DTR Clock (not supported: 0x0)
142  * [18:17]: Address bytes (3-byte only addressing: 0x0)
143  * [16:16]: (1S-1S-2S) (not supported: 0x0)
144  * [15: 8]: 4 KiB erase instruction (0x20)
145  * [ 7: 5]: Unused
146  * [ 4: 4]: Write enable instruction (use 0x06 for WREN: 0x1)
147  * [ 3: 3]: Volatile block protect bits (solely volatile: 0x1)
148  * [ 2: 2]: Write granularity (buffer >= 64 B: 0x1)
149  * [ 1: 0]: Block/sector erase sizes (uniform 4 KiB erase: 0x1)
150  */
151 #define BFPT_WORD_1(X) \
152  X(22, 19, kBfptNotSupported) & \
153  X(18, 17, 0x0) & \
154  X(16, 16, kBfptNotSupported) & \
155  X(15, 8, kSpiDeviceOpcodeSectorErase) & \
156  X( 4, 4, 0x1) & \
157  X( 3, 3, 0x1) & \
158  X( 2, 2, 0x1) & \
159  X( 1, 0, 0x1)
160 
161 /**
162  * BFPT 2nd Word
163  * -------------
164  * [31:31]: Density greater than 2 Gib (0x0)
165  * [30: 0]: Flash memory density in bits, zero-based (0x7fffff)
166  */
167 #define BFPT_WORD_2(X) \
168  X(31, 31, 0x0) & \
169  X(30, 0, kFlashBitCount - 1)
170 
171 /**
172  * BFPT 3rd Word
173  * -------------
174  * [31: 0]: Fast read (1S-4S-4S) (1S-1S-4S) (not supported, 0x0)
175  */
176 #define BFPT_WORD_3(X) \
177  X(31, 0, kBfptNotSupported)
178 
179 /**
180  * BFPT 4th Word
181  * -------------
182  * [31: 0]: Fast read (1S-1S-2S) (1S-2S-2S) (not supported, 0x0)
183  */
184 #define BFPT_WORD_4(X) \
185  X(31, 0, kBfptNotSupported)
186 
187 /**
188  * BFPT 5th Word
189  * -------------
190  * [31: 5]: Reserved
191  * [ 4: 4]: Fast read (4S-4S-4S) support (not supported, 0x0)
192  * [ 3: 1]: Reserved
193  * [ 0: 0]: Fast read (2S-2S-2S) support (not supported, 0x0)
194  */
195 #define BFPT_WORD_5(X) \
196  X( 4, 4, kBfptNotSupported) & \
197  X( 0, 0, kBfptNotSupported)
198 
199 /**
200  * BFPT 6th Word
201  * -------------
202  * [31:16]: Fast read (2S-2S-2S) (not supported, 0x0)
203  * [15: 0]: Reserved
204  */
205 #define BFPT_WORD_6(X) \
206  X(31, 16, kBfptNotSupported)
207 
208 /**
209  * BFPT 7th Word
210  * -------------
211  * [31:16]: Fast read (4S-4S-4S) (not supported, 0x0)
212  * [15: 0]: Reserved
213  */
214 #define BFPT_WORD_7(X) \
215  X(31, 16, kBfptNotSupported)
216 
217 /**
218  * BFPT 8th Word
219  * -------------
220  * [31:16]: Erase type 2 instruction and size (not supported, 0x0)
221  * [15: 8]: Erase type 1 instruction (0x20)
222  * [ 7: 0]: Erase type 1 size (4 KiB, 2^N bytes, N = 0x0c)
223  */
224 #define BFPT_WORD_8(X) \
225  X(31, 16, kBfptNotSupported) & \
226  X(15, 8, kSpiDeviceOpcodeSectorErase) & \
227  X( 7, 0, 0x0c)
228 
229 /**
230  * BFPT 9th Word
231  * -------------
232  * [31: 0]: Erase type 4 and 3 (not supported, 0x0)
233  */
234 #define BFPT_WORD_9(X) \
235  X(31, 0, kBfptNotSupported)
236 
237 /**
238  * BFPT 10th Word
239  * --------------
240  * [31:11]: Erase 4,3,2 typical time (not supported, 0x0)
241  * [10: 9]: Erase type 1 time unit (16 ms, 0x1)
242  * [ 8: 4]: Erase type 1 time count, zero-based (0x8)
243  * formula: (count + 1) * unit
244  * (8 + 1) * 16 ms = 144 ms
245  * [ 3: 0]: Max erase time multiplier, zero-based (0x6)
246  * formula: 2 * (multiplier + 1) * erase_time
247  */
248 #define BFPT_WORD_10(X) \
249  X(31, 11, kBfptNotSupported) & \
250  X(10, 9, 0x1) & \
251  X( 8, 4, 0x8) & \
252  X( 3, 0, 0x0)
253 
254 /**
255  * BFPT 11th Word
256  * --------------
257  * [31:31]: Reserved
258  * [30:29]: Chip erase time units (16 ms, 0x0)
259  * [28:24]: Chip erase time count, zero-based (0xb)
260  * formula: (count + 1) * unit
261  * (11 + 1) * 16 ms = 192 ms
262  * [23:23]: Additional byte program time units (8 us, 0x1)
263  * [22:19]: Additional byte program time count, zero-based (0x5)
264  * formula: (count + 1) * unit
265  * (5 + 1) * 8 us = 48 us
266  * [18:18]: First byte program time unit (8 us, 0x1)
267  * [17:14]: First byte program time count, zero-based (0x5)
268  * formula: (count + 1) * unit
269  * (5 + 1) * 8 us = 48 us
270  * [13:13]: Page program time unit (64 us, 0x1)
271  * [12: 8]: Page program time count, zero-based (0xb)
272  * formula: (count + 1) * unit
273  * (11 + 1) * 64 us = 768 us
274  * [ 7: 4]: Page size, 2^N (0x8)
275  * [ 3: 0]: Max program time multiplier, zero-based (0x0)
276  * formula: 2 * (multiplier + 1) * program_time
277  */
278 #define BFPT_WORD_11(X) \
279  X(30, 29, 0x0) & \
280  X(28, 24, 0xb) & \
281  X(23, 23, 0x1) & \
282  X(22, 19, 0x5) & \
283  X(18, 18, 0x1) & \
284  X(17, 14, 0x5) & \
285  X(13, 13, 0x1) & \
286  X(12, 8, 0xb) & \
287  X( 7, 4, 0x8) & \
288  X( 3, 0, 0x0)
289 
290 /**
291  * BFPT 12th Word
292  * --------------
293  * [31:31]: Suspend/Resume supported (not supported, 0x1)
294  * [30: 9]: Suspend/Resume latencies for erase & program (not supported)
295  * [ 8: 8]: Reserved
296  * [ 7: 0]: Prohibited ops during suspend (not supported, 0x0)
297  */
298 #define BFPT_WORD_12(X) \
299  X(31, 31, 0x1) & \
300  X(30, 9, kBfptNotSupported) & \
301  X( 7, 0, kBfptNotSupported)
302 
303 /**
304  * BFPT 13th Word
305  * --------------
306  * [31: 0]: Erase/program suspend/resume instructions (not supported, 0x0)
307  */
308 #define BFPT_WORD_13(X) \
309  X(31, 0, kBfptNotSupported)
310 
311 /**
312  * BFPT 14th Word
313  * --------------
314  * [31:31]: Deep powerdown support (not supported, 0x1)
315  * [30: 8]: Deep powerdown instructions and delay (not supported, 0x0)
316  * [ 7: 2]: Busy polling (bit 0 using 0x05 instruction, 0x1)
317  * [ 1: 0]: Reserved
318  */
319 #define BFPT_WORD_14(X) \
320  X(31, 31, 0x1) & \
321  X(30, 8, kBfptNotSupported) & \
322  X( 7, 2, 0x1)
323 
324 /**
325  * BFPT 15th Word
326  * --------------
327  * [31:24]: Reserved
328  * [23: 0]: Hold, QE, (4S-4S-4S), 0-4-4 (not supported, 0x0)
329  */
330 #define BFPT_WORD_15(X) \
331  X(23, 0, kBfptNotSupported)
332 
333 /**
334  * BFPT 16th Word
335  * --------------
336  * [31:14]: 4-Byte addressing (not supported, 0x0)
337  * [13: 8]: Soft-reset (0x66/0x99 sequence, 0x10)
338  * [ 7: 7]: Reserved
339  * [ 6: 0]: Status register (read-only, 0x0)
340  */
341 #define BFPT_WORD_16(X) \
342  X(31, 14, kBfptNotSupported) & \
343  X(13, 8, 0x10) & \
344  X( 6, 0, 0x0)
345 
346 /**
347  * BFPT 17th Word
348  * --------------
349  * [31: 0]: Fast read (1S-8S-8S) (1S-1S-8S) (not supported, 0x0)
350  */
351 #define BFPT_WORD_17(X) \
352  X(31, 0, kBfptNotSupported)
353 
354 /**
355  * BFPT 18th Word
356  * --------------
357  * [31, 0]: Data strobe, SPI protocol reset, etc. (not supported, 0x0)
358  *
359  * Note: Reserved fields of this word should be 0 (JESD216F 6.4.21).
360  */
361 #define BFPT_WORD_18(X) \
362  X(31, 0, kBfptNotSupported)
363 
364 /**
365  * BFPT 19th Word
366  * --------------
367  * [31, 0]: Octable enable, (8D-8D-8D), 0-8-8 mode (not suported, 0x0)
368  *
369  * Note: Reserved fields of this word should be 0 (JESD216F 6.4.22).
370  */
371 #define BFPT_WORD_19(X) \
372  X(31, 0, kBfptNotSupported)
373 
374 /**
375  * BFPT 20th Word
376  * --------------
377  * [31, 0]: Max (8S-8S-8S) (4D-4D-4D) (4S-4S-4S) speed
378  * (not supported, 0xffffffff)
379  */
380 #define BFPT_WORD_20(X) \
381  X(31, 0, UINT32_MAX)
382 
383 /**
384  * BFPT 21st Word
385  * --------------
386  * [31, 0]: Fast read support for various modes (not supported, 0x0)
387  *
388  * Note: Reserved fields of this word should be 0 (JESD216F 6.4.24).
389  */
390 #define BFPT_WORD_21(X) \
391  X(31, 0, kBfptNotSupported)
392 
393 /**
394  * BFPT 22nd Word
395  * --------------
396  * [31, 0]: Fast read (1S-1D-1D) (1S-2D-2D) (not supported, 0x0)
397  */
398 #define BFPT_WORD_22(X) \
399  X(31, 0, kBfptNotSupported)
400 
401 /**
402  * BFPT 23rd Word
403  * --------------
404  * [31, 0]: Fast read (1S-4D-4D) (4S-2D-2D) (not supported, 0x0)
405  */
406 #define BFPT_WORD_23(X) \
407  X(31, 0, kBfptNotSupported)
408 // clang-format on
409 
410 const spi_device_sfdp_table_t kSpiDeviceSfdpTable = {
411  .sfdp_header =
412  {
413  .signature = kSfdpSignature,
414  .minor_revision = kSfdpMinorRevision,
415  .major_revision = kSfdpMajorRevision,
416  .param_count = kSfdpParamCount,
417  .access_protocol = kSfdpAccessProtocol,
418  },
419  .bfpt_header =
420  {
421  .param_id_lsb = kBfptParamIdLsb,
422  .minor_revision = kBfptMinorRevision,
423  .major_revision = kBfptMajorRevision,
424  .table_word_count = kSpiDeviceBfptNumWords,
425  .table_pointer = {kBfptTablePointer},
426  .param_id_msb = kBfptParamIdMsb,
427  },
428  .bfpt = {{
429  BFPT_WORD_1(BFPT_FIELD_VALUE), BFPT_WORD_2(BFPT_FIELD_VALUE),
430  BFPT_WORD_3(BFPT_FIELD_VALUE), BFPT_WORD_4(BFPT_FIELD_VALUE),
431  BFPT_WORD_5(BFPT_FIELD_VALUE), BFPT_WORD_6(BFPT_FIELD_VALUE),
432  BFPT_WORD_7(BFPT_FIELD_VALUE), BFPT_WORD_8(BFPT_FIELD_VALUE),
433  BFPT_WORD_9(BFPT_FIELD_VALUE), BFPT_WORD_10(BFPT_FIELD_VALUE),
434  BFPT_WORD_11(BFPT_FIELD_VALUE), BFPT_WORD_12(BFPT_FIELD_VALUE),
435  BFPT_WORD_13(BFPT_FIELD_VALUE), BFPT_WORD_14(BFPT_FIELD_VALUE),
436  BFPT_WORD_15(BFPT_FIELD_VALUE), BFPT_WORD_16(BFPT_FIELD_VALUE),
437  BFPT_WORD_17(BFPT_FIELD_VALUE), BFPT_WORD_18(BFPT_FIELD_VALUE),
438  BFPT_WORD_19(BFPT_FIELD_VALUE), BFPT_WORD_20(BFPT_FIELD_VALUE),
439  BFPT_WORD_21(BFPT_FIELD_VALUE), BFPT_WORD_22(BFPT_FIELD_VALUE),
440  BFPT_WORD_23(BFPT_FIELD_VALUE),
441  }}};
442 
443 /**
444  * Configuration options for a SPI Flash command.
445  */
446 typedef struct cmd_info {
447  /**
448  * Offset of the CMD_INFO register to set.
449  */
450  uint32_t reg_offset;
451  /**
452  * Instruction code.
453  */
454  uint8_t op_code;
455  /**
456  * Address.
457  *
458  * 3 bytes if true, no address if false.
459  */
460  bool address;
461  /**
462  * Number of dummy cycles.
463  */
464  uint8_t dummy_cycles;
465  /**
466  * Whether the command is handled in software.
467  *
468  * If this field is true, BUSY and UPLOAD bits of the CMD_INFO register will
469  * be set. spi_device treats the bytes following the address as the payload.
470  * Maximum payload size is 256 bytes and spi_device will overwrite the payload
471  * area if a larger payload is received.
472  */
474 } cmd_info_t;
475 
476 /**
477  * Configures the spi_device to handle the given command.
478  *
479  * @param cmd_info Configuration options for a SPI Flash command.
480  */
481 static void cmd_info_set(cmd_info_t cmd_info) {
482  // CMD_INFO registers share the same layout, the code below uses the macros of
483  // the CMD_INFO_0 register.
484  uint32_t reg = bitfield_field32_write(0, SPI_DEVICE_CMD_INFO_0_OPCODE_0_FIELD,
485  cmd_info.op_code);
487  reg, SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_FIELD,
488  cmd_info.address ? SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDR3B
489  : SPI_DEVICE_CMD_INFO_0_ADDR_MODE_0_VALUE_ADDRDISABLED);
490  if (cmd_info.dummy_cycles > 0) {
491  // `DUMMY_SIZE` field is zero-based.
492  reg = bitfield_field32_write(reg, SPI_DEVICE_CMD_INFO_0_DUMMY_SIZE_0_FIELD,
493  cmd_info.dummy_cycles - 1);
494  reg = bitfield_bit32_write(reg, SPI_DEVICE_CMD_INFO_0_DUMMY_EN_0_BIT, true);
495  }
496  reg = bitfield_bit32_write(reg, SPI_DEVICE_CMD_INFO_0_UPLOAD_0_BIT,
498  reg = bitfield_bit32_write(reg, SPI_DEVICE_CMD_INFO_0_BUSY_0_BIT,
500  reg = bitfield_bit32_write(reg, SPI_DEVICE_CMD_INFO_0_VALID_0_BIT, true);
501  abs_mmio_write32(spi_device_reg_base() + cmd_info.reg_offset, reg);
502 }
503 
504 void spi_device_init(void) {
505  // CPOL = 0, CPHA = 0, MSb-first TX and RX, 3-byte addressing.
506  uint32_t reg = bitfield_bit32_write(0, SPI_DEVICE_CFG_TX_ORDER_BIT, false);
507  reg = bitfield_bit32_write(reg, SPI_DEVICE_CFG_RX_ORDER_BIT, false);
508  reg = bitfield_bit32_write(reg, SPI_DEVICE_CFG_MAILBOX_EN_BIT, false);
509  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_CFG_REG_OFFSET, reg);
510 
511  reg = bitfield_bit32_write(0, SPI_DEVICE_ADDR_MODE_ADDR_4B_EN_BIT, false);
512  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_ADDR_MODE_REG_OFFSET,
513  reg);
514 
515  // JEDEC manufacturer and device ID.
516  // spi_device sends these in the following order: continuation codes,
517  // manufacturer ID, LSB of device ID, and MSB of device ID (density).
518  reg = bitfield_field32_write(0, SPI_DEVICE_JEDEC_CC_CC_FIELD,
519  kSpiDeviceJedecContCode);
520  reg = bitfield_field32_write(reg, SPI_DEVICE_JEDEC_CC_NUM_CC_FIELD,
521  kSpiDeviceJedecContCodeCount);
522  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_JEDEC_CC_REG_OFFSET, reg);
523  // Note: The code below assumes that chip revision and generation numbers
524  // from the life cycle controller (16-bits each) will fit in the revision and
525  // generation fields of the device ID (3 and 4 bits, respectively).
526  lifecycle_hw_rev_t hw_rev;
527  lifecycle_hw_rev_get(&hw_rev);
528  // TODO: hw_rev mapping may have to be updated.
529  reg = bitfield_field32_write(0, SPI_DEVICE_DEV_ID_CHIP_REV_FIELD,
530  hw_rev.revision_id);
531  reg = bitfield_bit32_write(reg, SPI_DEVICE_DEV_ID_ROM_BOOTSTRAP_BIT, true);
532  reg = bitfield_field32_write(reg, SPI_DEVICE_DEV_ID_CHIP_GEN_FIELD,
533  hw_rev.product_id);
534  reg = bitfield_field32_write(reg, SPI_DEVICE_DEV_ID_DENSITY_FIELD,
535  kSpiDeviceJedecDensity);
536  reg = bitfield_field32_write(reg, SPI_DEVICE_JEDEC_ID_MF_FIELD,
537  kSpiDeviceJedecManufId);
538  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_JEDEC_ID_REG_OFFSET, reg);
539 
540  // Write SFDP table to the reserved region in spi_device buffer.
541  uint32_t dest = spi_device_reg_base() + kSfdpAreaStartOff;
542  const char *table = (const char *)&kSpiDeviceSfdpTable;
543  for (size_t i = 0; i < kSpiDeviceSfdpTableNumWords; ++i) {
544  abs_mmio_write32(dest, read_32(table));
545  dest += sizeof(uint32_t);
546  table += sizeof(uint32_t);
547  }
548  // Fill the remaining space with `0xff`s.
549  for (; dest < spi_device_reg_base() + kSfdpAreaEndOff;
550  dest += sizeof(uint32_t)) {
551  abs_mmio_write32(dest, UINT32_MAX);
552  }
553 
554  // Reset status register
555  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_FLASH_STATUS_REG_OFFSET,
556  0);
557 
558  // Configure the READ_STATUS command (CMD_INFO_0).
559  cmd_info_set((cmd_info_t){
560  .reg_offset = SPI_DEVICE_CMD_INFO_0_REG_OFFSET,
561  .op_code = kSpiDeviceOpcodeReadStatus,
562  .address = false,
563  .dummy_cycles = 0,
564  .handled_in_sw = false,
565  });
566  // Configure the READ_JEDEC_ID command (CMD_INFO_3).
567  cmd_info_set((cmd_info_t){
568  .reg_offset = SPI_DEVICE_CMD_INFO_3_REG_OFFSET,
569  .op_code = kSpiDeviceOpcodeReadJedecId,
570  .address = false,
571  .dummy_cycles = 0,
572  .handled_in_sw = false,
573  });
574  // Configure the READ_SFDP command (CMD_INFO_4).
575  cmd_info_set((cmd_info_t){
576  .reg_offset = SPI_DEVICE_CMD_INFO_4_REG_OFFSET,
577  .op_code = kSpiDeviceOpcodeReadSfdp,
578  .address = true,
579  .dummy_cycles = 8,
580  .handled_in_sw = false,
581  });
582  // Configure the CHIP_ERASE command (CMD_INFO_11).
583  cmd_info_set((cmd_info_t){
584  .reg_offset = SPI_DEVICE_CMD_INFO_11_REG_OFFSET,
585  .op_code = kSpiDeviceOpcodeChipErase,
586  .address = false,
587  .dummy_cycles = 0,
588  .handled_in_sw = true,
589  });
590  // Configure the SECTOR_ERASE command (CMD_INFO_12).
591  cmd_info_set((cmd_info_t){
592  .reg_offset = SPI_DEVICE_CMD_INFO_12_REG_OFFSET,
593  .op_code = kSpiDeviceOpcodeSectorErase,
594  .address = true,
595  .dummy_cycles = 0,
596  .handled_in_sw = true,
597  });
598  // Configure the PAGE_PROGRAM command (CMD_INFO_13).
599  cmd_info_set((cmd_info_t){
600  .reg_offset = SPI_DEVICE_CMD_INFO_13_REG_OFFSET,
601  .op_code = kSpiDeviceOpcodePageProgram,
602  .address = true,
603  .dummy_cycles = 0,
604  .handled_in_sw = true,
605  });
606  // Configure the RESET command (CMD_INFO_14).
607  cmd_info_set((cmd_info_t){
608  .reg_offset = SPI_DEVICE_CMD_INFO_14_REG_OFFSET,
609  .op_code = kSpiDeviceOpcodeReset,
610  .address = false,
611  .dummy_cycles = 0,
612  .handled_in_sw = true,
613  });
614  // Configure the WRITE_ENABLE and WRITE_DISABLE commands.
615  reg = bitfield_field32_write(0, SPI_DEVICE_CMD_INFO_WREN_OPCODE_FIELD,
616  kSpiDeviceOpcodeWriteEnable);
617  reg = bitfield_bit32_write(reg, SPI_DEVICE_CMD_INFO_WREN_VALID_BIT, true);
618  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_CMD_INFO_WREN_REG_OFFSET,
619  reg);
620  reg = bitfield_field32_write(reg, SPI_DEVICE_CMD_INFO_WRDI_OPCODE_FIELD,
621  kSpiDeviceOpcodeWriteDisable);
622  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_CMD_INFO_WRDI_REG_OFFSET,
623  reg);
624 }
625 
626 rom_error_t spi_device_cmd_get(spi_device_cmd_t *cmd) {
627  uint32_t reg = 0;
628  bool cmd_pending = false;
629  while (!cmd_pending) {
630  // Note: Using INTR_STATE.UPLOAD_CMDFIFO_NOT_EMPTY because
631  // UPLOAD_STATUS.CMDFIFO_NOTEMPTY is set before the SPI transaction ends.
632  reg = abs_mmio_read32(spi_device_reg_base() +
633  SPI_DEVICE_INTR_STATE_REG_OFFSET);
634  cmd_pending = bitfield_bit32_read(
635  reg, SPI_DEVICE_INTR_COMMON_UPLOAD_CMDFIFO_NOT_EMPTY_BIT);
636  }
637  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_INTR_STATE_REG_OFFSET,
638  UINT32_MAX);
639  if (bitfield_bit32_read(reg,
640  SPI_DEVICE_INTR_COMMON_UPLOAD_PAYLOAD_OVERFLOW_BIT)) {
641  return kErrorSpiDevicePayloadOverflow;
642  }
643 
644  reg = abs_mmio_read32(spi_device_reg_base() +
645  SPI_DEVICE_UPLOAD_CMDFIFO_REG_OFFSET);
646  cmd->opcode =
647  bitfield_field32_read(reg, SPI_DEVICE_UPLOAD_CMDFIFO_DATA_FIELD);
648  cmd->address = kSpiDeviceNoAddress;
649  reg = abs_mmio_read32(spi_device_reg_base() +
650  SPI_DEVICE_UPLOAD_STATUS_REG_OFFSET);
651  if (bitfield_bit32_read(reg,
652  SPI_DEVICE_UPLOAD_STATUS_ADDRFIFO_NOTEMPTY_BIT)) {
653  cmd->address = abs_mmio_read32(spi_device_reg_base() +
654  SPI_DEVICE_UPLOAD_ADDRFIFO_REG_OFFSET);
655  }
656 
657  reg = abs_mmio_read32(spi_device_reg_base() +
658  SPI_DEVICE_UPLOAD_STATUS2_REG_OFFSET);
659  cmd->payload_byte_count =
660  bitfield_field32_read(reg, SPI_DEVICE_UPLOAD_STATUS2_PAYLOAD_DEPTH_FIELD);
661  // `payload_byte_count` can be at most `kSpiDevicePayloadAreaNumBytes`.
662  HARDENED_CHECK_LE(cmd->payload_byte_count, kSpiDevicePayloadAreaNumBytes);
663  uint32_t src = spi_device_reg_base() + SPI_DEVICE_INGRESS_BUFFER_REG_OFFSET +
664  kSpiDevicePayloadAreaOffset;
665  char *dest = (char *)&cmd->payload;
666  for (size_t i = 0; i < cmd->payload_byte_count; i += sizeof(uint32_t)) {
667  write_32(abs_mmio_read32(src + i), dest + i);
668  }
669 
670  return kErrorOk;
671 }
672 
673 void spi_device_flash_status_clear(void) {
674  abs_mmio_write32(spi_device_reg_base() + SPI_DEVICE_FLASH_STATUS_REG_OFFSET,
675  0);
676 }
677 
678 uint32_t spi_device_flash_status_get(void) {
679  return abs_mmio_read32(spi_device_reg_base() +
680  SPI_DEVICE_FLASH_STATUS_REG_OFFSET);
681 }