Software APIs
spi_host_flash_test_impl.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 #include <assert.h>
5 
14 #include "sw/device/lib/testing/spi_device_testutils.h"
15 #include "sw/device/lib/testing/spi_flash_testutils.h"
16 #include "sw/device/lib/testing/test_framework/check.h"
17 
19 
20 #define MODULE_ID MAKE_MODULE_ID('s', 'h', 'f')
21 
22 // A data pattern to program into the chip:
23 // From: http://www.abrahamlincolnonline.org/lincoln/speeches/gettysburg.htm
24 static const char kGettysburgPrelude[256] =
25  "Four score and seven years ago our fathers brought forth on this "
26  "continent, a new nation, conceived in Liberty, and dedicated to the "
27  "proposition that all men are created equal.";
28 
29 // The SFDP structure we'll read out of the chip.
30 typedef struct sfdp {
31  union {
32  struct {
35  };
36  uint8_t data[256];
37  };
38  uint32_t *bfpt;
39 } sfdp_t;
40 
41 sfdp_t sfdp;
42 
43 status_t test_software_reset(dif_spi_host_t *spi) {
44  // The software reset sequence is two transactions: RSTEN followed by RST.
47  .opcode = {.opcode = kSpiDeviceFlashOpResetEnable,
48  .width = kDifSpiHostWidthStandard}};
49  TRY(dif_spi_host_transaction(spi, /*cs_id=*/0, &op, 1));
50 
51  TRY(dif_spi_host_transaction(spi, /*cs_id=*/0, &op, 1));
52  return OK_STATUS();
53 }
54 
55 status_t test_read_sfdp(dif_spi_host_t *spi) {
56  TRY(spi_flash_testutils_read_sfdp(spi, 0, sfdp.data, sizeof(sfdp.data)));
57  LOG_INFO("SFDP signature is 0x%08x", sfdp.header.signature);
58  CHECK(sfdp.header.signature == kSfdpSignature,
59  "Expected to find the SFDP signature!");
60 
61  uint32_t bfpt_offset = (uint32_t)sfdp.param.table_pointer[0] |
62  (uint32_t)(sfdp.param.table_pointer[1] << 8) |
63  (uint32_t)(sfdp.param.table_pointer[2] << 16);
64  sfdp.bfpt = (uint32_t *)(sfdp.data + bfpt_offset);
65  return OK_STATUS();
66 }
67 
68 status_t test_read_jedec(dif_spi_host_t *spi, uint8_t manufacture_id) {
70  TRY(spi_flash_testutils_read_id(spi, &jdec));
71  TRY_CHECK(jdec.manufacturer_id == manufacture_id, "Expected %x, got %x!",
72  manufacture_id, jdec.manufacturer_id);
73  return OK_STATUS();
74 }
75 
76 status_t test_sector_erase(dif_spi_host_t *spi) {
77  TRY(spi_flash_testutils_erase_sector(spi, 0, false));
78 
79  // Check that the first page of flash actually got erased.
80  uint8_t buf[256] = {0};
81  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadNormal, buf,
82  sizeof(buf),
83  /*address=*/0,
84  /*addr_is_4b=*/false,
85  /*width=*/1,
86  /*dummy=*/0));
87  uint8_t expected[256];
88  memset(expected, 0xFF, sizeof(expected));
89  TRY_CHECK_ARRAYS_EQ(buf, expected, ARRAYSIZE(expected));
90  return OK_STATUS();
91 }
92 
93 status_t test_enable_quad_mode(dif_spi_host_t *spi) {
94  if (sfdp.param.length < 14) {
95  return INVALID_ARGUMENT();
96  }
97  uint8_t mech =
98  (uint8_t)bitfield_field32_read(sfdp.bfpt[14], SPI_FLASH_QUAD_ENABLE);
99  LOG_INFO("Setting the EEPROM's QE bit via mechanism %d", mech);
100  TRY(spi_flash_testutils_quad_enable(spi, mech, /*enabled=*/true));
101  return OK_STATUS();
102 }
103 
104 // Program a pattern into the flash part and read it back.
105 status_t test_page_program(dif_spi_host_t *spi) {
106  TRY(spi_flash_testutils_program_page(spi, kGettysburgPrelude,
107  sizeof(kGettysburgPrelude),
108  /*address=*/0, /*addr_is_4b=*/0));
109 
110  uint8_t buf[256];
111  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadNormal, buf,
112  sizeof(buf), 0,
113  /*addr_is_4b=*/false,
114  /*width=*/1,
115  /*dummy=*/0));
116  TRY_CHECK_ARRAYS_EQ(buf, kGettysburgPrelude, ARRAYSIZE(kGettysburgPrelude));
117  return OK_STATUS();
118 }
119 
120 status_t test_page_program_quad(
121  dif_spi_host_t *spi, uint8_t opcode,
122  spi_flash_testutils_transaction_width_mode_t page_program_mode) {
123  enum { kPageSize = 256, kAddress = kPageSize * 10 };
124 
125  TRY(spi_flash_testutils_erase_sector(spi, kAddress, false));
126 
127  TRY(spi_flash_testutils_program_op(
128  spi, opcode, kGettysburgPrelude, sizeof(kGettysburgPrelude),
129  /*address=*/kAddress, /*addr_is_4b=*/false, page_program_mode));
130 
131  uint8_t buf[256];
132  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadNormal, buf,
133  sizeof(buf), kAddress,
134  /*addr_is_4b=*/false,
135  /*width=*/1,
136  /*dummy=*/0));
137  TRY_CHECK_ARRAYS_EQ(buf, kGettysburgPrelude, ARRAYSIZE(kGettysburgPrelude));
138  return OK_STATUS();
139 }
140 
141 // Read the flash device using the "fast read" opcode.
142 status_t test_fast_read(dif_spi_host_t *spi) {
143  uint8_t buf[256];
144  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadFast, buf,
145  sizeof(buf), 0,
146  /*addr_is_4b=*/false,
147  /*width=*/1,
148  /*dummy=*/8));
149  TRY_CHECK_ARRAYS_EQ(buf, kGettysburgPrelude, ARRAYSIZE(kGettysburgPrelude));
150  return OK_STATUS();
151 }
152 
153 // Read the flash device using the "fast dual read" opcode.
154 status_t test_dual_read(dif_spi_host_t *spi) {
155  uint8_t buf[256];
156  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadDual, buf,
157  sizeof(buf), 0,
158  /*addr_is_4b=*/false,
159  /*width=*/2,
160  /*dummy=*/8));
161  TRY_CHECK_ARRAYS_EQ(buf, kGettysburgPrelude, ARRAYSIZE(kGettysburgPrelude));
162  return OK_STATUS();
163 }
164 
165 // Read the flash device using the "fast quad read" opcode.
166 status_t test_quad_read(dif_spi_host_t *spi) {
167  uint8_t buf[256];
168  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadQuad, buf,
169  sizeof(buf), 0,
170  /*addr_is_4b=*/false,
171  /*width=*/4,
172  /*dummy=*/8));
173  TRY_CHECK_ARRAYS_EQ(buf, kGettysburgPrelude, ARRAYSIZE(kGettysburgPrelude));
174  return OK_STATUS();
175 }
176 
177 bool is_4_bytes_address_mode_supported(void) {
178  enum { kSupportOnly3Bytes, kSupport3and4Bytes, kSupportOnly4Bytes };
179  uint32_t address_mode =
180  bitfield_field32_read(sfdp.bfpt[0], SPI_FLASH_ADDRESS_MODE);
181  return (address_mode == kSupport3and4Bytes ||
182  address_mode == kSupportOnly4Bytes);
183 }
184 
185 status_t test_4bytes_address(dif_spi_host_t *spi) {
186  enum { kAddress = 0x01000100, kSectorSize = 4096 };
187  static_assert(kAddress % kSectorSize,
188  "Should be at the beginning of the sector.");
189 
190  TRY(spi_flash_testutils_enter_4byte_address_mode(spi));
191  TRY(spi_flash_testutils_erase_sector(spi, kAddress, true));
192 
193  TRY(spi_flash_testutils_program_page(spi, kGettysburgPrelude,
194  sizeof(kGettysburgPrelude), kAddress,
195  /*addr_is_4b=*/true));
196 
197  uint8_t buf[256];
198  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadNormal, buf,
199  sizeof(buf), kAddress,
200  /*addr_is_4b=*/true,
201  /*width=*/1,
202  /*dummy=*/0));
203  TRY_CHECK_ARRAYS_EQ(buf, kGettysburgPrelude, ARRAYSIZE(kGettysburgPrelude));
204  return spi_flash_testutils_exit_4byte_address_mode(spi);
205 }
206 
207 status_t test_erase_32k_block(dif_spi_host_t *spi) {
208  enum { kPageSize = 256, kBlockSize = 32 * 1024, kAddress = kBlockSize * 3 };
209  TRY(spi_flash_testutils_erase_block32k(spi, kAddress, false));
210 
211  uint8_t expected[256];
212  memset(expected, 0xFF, sizeof(expected));
213  uint8_t dummy[256];
214  memset(dummy, 0x5A, sizeof(dummy));
215 
216  for (size_t addr = kAddress; addr < kAddress + kBlockSize;
217  addr += kPageSize) {
218  uint8_t buf[256] = {0};
219  // Check that all the pages in the block actually got erased.
220  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadNormal, buf,
221  sizeof(buf),
222  /*address=*/addr,
223  /*addr_is_4b=*/false,
224  /*width=*/1,
225  /*dummy=*/0));
226  TRY_CHECK_ARRAYS_EQ(buf, expected, ARRAYSIZE(expected));
227 
228  // Write dummy data to make sure that the next time the block will really be
229  // erased.
230  TRY(spi_flash_testutils_program_page(spi, dummy, sizeof(dummy),
231  /*address=*/addr,
232  /*addr_is_4b=*/false));
233  }
234 
235  return OK_STATUS();
236 }
237 
238 status_t test_erase_64k_block(dif_spi_host_t *spi) {
239  enum { kPageSize = 256, kBlockSize = 64 * 1024, kAddress = kBlockSize * 5 };
240  TRY(spi_flash_testutils_erase_block64k(spi, kAddress, false));
241 
242  uint8_t expected[256];
243  memset(expected, 0xFF, sizeof(expected));
244  uint8_t dummy[256];
245  memset(dummy, 0x5A, sizeof(dummy));
246 
247  for (size_t addr = kAddress; addr < kAddress + kBlockSize;
248  addr += kPageSize) {
249  uint8_t buf[256] = {0};
250  // Check that all the pages in the block actually got erased.
251  TRY(spi_flash_testutils_read_op(spi, kSpiDeviceFlashOpReadNormal, buf,
252  sizeof(buf),
253  /*address=*/addr,
254  /*addr_is_4b=*/false,
255  /*width=*/1,
256  /*dummy=*/0));
257  TRY_CHECK_ARRAYS_EQ(buf, expected, ARRAYSIZE(expected));
258 
259  // Write dummy data to make sure that the next time the block will really be
260  // erased.
261  TRY(spi_flash_testutils_program_page(spi, dummy, sizeof(dummy),
262  /*address=*/addr,
263  /*addr_is_4b=*/false));
264  }
265 
266  return OK_STATUS();
267 }