Software APIs
soc_proxy_smoketest.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 
8 #include "sw/device/lib/dif/dif_soc_proxy.h"
10 #include "sw/device/lib/runtime/irq.h"
12 #include "sw/device/lib/testing/rstmgr_testutils.h"
14 
15 #include "hw/top_darjeeling/sw/autogen/top_darjeeling.h"
16 #include "soc_proxy_regs.h"
17 
18 OTTF_DEFINE_TEST_CONFIG();
19 
20 /**
21  * @brief To be executed after power-on reset (POR).
22  *
23  * @param pwrmgr Pointer to an initialized `dif_pwrmgr_t`.
24  *
25  * @return Does not return (spinwaits for a timeout and fails a check if the
26  * timeout is reached).
27  */
28 void after_por(dif_pwrmgr_t *pwrmgr) {
29  LOG_INFO("Reset after POR.");
30 
31  // Enable external reset request in pwrmgr.
32  dif_pwrmgr_request_sources_t reset_sources;
33  CHECK_DIF_OK(dif_pwrmgr_find_request_source(
34  pwrmgr, kDifPwrmgrReqTypeReset, dt_soc_proxy_instance_id(kDtSocProxy),
35  kDtSocProxyResetReqExternal, &reset_sources));
36  CHECK_DIF_OK(dif_pwrmgr_set_request_sources(
37  pwrmgr, kDifPwrmgrReqTypeReset, reset_sources, kDifToggleEnabled));
38  LOG_INFO("External resets enabled.");
39 
40  // Give DV environment time for triggering external reset.
41  busy_spin_micros(1000);
42 
43  // This should never be reached.
44  CHECK(false, "Did not get reset in time!");
45 }
46 
47 /**
48  * @brief To be executed after external reset request.
49  */
50 void after_ext_rst_req(const dif_rv_plic_t *rv_plic,
51  const dif_soc_proxy_t *soc_proxy) {
52  LOG_INFO("Reset on external request.");
53 
54  // At this point, we are expecting interrupt requests from DV env.
55 
56  // Enable external IRQs in Ibex.
57  irq_external_ctrl(true);
58 
59  for (unsigned i = 0; i < SOC_PROXY_PARAM_NUM_EXTERNAL_IRQS; i++) {
60  const dif_rv_plic_irq_id_t rv_plic_irq =
61  (dif_rv_plic_irq_id_t)(kTopDarjeelingPlicIrqIdSocProxyExternal0 + i);
62  const dif_rv_plic_target_t rv_plic_target = kTopDarjeelingPlicTargetIbex0;
63  const dif_soc_proxy_irq_t soc_proxy_irq = (dif_soc_proxy_irq_t)i;
64 
65  // Enable IRQ in SoC Proxy and PLIC.
66  CHECK_DIF_OK(dif_soc_proxy_irq_set_enabled(soc_proxy, soc_proxy_irq,
68  CHECK_DIF_OK(dif_rv_plic_irq_set_priority(rv_plic, rv_plic_irq, 1));
69  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
70  rv_plic, rv_plic_irq, rv_plic_target, kDifToggleEnabled));
71  LOG_INFO("IRQ %0d enabled.", i);
72 
73  for (unsigned num_try = 0; num_try < 10; num_try++) {
74  // Wait for interrupt, then check that the expected IRQ is pending in both
75  // SoC Proxy and PLIC.
77  bool soc_proxy_irq_pending;
78  CHECK_DIF_OK(dif_soc_proxy_irq_is_pending(soc_proxy, soc_proxy_irq,
79  &soc_proxy_irq_pending));
80  if (soc_proxy_irq_pending) {
81  LOG_INFO("IRQ %0d pending in soc_proxy.", i);
82  } else {
83  // Not the IRQ we're expecting, wait for another one.
84  continue;
85  }
86  bool rv_plic_irq_pending;
87  CHECK_DIF_OK(dif_rv_plic_irq_is_pending(rv_plic, rv_plic_irq,
88  &rv_plic_irq_pending));
89  if (rv_plic_irq_pending) {
90  // IRQ pending in PLIC and SoC Proxy, stop trying.
91  LOG_INFO("IRQ %0d pending in rv_plic.", i);
92  break;
93  } else {
94  // IRQ pending in SoC Proxy but not PLIC -> error and abort.
95  CHECK(false, "Expected IRQ to be pending in soc_proxy AND rv_plic!");
96  }
97  }
98 
99  // Acknowledge and complete IRQ.
100  CHECK_DIF_OK(dif_soc_proxy_irq_acknowledge(soc_proxy, soc_proxy_irq));
101  CHECK_DIF_OK(
102  dif_rv_plic_irq_complete(rv_plic, rv_plic_target, rv_plic_irq));
103 
104  // Disable IRQ in PLIC and SoC Proxy.
105  CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
106  rv_plic, rv_plic_irq, rv_plic_target, kDifToggleDisabled));
107  CHECK_DIF_OK(dif_soc_proxy_irq_set_enabled(soc_proxy, soc_proxy_irq,
109  }
110 
111  // Disable external IRQs in Ibex.
112  irq_external_ctrl(false);
113 }
114 
115 bool test_main(void) {
116  dif_pwrmgr_t pwrmgr;
117  dif_rstmgr_t rstmgr;
118  dif_rv_plic_t rv_plic;
119  dif_soc_proxy_t soc_proxy;
120 
121  CHECK_DIF_OK(dif_pwrmgr_init_from_dt(kDtPwrmgrAon, &pwrmgr));
122  CHECK_DIF_OK(dif_rstmgr_init_from_dt(kDtRstmgrAon, &rstmgr));
123  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kDtRvPlic, &rv_plic));
124  CHECK_DIF_OK(dif_soc_proxy_init_from_dt(kDtSocProxy, &soc_proxy));
125 
126  // Behave based on reset reason.
127  if (UNWRAP(
128  rstmgr_testutils_reset_info_any(&rstmgr, kDifRstmgrResetInfoPor))) {
129  after_por(&pwrmgr);
130  } else if (UNWRAP(rstmgr_testutils_reset_info_any(
131  &rstmgr, kDifRstmgrResetInfoExternalRst))) {
132  after_ext_rst_req(&rv_plic, &soc_proxy);
133  } else {
134  // Unexpected reset reason -> fail test.
135  return false;
136  }
137 
138  return true;
139 }