Software APIs
pattgen_ios_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 
9 #include "sw/device/lib/runtime/irq.h"
11 #include "sw/device/lib/testing/rv_plic_testutils.h"
12 #include "sw/device/lib/testing/test_framework/check.h"
13 #include "sw/device/lib/testing/test_framework/ottf_console.h"
15 #include "sw/device/lib/testing/test_framework/ottf_utils.h"
16 
18 #include "pattgen_regs.h" // Generated.
19 
20 /**
21  PATTGEN IOS test
22  The test programs both channels of the pattgen to random patterns.
23  Pattgen ios are connected as follows:
24  pda_tx[0] - IOB9
25  pcl_tx[0] - IOB10
26  pda_tx[1] - IOB11
27  pcl_tx[1] - IOB12
28 
29  The random pattern programmed by 'chip_sw_patt_ios_vseq.sv'
30  and output will be collected at the PADS and compared in SV test bench.
31  */
32 
33 OTTF_DEFINE_TEST_CONFIG(.enable_uart_flow_control = true);
34 
35 enum {
36  kTestCmdTimeoutUsec = 5000000,
37 };
38 
39 /* Macro to define and use variable that need to be stored in flash
40  * for DV tests and RAM for real tests, to enable backdoor access. */
41 #define DEFINE_BACKDOOR_VAR(type, name, default_val) \
42  /* DV variable in flash. */ \
43  OTTF_BACKDOOR_VAR_DV type name##DV = default_val; \
44  /* non-DV variable in RAM. */ \
45  OTTF_BACKDOOR_VAR type name##Real = default_val;
46 
47 #define BACKDOOR_VAR(name) \
48  (kDeviceType == kDeviceSimDV ? OTTF_BACKDOOR_READ(name##DV) : name##Real)
49 
50 // Following volatile const will be overwritten by
51 // SV testbench with random values.
52 // 1: channel 0, 2: channel 1, 3: Both channels
53 DEFINE_BACKDOOR_VAR(uint8_t, kChannelEnable, 3)
54 
55 DEFINE_BACKDOOR_VAR(uint8_t, kPattPol0, kDifPattgenPolarityLow)
56 DEFINE_BACKDOOR_VAR(uint8_t, kPattInactiveLevelPda0, 0)
57 DEFINE_BACKDOOR_VAR(uint8_t, kPattInactiveLevelPcl0, 0)
58 DEFINE_BACKDOOR_VAR(uint32_t, kPattDiv0, 0)
59 DEFINE_BACKDOOR_VAR(uint32_t, kPattLower0, 0x76543210)
60 DEFINE_BACKDOOR_VAR(uint32_t, kPattUpper0, 0x76543210)
61 DEFINE_BACKDOOR_VAR(uint8_t, kPattLen0, 40)
62 DEFINE_BACKDOOR_VAR(uint16_t, kPattRep0, 3)
63 
64 DEFINE_BACKDOOR_VAR(uint8_t, kPattPol1, kDifPattgenPolarityLow)
65 DEFINE_BACKDOOR_VAR(uint8_t, kPattInactiveLevelPda1, 0)
66 DEFINE_BACKDOOR_VAR(uint8_t, kPattInactiveLevelPcl1, 0)
67 DEFINE_BACKDOOR_VAR(uint32_t, kPattDiv1, 0)
68 DEFINE_BACKDOOR_VAR(uint32_t, kPattLower1, 0x76543210)
69 DEFINE_BACKDOOR_VAR(uint32_t, kPattUpper1, 0x76543210)
70 DEFINE_BACKDOOR_VAR(uint8_t, kPattLen1, 40)
71 DEFINE_BACKDOOR_VAR(uint16_t, kPattRep1, 3)
72 
73 typedef enum {
74  kTestCmdWait = 0,
75  kTestCmdConfigure = 1,
76  kTestCmdRun = 2,
77  kTestCmdStop = 3,
78 } test_cmd_t;
79 
80 /* Backdoor variable for real device */
81 OTTF_BACKDOOR_VAR
82 uint8_t test_cmd = kTestCmdWait;
83 
84 static const uint32_t kPlicTarget = kTopEarlgreyPlicTargetIbex0;
85 static const uint8_t kPattOuts = 4;
86 
87 static const dif_pinmux_index_t kPinmuxOutsel[] = {
88  kTopEarlgreyPinmuxOutselPattgenPda0Tx, /**< = 49: Peripheral Output 46 */
89  kTopEarlgreyPinmuxOutselPattgenPcl0Tx, /**< = 50: Peripheral Output 47 */
90  kTopEarlgreyPinmuxOutselPattgenPda1Tx, /**< = 51: Peripheral Output 48 */
91  kTopEarlgreyPinmuxOutselPattgenPcl1Tx, /**< = 52: Peripheral Output 49 */
92 };
93 static const dif_pinmux_index_t kPinmuxMioOutDV[] = {
98 };
99 static const dif_pinmux_index_t kPinmuxMioOutReal[] = {
104 };
105 
106 static dif_rv_plic_t plic;
107 static dif_pattgen_t pattgen;
108 static volatile uint8_t channel_fired = 0;
109 
110 /**
111  * External interrupt handler.
112  */
113 void ottf_external_isr(uint32_t *exc_info) {
114  dif_rv_plic_irq_id_t irq_id;
115 
116  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &irq_id));
117  // Handle OTTF interrupt.
120  if (peripheral == kTopEarlgreyPlicPeripheralUart0 &&
121  ottf_console_flow_control_isr(exc_info)) {
122  return;
123  }
124 
125  LOG_INFO("IRQ detected %d", irq_id);
126 
127  bool is_pending;
128  switch (irq_id) {
130  LOG_INFO("Channel 0");
131  channel_fired |= 1 << 0;
132  // Check the expected interrupt is triggered.
133  CHECK_DIF_OK(dif_pattgen_irq_is_pending(&pattgen, kDifPattgenIrqDoneCh0,
134  &is_pending));
135  CHECK(is_pending == true);
136  CHECK_DIF_OK(
137  dif_pattgen_irq_acknowledge(&pattgen, kDifPattgenIrqDoneCh0));
138  break;
140  channel_fired |= 1 << 1;
141  LOG_INFO("Channel 1");
142  // Check the expected interrupt is triggered.
143  CHECK_DIF_OK(dif_pattgen_irq_is_pending(&pattgen, kDifPattgenIrqDoneCh1,
144  &is_pending));
145  CHECK(is_pending == true);
146  CHECK_DIF_OK(
147  dif_pattgen_irq_acknowledge(&pattgen, kDifPattgenIrqDoneCh1));
148  break;
149  default:
150  LOG_FATAL("IRQ: unknown irq %d", irq_id);
151  break;
152  }
153  // Complete the IRQ by writing the IRQ source to the Ibex specific CC.
154  // register.
155  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, irq_id));
156 }
157 
158 static void run_test(void);
159 
160 bool test_main(void) {
161  dif_pinmux_t pinmux;
162  // Let the host know the peripheral frequency.
163  LOG_INFO("peripheral frequency: %u", (unsigned int)kClockFreqPeripheralHz);
164 
165  irq_global_ctrl(true);
166  irq_external_ctrl(true);
167 
168  CHECK_DIF_OK(dif_pattgen_init(
170  CHECK_DIF_OK(dif_pattgen_channel_set_enabled(&pattgen, kDifPattgenChannel0,
172  CHECK_DIF_OK(dif_pattgen_channel_set_enabled(&pattgen, kDifPattgenChannel1,
174  CHECK_DIF_OK(dif_rv_plic_init(
176  rv_plic_testutils_irq_range_enable(&plic, kPlicTarget,
179 
180  // Initialize pinmux
181  // Assign PattgenOutput to IOB9..12
182  CHECK_DIF_OK(dif_pinmux_init(
184 
185  LOG_INFO("pinmux_init begin");
186  const dif_pinmux_index_t *kPinmuxMioOut =
187  kDeviceType == kDeviceSimDV ? kPinmuxMioOutDV : kPinmuxMioOutReal;
188  for (uint8_t i = 0; i < kPattOuts; ++i) {
189  CHECK_DIF_OK(
190  dif_pinmux_output_select(&pinmux, kPinmuxMioOut[i], kPinmuxOutsel[i]));
191  }
192  // Do not remove below msg.
193  LOG_INFO("pinmux_init end");
194 
195  // In DV, we only run the test once.
196  if (kDeviceType == kDeviceSimDV) {
197  run_test();
198  return true;
199  }
200  // On FPGA/silicon, we run the test in a loop.
201  while (true) {
202  test_cmd = kTestCmdWait;
203  OTTF_WAIT_FOR(test_cmd != kTestCmdWait, kTestCmdTimeoutUsec);
204  if (test_cmd == kTestCmdStop) {
205  break;
206  }
207  CHECK(test_cmd == kTestCmdConfigure);
208  run_test();
209  }
210  return true;
211 }
212 
213 static void run_test(void) {
214  // Enable pattgen interrupt at plic
215  CHECK_DIF_OK(dif_pattgen_irq_set_enabled(&pattgen, kDifPattgenIrqDoneCh0,
217  CHECK_DIF_OK(dif_pattgen_irq_set_enabled(&pattgen, kDifPattgenIrqDoneCh1,
219 
220  channel_fired = 0;
221  // Program pattgen if the channel is enabled.
223  if (BACKDOOR_VAR(kChannelEnable) & 0x1) {
224  patt_cfg.polarity = BACKDOOR_VAR(kPattPol0);
225  patt_cfg.inactive_level_pda = BACKDOOR_VAR(kPattInactiveLevelPda0);
226  patt_cfg.inactive_level_pcl = BACKDOOR_VAR(kPattInactiveLevelPcl0);
227  patt_cfg.clock_divisor = BACKDOOR_VAR(kPattDiv0);
228  patt_cfg.seed_pattern_lower_word = BACKDOOR_VAR(kPattLower0);
229  patt_cfg.seed_pattern_upper_word = BACKDOOR_VAR(kPattUpper0);
230  patt_cfg.seed_pattern_length = BACKDOOR_VAR(kPattLen0);
231  patt_cfg.num_pattern_repetitions = BACKDOOR_VAR(kPattRep0);
232  CHECK_DIF_OK(
233  dif_pattgen_configure_channel(&pattgen, kDifPattgenChannel0, patt_cfg));
234  }
235 
236  if (BACKDOOR_VAR(kChannelEnable) & 0x2) {
237  patt_cfg.polarity = BACKDOOR_VAR(kPattPol1);
238  patt_cfg.inactive_level_pda = BACKDOOR_VAR(kPattInactiveLevelPda1);
239  patt_cfg.inactive_level_pcl = BACKDOOR_VAR(kPattInactiveLevelPcl1);
240  patt_cfg.clock_divisor = BACKDOOR_VAR(kPattDiv1);
241  patt_cfg.seed_pattern_lower_word = BACKDOOR_VAR(kPattLower1);
242  patt_cfg.seed_pattern_upper_word = BACKDOOR_VAR(kPattUpper1);
243  patt_cfg.seed_pattern_length = BACKDOOR_VAR(kPattLen1);
244  patt_cfg.num_pattern_repetitions = BACKDOOR_VAR(kPattRep1);
245  CHECK_DIF_OK(
246  dif_pattgen_configure_channel(&pattgen, kDifPattgenChannel1, patt_cfg));
247  }
248  // Tell host that the channels are configured.
249  LOG_INFO("Channels configured");
250  // Wait for host to tell us to run.
251  if (kDeviceType != kDeviceSimDV) {
252  OTTF_WAIT_FOR(test_cmd == kTestCmdRun, kTestCmdTimeoutUsec);
253  }
254 
255  // Start channels.
256  if (BACKDOOR_VAR(kChannelEnable) & 0x1) {
257  CHECK_DIF_OK(dif_pattgen_channel_set_enabled(&pattgen, kDifPattgenChannel0,
259  }
260  if (BACKDOOR_VAR(kChannelEnable) & 0x2) {
261  CHECK_DIF_OK(dif_pattgen_channel_set_enabled(&pattgen, kDifPattgenChannel1,
263  }
264 
265  // Make sure both interrupts are triggered when both channels are enabled.
266  // Because interrupt from each channel can be triggered at different time,
267  // 'wait_for_interrupt' is not sufficient
268  ATOMIC_WAIT_FOR_INTERRUPT(channel_fired == BACKDOOR_VAR(kChannelEnable));
269 
270  // Disable both channels.
271  CHECK_DIF_OK(dif_pattgen_channel_set_enabled(&pattgen, kDifPattgenChannel0,
273  CHECK_DIF_OK(dif_pattgen_channel_set_enabled(&pattgen, kDifPattgenChannel1,
275 
276  // Do not remove the below message
277  LOG_INFO("TEST DONE");
278 }