Software APIs
rstmgr_sw_rst_ctrl_test.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 #if defined(OPENTITAN_IS_EARLGREY)
6 #include "dt/dt_usbdev.h" // Generated
7 #include "sw/device/lib/dif/dif_usbdev.h" // Generated
8 
9 #include "usbdev_regs.h" // Generated
10 #elif defined(OPENTITAN_IS_DARJEELING)
11 // Darjeeling does not have a USB device
12 #else
13 #error "rstmgr_sw_rst_ctrl_test does not support this top"
14 #endif
15 
16 #include "dt/dt_i2c.h" // Generated
17 #include "dt/dt_rstmgr.h" // Generated
18 #include "dt/dt_spi_device.h" // Generated
19 #include "dt/dt_spi_host.h" // Generated
29 #include "sw/device/lib/testing/test_framework/check.h"
31 
32 #include "i2c_regs.h" // Generated
33 #include "spi_device_regs.h" // Generated
34 #include "spi_host_regs.h" // Generated
35 
36 OTTF_DEFINE_TEST_CONFIG();
37 
38 /**
39  * RSTMGR SW_RST_CTRL Test
40  *
41  * This test checks RSTMGR.SW_RST_CTRL_N[index] with peripheral devices.
42  *
43  * On Earlgrey, the RSTMGR.SW_RST_CTRL_N register has 8 bits. One of these
44  * controls USB_AON which has no software writeable CSRs, so it is not
45  * amenable to this test yet it is still reset with the expectation that
46  * it has no side-effects. The various bits control peripheral resets as
47  * follows:
48  *
49  * // index | device | test register | reset value | prgm value |
50  * // ------------------------------------------------------------------
51  * // 0 | SPI_DEVICE | CFG | 0x7f00 | 0x3f0c
52  * // 1 | SPI_HOST0 | CONFIGOPTS | 0x0 | 0x3210000
53  * // 2 | SPI_HOST1 | CONFIGOPTS | 0x0 | 0x6540000
54  * // 3 | USB | EP_OUT_ENABLE | 0x0 | 0xc3
55  * // 4 | USB_AON | | |
56  * // 5 | I2C0 | TIMING0 | 0x0 | 0x8b00cfe
57  * // 6 | I2C1 | TIMING1 | 0x0 | 0x114010d8
58  * // 7 | I2C2 | TIMING2 | 0x0 | 0x19ec1595
59  *
60  * On Darjeeling, there are only 3 bits:
61  *
62  * // index | device | test register | reset value | prgm value |
63  * // ------------------------------------------------------------------
64  * // 0 | SPI_DEVICE | CFG | 0x7f00 | 0x3f0c
65  * // 1 | SPI_HOST0 | CONFIGOPTS | 0x0 | 0x3210000
66  * // 2 | I2C0 | TIMING0 | 0x0 | 0x8b00cfe
67  *
68  * 'test register' is a rw type register under each peripheral device.
69  * These registers are programmed with arbitrary values ('prgm value') before
70  * resetting each peripheral, and the expectation is that when reset is
71  * asserted the register value is set to its reset value. This test has
72  * multiple rounds, one per peripheral.
73  */
74 
75 #define MAKE_INIT_FUNC(ip_) \
76  void ip_##_init(void *ip_, int32_t dt) { \
77  CHECK_DIF_OK(dif##_##ip_##_init_from_dt((dt_##ip_##_t)dt, ip_)); \
78  }
79 
80 #define MAKE_BASE_ADDR_FUNC(ip_) \
81  uintptr_t ip_##_base_addr(int32_t dt, int32_t reg_block) { \
82  return dt_##ip_##_reg_block((dt_##ip_##_t)dt, \
83  (dt_##ip_##_reg_block_t)reg_block); \
84  }
85 
86 #define MAKE_RSTMGR_RESET_FUNC(ip_) \
87  dt_reset_t ip_##_rstmgr_reset(int32_t dt, int32_t device_reset) { \
88  return dt_##ip_##_reset((dt_##ip_##_t)dt, \
89  (dt_##ip_##_reset_t)device_reset); \
90  }
91 
92 #define MAKE_TEST_FUNCS(ip_) \
93  MAKE_INIT_FUNC(ip_); \
94  MAKE_BASE_ADDR_FUNC(ip_); \
95  MAKE_RSTMGR_RESET_FUNC(ip_);
96 
97 #if defined(OT_HAS_USBDEV)
98 MAKE_TEST_FUNCS(usbdev);
99 #endif // defined(OT_HAS_USBDEV)
100 
101 MAKE_TEST_FUNCS(spi_device);
102 MAKE_TEST_FUNCS(spi_host);
103 MAKE_TEST_FUNCS(i2c);
104 
105 static void spi_device_config(void *dif) {
106  uintptr_t handle_address =
107  ((uintptr_t)dif - offsetof(dif_spi_device_handle_t, dev));
108  dif_spi_device_handle_t *handle = (dif_spi_device_handle_t *)handle_address;
110  .tx_order = kDifSpiDeviceBitOrderLsbToMsb,
111  .rx_order = kDifSpiDeviceBitOrderLsbToMsb,
112  .device_mode = kDifSpiDeviceModeDisabled,
113  };
114  CHECK_DIF_OK(dif_spi_device_configure(handle, cfg));
115 }
116 
117 static void spi_host0_config(void *dif) {
118  dif_spi_host_config_t cfg = {
119  .spi_clock = 500000,
120  .peripheral_clock_freq_hz = 1000000,
121  .chip_select =
122  {
123  .idle = 1,
124  .trail = 2,
125  .lead = 3,
126  },
127  .full_cycle = false,
128  .cpha = false,
129  .cpol = false,
130  };
131  CHECK_DIF_OK(dif_spi_host_configure(dif, cfg));
132 }
133 
134 #if defined(OPENTITAN_IS_EARLGREY)
135 static void spi_host1_config(void *dif) {
136  dif_spi_host_config_t cfg = {
137  .spi_clock = 2500000,
138  .peripheral_clock_freq_hz = 5000000,
139  .chip_select =
140  {
141  .idle = 4,
142  .trail = 5,
143  .lead = 6,
144  },
145  .full_cycle = false,
146  .cpha = false,
147  .cpol = false,
148  };
149  CHECK_DIF_OK(dif_spi_host_configure(dif, cfg));
150 }
151 #elif defined(OPENTITAN_IS_DARJEELING)
152 // Darjeeling only has 1 SPI Host
153 #else
154 #error "rstmgr_sw_rst_ctrl_test does not support this top"
155 #endif
156 
157 static void i2c0_config(void *dif) {
158  dif_i2c_config_t cfg = {
159  .scl_time_high_cycles = 3326,
160  .scl_time_low_cycles = 2224,
161  };
162  CHECK_DIF_OK(dif_i2c_configure(dif, cfg));
163 }
164 
165 #if defined(OPENTITAN_IS_EARLGREY)
166 static void i2c1_config(void *dif) {
167  dif_i2c_config_t cfg = {
168  .rise_cycles = 4312,
169  .fall_cycles = 4416,
170  };
171  CHECK_DIF_OK(dif_i2c_configure(dif, cfg));
172 }
173 
174 static void i2c2_config(void *dif) {
175  dif_i2c_config_t cfg = {
176  .start_signal_setup_cycles = 5525,
177  .start_signal_hold_cycles = 6636,
178  };
179  CHECK_DIF_OK(dif_i2c_configure(dif, cfg));
180 }
181 #elif defined(OPENTITAN_IS_DARJEELING)
182 // Darjeeling only has 1 I2C Controller
183 #else
184 #error "rstmgr_sw_rst_ctrl_test does not support this top"
185 #endif
186 
187 static dif_spi_device_handle_t spi_dev;
188 static dif_spi_host_t spi_host0;
189 static dif_i2c_t i2c0;
190 
191 #if defined(OPENTITAN_IS_EARLGREY)
192 static dif_spi_host_t spi_host1;
193 static dif_usbdev_t usbdev;
194 static dif_i2c_t i2c1;
195 static dif_i2c_t i2c2;
196 #elif defined(OPENTITAN_IS_DARJEELING)
197 /* Darjeeling does not have a USB device, and only has 1 I2C Controller and
198 SPI Host. */
199 #else
200 #error "rstmgr_sw_rst_ctrl_test does not support this top"
201 #endif
202 
203 typedef struct test {
204  /**
205  * Name of the peripheral.
206  */
207  const char *name;
208  /**
209  * Initialization for the base address of the peripheral.
210  *
211  * Cannot be `NULL`.
212  */
213  uintptr_t (*get_base_address)(int32_t dt, int32_t reg_block);
214  /*
215  * The devicetable instance of the peripheral.
216  */
217  int32_t dt;
218  /**
219  * The register block that the test register belongs to.
220  */
221  int32_t reg_block;
222  /**
223  * Offset to the peripheral's test register.
224  */
225  ptrdiff_t offset;
226  /**
227  * Handle to the DIF object for this peripheral.
228  */
229  void *dif;
230  /**
231  * Initialization for the DIF based on an address location.
232  *
233  * May be `NULL`.
234  */
235  void (*init)(void *dif, int32_t dt);
236  /**
237  * Configuration and initialization actions for the device. This
238  * will be passed the value of `dif` above.
239  *
240  * If `NULL`, the test register will be set to 'reset_vals[]'.
241  */
242  void (*config)(void *dif);
243  /**
244  * Arbitrary test register value before reset.
245  */
246  uint32_t program_val;
247  /**
248  * The device-local DT reset index for this device. By using the
249  * corresponding dt instance, this is used to retrieve the correct
250  * index in the reset manager for this device.
251  */
252  int32_t reset_index;
253  /**
254  * The DT function for getting the reset manager index of the
255  * corresponding device for this test using the reset index.
256  *
257  * Cannot be `NULL`.
258  */
259  dt_reset_t (*get_rstmgr_rst_index)(int32_t dt, int32_t reset_index);
260 } test_t;
261 
262 static const test_t kPeripherals[] = {
263  {
264  .name = "SPI_DEVICE",
265  .get_base_address = spi_device_base_addr,
266  .dt = (dt_spi_device_t)0,
267  .reg_block = kDtSpiDeviceRegBlockCore,
268  .offset = SPI_DEVICE_CFG_REG_OFFSET,
269  .dif = &spi_dev.dev,
270  .init = spi_device_init,
271  .config = spi_device_config,
272  .program_val = 0x3f0c,
273  .reset_index = kDtSpiDeviceResetRst,
274  .get_rstmgr_rst_index = spi_device_rstmgr_reset,
275  },
276  {
277  .name = "SPI_HOST0",
278  .get_base_address = spi_host_base_addr,
279  .dt = (dt_spi_host_t)0,
280  .reg_block = kDtSpiHostRegBlockCore,
281  .offset = SPI_HOST_CONFIGOPTS_REG_OFFSET,
282  .dif = &spi_host0,
283  .init = spi_host_init,
284  .config = spi_host0_config,
285  .program_val = 0x3210000,
286  .reset_index = kDtSpiHostResetRst,
287  .get_rstmgr_rst_index = spi_host_rstmgr_reset,
288  },
289 #if defined(OPENTITAN_IS_EARLGREY)
290  {
291  .name = "SPI_HOST1",
292  .get_base_address = spi_host_base_addr,
293  .dt = (dt_spi_host_t)1,
294  .reg_block = kDtSpiHostRegBlockCore,
295  .offset = SPI_HOST_CONFIGOPTS_REG_OFFSET,
296  .dif = &spi_host1,
297  .init = spi_host_init,
298  .config = spi_host1_config,
299  .program_val = 0x6540000,
300  .reset_index = kDtSpiHostResetRst,
301  .get_rstmgr_rst_index = spi_host_rstmgr_reset,
302  },
303  {
304  .name = "USB",
305  .get_base_address = usbdev_base_addr,
306  .dt = (dt_usbdev_t)0,
307  .reg_block = kDtUsbdevRegBlockCore,
308  .offset = USBDEV_EP_OUT_ENABLE_REG_OFFSET,
309  .dif = &usbdev,
310  .init = usbdev_init,
311  .program_val = 0xc3,
312  .reset_index = kDtUsbdevResetRst,
313  .get_rstmgr_rst_index = usbdev_rstmgr_reset,
314  },
315 #elif defined(OPENTITAN_IS_DARJEELING)
316 // Darjeeling does not have a USB Device, and only has 1 SPI Host
317 #else
318 #error "rstmgr_sw_rst_ctrl_test does not support this top"
319 #endif
320  {
321  .name = "I2C0",
322  .get_base_address = i2c_base_addr,
323  .reg_block = kDtI2cRegBlockCore,
324  .dt = (dt_i2c_t)0,
325  .offset = I2C_TIMING0_REG_OFFSET,
326  .dif = &i2c0,
327  .init = i2c_init,
328  .config = i2c0_config,
329  .program_val = 0x8b00cfe,
330  .reset_index = kDtI2cResetRst,
331  .get_rstmgr_rst_index = i2c_rstmgr_reset,
332  },
333 #if defined(OPENTITAN_IS_EARLGREY)
334  {
335  .name = "I2C1",
336  .get_base_address = i2c_base_addr,
337  .dt = (dt_i2c_t)1,
338  .reg_block = kDtI2cRegBlockCore,
339  .offset = I2C_TIMING1_REG_OFFSET,
340  .dif = &i2c1,
341  .init = i2c_init,
342  .config = i2c1_config,
343  .program_val = 0x114010d8,
344  .reset_index = kDtI2cResetRst,
345  .get_rstmgr_rst_index = i2c_rstmgr_reset,
346  },
347  {
348  .name = "I2C2",
349  .get_base_address = i2c_base_addr,
350  .dt = (dt_i2c_t)2,
351  .reg_block = kDtI2cRegBlockCore,
352  .offset = I2C_TIMING2_REG_OFFSET,
353  .dif = &i2c2,
354  .init = i2c_init,
355  .config = i2c2_config,
356  .program_val = 0x19ec1595,
357  .reset_index = kDtI2cResetRst,
358  .get_rstmgr_rst_index = i2c_rstmgr_reset,
359  },
360 #elif defined(OPENTITAN_IS_DARJEELING)
361 // Darjeeling only has 1 I2C Controller
362 #else
363 #error "rstmgr_sw_rst_ctrl_test does not support this top"
364 #endif
365 };
366 
367 /**
368  * Reads the value of the test register in a particular device.
369  */
370 static uint32_t read_test_reg(const test_t *test) {
371  uintptr_t base = test->get_base_address(test->dt, test->reg_block);
372  return mmio_region_read32(mmio_region_from_addr(base), test->offset);
373 }
374 
375 bool test_main(void) {
376  dif_rstmgr_t rstmgr;
377  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kDtRstmgrAon, &rstmgr));
378 
379 #if defined(OT_HAS_USBDEV)
380  // For completeness reset USB_AON first, expecting no side-effects. The lame
381  // check is that the rest of the test goes through with no problem.
382  dt_reset_t reset = dt_usbdev_reset((dt_usbdev_t)0, kDtUsbdevResetRst);
383  size_t sw_reset_index;
384  CHECK_DIF_OK(
385  dif_rstmgr_get_sw_reset_index(kDtRstmgrAon, reset, &sw_reset_index));
386  CHECK_DIF_OK(dif_rstmgr_software_reset(&rstmgr, sw_reset_index,
388 #endif // defined(OT_HAS_USBDEV)
389 
390  uint32_t reset_vals[ARRAYSIZE(kPeripherals)];
391  for (size_t i = 0; i < ARRAYSIZE(kPeripherals); ++i) {
392  if (kPeripherals[i].init != NULL) {
393  kPeripherals[i].init(kPeripherals[i].dif, kPeripherals[i].dt);
394  }
395  reset_vals[i] = read_test_reg(&kPeripherals[i]);
396  LOG_INFO("reset_val for %s is 0x%08x", kPeripherals[i].name, reset_vals[i]);
397  }
398 
399  for (size_t i = 0; i < ARRAYSIZE(kPeripherals); ++i) {
400  if (kPeripherals[i].config != NULL) {
401  kPeripherals[i].config(kPeripherals[i].dif);
402  } else {
403  uintptr_t base = kPeripherals[i].get_base_address(
404  kPeripherals[i].dt, kPeripherals[i].reg_block);
405  mmio_region_write32(mmio_region_from_addr(base), kPeripherals[i].offset,
406  kPeripherals[i].program_val);
407  }
408 
409  // add read back to make sure
410  // all register access complete
411  uint32_t got = read_test_reg(&kPeripherals[i]);
412  LOG_INFO("programmed value : 0x%x", got);
413  }
414 
415  for (size_t i = 0; i < ARRAYSIZE(kPeripherals); ++i) {
416  dt_reset_t reset_index = kPeripherals[i].get_rstmgr_rst_index(
417  kPeripherals[i].dt, kPeripherals[i].reset_index);
418  size_t sw_reset_index;
419  CHECK_DIF_OK(dif_rstmgr_get_sw_reset_index(kDtRstmgrAon, reset_index,
420  &sw_reset_index));
421  CHECK_DIF_OK(dif_rstmgr_software_reset(&rstmgr, sw_reset_index,
423 
424  uint32_t got = read_test_reg(&kPeripherals[i]);
425  CHECK(got == reset_vals[i],
426  "after configure: reset_val for %s mismatch: want 0x%x, got 0x%x",
427  kPeripherals[i].name, reset_vals[i], got);
428  }
429 
430  return true;
431 }