Software APIs
spi_flash_testutils.h
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 #ifndef OPENTITAN_SW_DEVICE_LIB_TESTING_SPI_FLASH_TESTUTILS_H_
6 #define OPENTITAN_SW_DEVICE_LIB_TESTING_SPI_FLASH_TESTUTILS_H_
7 
8 #include <stdbool.h>
9 #include <stdint.h>
10 
12 #include "sw/device/lib/base/status.h"
14 
16  uint16_t device_id;
17  uint8_t manufacturer_id;
18  uint8_t continuation_len;
20 
21 enum {
22  // The standard SFDP signature value.
23  kSfdpSignature = 0x50444653,
24 };
25 
26 /**
27  * Transaction width mode.
28  */
29 typedef enum spi_flash_testutils_transaction_width_mode {
30  /* Use 1 channel for opcode, 1 channel for address and 1 channel for data. */
31  kTransactionWidthMode111 = 0,
32  /* Use 1 channel for opcode, 1 channel for address and 2 channels for data. */
33  kTransactionWidthMode112,
34  /* Use 1 channel for opcode, 2 channels for address and 2 channels for data.
35  */
36  kTransactionWidthMode122,
37  /* Use 2 channels for opcode, 2 channels for address and 2 channels for data.
38  */
39  kTransactionWidthMode222,
40  /* Use 1 channel for opcode, 1 channel for address and 4 channel for data. */
41  kTransactionWidthMode114,
42  /* Use 1 channel for opcode, 4 channels for address and 4 channels for data.
43  */
44  kTransactionWidthMode144,
45  /* Use 4 channels for opcode, 4 channels for address and 4 channels for data.
46  */
47  kTransactionWidthMode444,
48 } spi_flash_testutils_transaction_width_mode_t;
49 
51  uint32_t signature;
52  uint8_t minor;
53  uint8_t major;
54  uint8_t nph;
55  uint8_t reserved;
57 
59  uint8_t param_id;
60  uint8_t minor;
61  uint8_t major;
62  uint8_t length;
63  uint8_t table_pointer[3];
64  uint8_t pad;
66 
67 // JESD216F, section 6.4.18:
68 // The Quad Enable mechanism is bits 20:23 of the 15th dword.
69 #define SPI_FLASH_QUAD_ENABLE ((bitfield_field32_t){.mask = 7, .index = 20})
70 #define SPI_FLASH_ADDRESS_MODE ((bitfield_field32_t){.mask = 3, .index = 17})
71 
72 /**
73  * Read out the JEDEC ID from the SPI flash.
74  *
75  * @param spih A SPI host handle.
76  * @param[out] id A pointer to where to store the ID.
77  * @return The result of the operation.
78  */
80 status_t spi_flash_testutils_read_id(dif_spi_host_t *spih,
82 
83 /**
84  * Read out the SFDP from the indicated address and place the table contents
85  * into the buffer.
86  *
87  * @param spih A SPI host handle.
88  * @param[out] buffer A pointer to a buffer that will hold the SFDP contents.
89  * @param length The number of bytes to write into `buffer`.
90  * @return The result of the operation.
91  */
93 status_t spi_flash_testutils_read_sfdp(dif_spi_host_t *spih, uint32_t address,
94  void *buffer, size_t length);
95 
96 typedef enum spi_flash_status_bit {
97  kSpiFlashStatusBitWip = 0x1,
98  kSpiFlashStatusBitWel = 0x2,
99 } spi_flash_status_bit_t;
100 
101 /**
102  * Perform a Read Status command.
103  *
104  * Issues a Read Status transaction using the requested opcode.
105  * In the case of a multi-byte status, the bytes are assembled and returned
106  * as a litte-endian word.
107  *
108  * @param spih A SPI host handle.
109  * @param opcode The desired Read Status opcode.
110  * @param length The result length (1 to 3 bytes).
111  * @return status_t containing either the status register value or an error.
112  */
114 status_t spi_flash_testutils_read_status(dif_spi_host_t *spih, uint8_t opcode,
115  size_t length);
116 
117 /**
118  * Perform a Write Status command.
119  *
120  * Issues a Write Status transaction using the requested opcode.
121  * In the case of a multi-byte status, the status word bytes are
122  * as a litte-endian word.
123  *
124  * @param spih A SPI host handle.
125  * @param opcode The desired Write Status opcode.
126  * @param status The status register value to write.
127  * @param length The status length (1 to 3 bytes).
128  * @return status_t containing either OK or an error.
129  */
131 status_t spi_flash_testutils_write_status(dif_spi_host_t *spih, uint8_t opcode,
132  uint32_t status, size_t length);
133 /**
134  * Spin wait until a Read Status command shows the downstream SPI flash is no
135  * longer busy.
136  *
137  * @param spih A SPI host handle.
138  * @return status_t containing either OK or an error.
139  */
141 status_t spi_flash_testutils_wait_until_not_busy(dif_spi_host_t *spih);
142 
143 /**
144  * Issue the Write Enable command to the downstream SPI flash.
145  *
146  * @param spih A SPI host handle.
147  * @return status_t containing either OK or an error.
148  */
150 status_t spi_flash_testutils_issue_write_enable(dif_spi_host_t *spih);
151 
152 /**
153  * Perform full Chip Erase sequence, including the Write Enable and Chip Erase
154  * commands, and poll the status registers in a loop until the WIP bit clears.
155  *
156  * Does not return until the erase completes.
157  *
158  * @param spih A SPI host handle.
159  * @return status_t containing either OK or an error.
160  */
162 status_t spi_flash_testutils_erase_chip(dif_spi_host_t *spih);
163 
164 /**
165  * Perform full Sector Erase sequence via the requested opcode.
166  * The sequence includes the Write Enable and Sector Erase commands,
167  * and then polls the status registers in a loop until the WIP
168  * bit clears.
169  *
170  * Does not return until the erase completes.
171  *
172  * @param spih A SPI host handle.
173  * @param opcode The desired erase opcode.
174  * @param address An address contained within the desired sector.
175  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
176  * @return status_t containing either OK or an error.
177  */
179 status_t spi_flash_testutils_erase_op(dif_spi_host_t *spih, uint8_t opcode,
180  uint32_t address, bool addr_is_4b);
181 
182 /**
183  * Perform full Sector Erase sequence via the standard Sector Erase opcode.
184  * The sequence includes the Write Enable and Sector Erase commands,
185  * and then polls the status registers in a loop until the WIP
186  * bit clears.
187  * Does not return until the erase completes.
188  *
189  * @param spih A SPI host handle.
190  * @param address An address contained within the desired sector.
191  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
192  * @return status_t containing either OK or an error.
193  */
195 status_t spi_flash_testutils_erase_sector(dif_spi_host_t *spih,
196  uint32_t address, bool addr_is_4b);
197 
198 /**
199  * Perform full 32 kB block erase.
200  * The sequence includes the Write Enable and Block Erase commands,
201  * and then polls the status registers in a loop until the WIP
202  * bit clears.
203  * Does not return until the erase completes.
204  *
205  * @param spih A SPI host handle.
206  * @param address An address contained within the desired block.
207  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
208  * @return status_t containing either OK or an error.
209  */
210 status_t spi_flash_testutils_erase_block32k(dif_spi_host_t *spih,
211  uint32_t address, bool addr_is_4b);
212 
213 /**
214  * Perform full 64 kB block erase.
215  * The sequence includes the Write Enable and Block Erase commands,
216  * and then polls the status registers in a loop until the WIP
217  * bit clears.
218  * Does not return until the erase completes.
219  *
220  * @param spih A SPI host handle.
221  * @param address An address contained within the desired block.
222  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
223  * @return status_t containing either OK or an error.
224  */
225 status_t spi_flash_testutils_erase_block64k(dif_spi_host_t *spih,
226  uint32_t address, bool addr_is_4b);
227 /**
228  * Perform full Page Program sequence via the requested opcode.
229  * The sequence includes the Write Enable and Page Program commands,
230  * and then polls the status registers in a loop until the WIP bit
231  * clears.
232  *
233  * Does not return until the programming operation completes.
234  *
235  * @param spih A SPI host handle.
236  * @param opcode The desired program opcode.
237  * @param payload A pointer to the payload to be written to the page.
238  * @param length Number of bytes in the payload. Must be less than or equal to
239  * 256 bytes.
240  * @param address The start address where the payload programming should begin.
241  * Note that an address + length that crosses a page boundary may
242  * wrap around to the start of the page.
243  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
244  * @param page_program_mode The width of the transaction sections (opcode,
245  * address and data).
246  * @return status_t containing either OK or an error.
247  */
249 status_t spi_flash_testutils_program_op(
250  dif_spi_host_t *spih, uint8_t opcode, const void *payload, size_t length,
251  uint32_t address, bool addr_is_4b,
252  spi_flash_testutils_transaction_width_mode_t page_program_mode);
253 
254 /**
255  * Perform full Page Program sequence via the standard page program opcode.
256  * The sequence includes the Write Enable and Page Program commands,
257  * and then polls the status registers in a loop until the WIP bit
258  * clears.
259  *
260  * Does not return until the programming operation completes.
261  *
262  * @param spih A SPI host handle.
263  * @param payload A pointer to the payload to be written to the page.
264  * @param length Number of bytes in the payload. Must be less than or equal to
265  * 256 bytes.
266  * @param address The start address where the payload programming should begin.
267  * Note that an address + length that crosses a page boundary may
268  * wrap around to the start of the page.
269  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
270  * @return status_t containing either OK or an error.
271  */
273 status_t spi_flash_testutils_program_page(dif_spi_host_t *spih,
274  const void *payload, size_t length,
275  uint32_t address, bool addr_is_4b);
276 /**
277  * Perform full Page Program sequence via the quad page program opcode.
278  * The sequence includes the Write Enable and Page Program commands,
279  * and then polls the status registers in a loop until the WIP bit
280  * clears.
281  *
282  * Does not return until the programming operation completes.
283  *
284  * @param spih A SPI host handle.
285  * @param opcode The program page quad opcode as it varies across parts.
286  * @param payload A pointer to the payload to be written to the page.
287  * @param length Number of bytes in the payload. Must be less than or equal to
288  * 256 bytes.
289  * @param address The start address where the payload programming should begin.
290  * Note that an address + length that crosses a page boundary may
291  * wrap around to the start of the page.
292  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
293  * @param addr_width The width of the transaction addressing section.
294  * @return status_t containing either OK or an error.
295  */
297 status_t spi_flash_testutils_program_page_quad(
298  dif_spi_host_t *spih, uint8_t opcode, const void *payload, size_t length,
299  uint32_t address, bool addr_is_4b, uint8_t addr_width);
300 
301 /**
302  * Perform a read via the requested opcode.
303  *
304  * @param spih A SPI host handle.
305  * @param opcode The desired read opcode.
306  * @param[out] payload A pointer to the buffer to receive data from the device.
307  * @param length Number of bytes in the buffer. Must be less than or equal to
308  * 256 bytes.
309  * @param address The start address where the read should begin.
310  * @param addr_is_4b True if `address` is 4 bytes long, else 3 bytes.
311  * @param width The width of the read (1, 2 or 4 bits).
312  * @param dummy The number of dummy cycles required after the address phase.
313  * @return status_t containing either OK or an error.
314  */
316 status_t spi_flash_testutils_read_op(dif_spi_host_t *spih, uint8_t opcode,
317  void *payload, size_t length,
318  uint32_t address, bool addr_is_4b,
319  uint8_t width, uint8_t dummy);
320 
321 /**
322  * Enable or disable Quad mode on the EEPROM according to the SFDP-described
323  * method.
324  *
325  * @param spih A SPI host handle.
326  * @param method The method to use to enable. This value should come from the
327  * SFDP quad-enable field described in JESD216 section 6.4.18.
328  * @param enable Whether to enable or disable quad mode.
329  * @return status_t containing either OK or an error.
330  */
332 status_t spi_flash_testutils_quad_enable(dif_spi_host_t *spih, uint8_t method,
333  bool enable);
334 /**
335  * Enables 4-bytes addressing mode.
336  *
337  * @param spih A SPI host handle.
338  * @return status_t containing either OK or an error.
339  */
341 status_t spi_flash_testutils_enter_4byte_address_mode(dif_spi_host_t *spih);
342 
343 /**
344  * Disables 4-bytes addressing mode.
345  *
346  * @param spih A SPI host handle.
347  * @return status_t containing either OK or an error.
348  */
350 status_t spi_flash_testutils_exit_4byte_address_mode(dif_spi_host_t *spih);
351 
352 /**
353  * Get the opcode width of a transaction mode.
354  *
355  * @param width_mode The transaction width mode.
356  * @return The opcode width
357  */
358 inline static dif_spi_host_width_t spi_flash_testutils_get_opcode_width(
359  spi_flash_testutils_transaction_width_mode_t width_mode) {
360  switch (width_mode) {
361  case kTransactionWidthMode222:
362  return kDifSpiHostWidthDual;
363  case kTransactionWidthMode444:
364  return kDifSpiHostWidthQuad;
365  default:
367  }
368 };
369 
370 /**
371  * Get the address width of a transaction mode.
372  *
373  * @param width_mode The transaction width mode.
374  * @return The address width
375  */
376 inline static dif_spi_host_width_t spi_flash_testutils_get_address_width(
377  spi_flash_testutils_transaction_width_mode_t width_mode) {
378  switch (width_mode) {
379  case kTransactionWidthMode122:
380  return kDifSpiHostWidthDual;
381  case kTransactionWidthMode222:
382  return kDifSpiHostWidthDual;
383  case kTransactionWidthMode144:
384  return kDifSpiHostWidthQuad;
385  case kTransactionWidthMode444:
386  return kDifSpiHostWidthQuad;
387  default:
389  }
390 };
391 
392 /**
393  * Get the data width of a transaction mode.
394  *
395  * @param width_mode The transaction width mode.
396  * @return The data width
397  */
398 inline static dif_spi_host_width_t spi_flash_testutils_get_data_width(
399  spi_flash_testutils_transaction_width_mode_t width_mode) {
400  switch (width_mode) {
401  case kTransactionWidthMode111:
403  case kTransactionWidthMode112:
404  return kDifSpiHostWidthDual;
405  case kTransactionWidthMode122:
406  return kDifSpiHostWidthDual;
407  case kTransactionWidthMode222:
408  return kDifSpiHostWidthDual;
409  default:
410  return kDifSpiHostWidthQuad;
411  }
412 };
413 
414 #endif // OPENTITAN_SW_DEVICE_LIB_TESTING_SPI_FLASH_TESTUTILS_H_