Software APIs
gpio_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 
11 #include "sw/device/lib/runtime/irq.h"
13 #include "sw/device/lib/testing/pinmux_testutils.h"
14 #include "sw/device/lib/testing/rv_plic_testutils.h"
15 #include "sw/device/lib/testing/test_framework/check.h"
17 
18 static const dt_gpio_t kGpioDt = kDtGpio;
19 static const dt_pinmux_t kPinmuxDt = kDtPinmuxAon;
20 static const dt_rv_plic_t kRvPlicDt = kDtRvPlic;
21 
22 enum {
23  kPlicTarget = 0,
24 };
25 
26 // Assume that the pins in dt_gpio_pin_t are numbered 0, 1, and so on.
27 static_assert(kDtGpioPeriphIoGpio0 == 0, "kDtGpioPinGpio0 is expected to be 0");
28 // Assume that the IRQs in dt_gpio_irq_t are numbered 0, 1, and so on.
29 static_assert(kDtGpioIrqGpio0 == 0, "kDtGpioIrqGpio0 is expected to be 0");
30 static_assert(kDtGpioPeriphIoCount == kDifGpioNumPins,
31  "kDtGpioPinCount does not match kDifGpioNumPins");
32 
33 static dif_gpio_t gpio;
34 static dif_pinmux_t pinmux;
35 static dif_rv_plic_t plic;
36 
37 // These indicate the GPIO pin irq expected to fire, declared volatile since
38 // they are used by the ISR.
39 static volatile uint32_t expected_gpio_pin_irq;
40 static volatile bool expected_irq_edge;
41 
42 /**
43  * GPIO test - verifies the GPIO pins in the input and output directions.
44  *
45  * In the output direction, SW writes the following pattern:
46  * 1. Start with GPIOs = all zeros
47  * 2. Walk a 1 through ALL GPIOs (presented by the IP), read `data_in` with each
48  * write to ensure correctness
49  * 3. Set all GPIOs to 0s, followed by all 1s.
50  * 4. Walk a 0 through ALL GPIOs (presented by the IP), read `data_in` with each
51  * write to ensure correctness
52  * 5. Set all GPIOs to 1s, followed by all 0s.
53  *
54  * The correctness of the GPIO values on the chip pins is verified by the
55  * external testbench. The correctness of `data_in` is limited to the number of
56  * GPIOs exposed by the chip, so we mask the written value accordingly.
57  *
58  * In the input direction, the external testbench sends the following pattern:
59  * 1. Walk a 1 in 'temperature' pattern (0001, 0011, 0111, 1111, 1110, 100, ..)
60  *
61  * Both, rising and falling edges are configured for generating an interrupt. As
62  * each pin rises or falls, the SW checks the interrupt, status and `data_in`
63  * for correctness.
64  */
65 
66 /**
67  * Runs the GPIO output test.
68  *
69  * Walks a 1 over the GPIO pins, followed by walking a 0.
70  * The external testbench checks the GPIO values for correctness.
71  */
72 static void gpio_output_test(const dif_gpio_t *gpio, uint32_t mask) {
73  LOG_INFO("Starting GPIO output test");
74 
75  // Set the GPIOs to be in output mode.
76  CHECK_DIF_OK(dif_gpio_output_set_enabled_all(gpio, mask));
77 
78  // Walk 1s - 0001, 0010, 0100, 1000, etc.
79  for (uint32_t i = 0; i < kDifGpioNumPins; ++i) {
80  uint32_t gpio_val = 1 << i;
81  CHECK_DIF_OK(dif_gpio_write_all(gpio, gpio_val));
82 
83  // The GPIO output signals are routed through pinmux back to the GPIO block
84  // and there are synchronizers involved so the inputs may not be available
85  // immediately, and may in fact arrive at different times.
87 
88  // Read GPIO_IN to confirm what we wrote.
89  uint32_t read_val;
90  CHECK_DIF_OK(dif_gpio_read_all(gpio, &read_val));
91 
92  // Check written and read val for correctness.
93  CHECK(gpio_val == read_val, "GPIOs mismatched (written = %x, read = %x)",
94  gpio_val, read_val);
95  }
96 
97  // Write all 0s to the GPIOs.
98  CHECK_DIF_OK(dif_gpio_write_all(gpio, ~mask));
99 
100  // Write all 1s to the GPIOs.
101  CHECK_DIF_OK(dif_gpio_write_all(gpio, mask));
102 
103  // Now walk 0s - 1110, 1101, 1011, 0111, etc.
104  for (uint32_t i = 0; i < kDifGpioNumPins; ++i) {
105  uint32_t gpio_val = ~(1 << i);
106  CHECK_DIF_OK(dif_gpio_write_all(gpio, gpio_val));
107 
108  // The GPIO output signals are routed through pinmux back to the GPIO block
109  // and there are synchronizers involved so the inputs may not be available
110  // immediately, and may in fact arrive at different times.
111  busy_spin_micros(1);
112 
113  // Read GPIO_IN to confirm what we wrote.
114  uint32_t read_val;
115  CHECK_DIF_OK(dif_gpio_read_all(gpio, &read_val));
116 
117  // Check written and read val for correctness.
118  CHECK(gpio_val == read_val, "GPIOs mismatched (written = %x, read = %x)",
119  gpio_val, read_val);
120  }
121 
122  // Write all 1s to the GPIOs.
123  CHECK_DIF_OK(dif_gpio_write_all(gpio, mask));
124 
125  // Write all 0s to the GPIOs.
126  CHECK_DIF_OK(dif_gpio_write_all(gpio, ~mask));
127 }
128 
129 /**
130  * Runs the GPIO input test.
131  *
132  * We start off with all 0s. The function polls the GPIOs for a 'thermometer
133  * code' pattern (0, 1, 11, 111 etc) which is driven by the testbench, through
134  * interrupts. The rising edge of each subsequent pin causes an interrupt to
135  * fire. The ISR checks for the right GPIO and polarity. The testbench then
136  * reverses the thermometer pattern (1111, 1110, 1100, 1000, etc).to capture the
137  * interrupt on the falling edge.
138  */
139 static void gpio_input_test(const dif_gpio_t *gpio, uint32_t mask) {
140  LOG_INFO("Starting GPIO input test");
141 
142  // Enable the noise filter on all GPIOs.
143  CHECK_DIF_OK(
145 
146  // Configure all GPIOs to be rising and falling edge interrupts.
147  CHECK_DIF_OK(dif_gpio_irq_set_trigger(gpio, mask,
149 
150  // Enable interrupts on all GPIOs.
151  CHECK_DIF_OK(dif_gpio_irq_restore_all(gpio, &mask));
152 
153  // Set the GPIOs to be in input mode.
154  CHECK_DIF_OK(dif_gpio_output_set_enabled_all(gpio, 0u));
155 
156  // Wait for rising edge interrupt on each pin.
157  expected_irq_edge = true;
158  for (expected_gpio_pin_irq = 0; expected_gpio_pin_irq < kDifGpioNumPins;
159  ++expected_gpio_pin_irq) {
161  }
162  uint32_t read_val;
163  uint32_t gpio_exp_val;
164 
165  gpio_exp_val = mask;
166  CHECK_DIF_OK(dif_gpio_read_all(gpio, &read_val));
167  CHECK(gpio_exp_val == read_val,
168  "GPIOs mismatched (expected = %x, actual = %x)", gpio_exp_val,
169  read_val);
170 
171  // Wait for falling edge interrupt on each pin.
172  expected_irq_edge = false;
173  for (expected_gpio_pin_irq = 0; expected_gpio_pin_irq < kDifGpioNumPins;
174  ++expected_gpio_pin_irq) {
176  }
177 
178  gpio_exp_val = ~mask;
179  CHECK_DIF_OK(dif_gpio_read_all(gpio, &read_val));
180  CHECK(gpio_exp_val == read_val,
181  "GPIOs mismatched (expected = %x, actual = %x)", gpio_exp_val,
182  read_val);
183 }
184 
185 /**
186  * Provides external irq handling for this test.
187  *
188  * This function overrides the default OTTF external ISR.
189  */
190 void ottf_external_isr(uint32_t *exc_info) {
191  // Find which interrupt fired at PLIC by claiming it.
192  dif_rv_plic_irq_id_t plic_irq_id;
193  CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic, kPlicTarget, &plic_irq_id));
194 
195  // Check if it is the right peripheral.
196  dt_instance_id_t inst_id = dt_plic_id_to_instance_id(plic_irq_id);
197  CHECK(inst_id == dt_gpio_instance_id(kGpioDt),
198  "Interrupt from incorrect peripheral: (exp: %d, obs: %s)",
199  dt_gpio_instance_id(kGpioDt), inst_id);
200 
201  // Correlate the interrupt fired from GPIO.
202  uint32_t gpio_pin_irq_fired = dt_gpio_irq_from_plic_id(kGpioDt, plic_irq_id);
203 
204  // Check if we did expect the right GPIO IRQ to fire.
205  CHECK(gpio_pin_irq_fired == expected_gpio_pin_irq,
206  "Incorrect GPIO interrupt (exp: %d, obs: %d)", expected_gpio_pin_irq,
207  gpio_pin_irq_fired);
208 
209  // Check if the same interrupt fired at GPIO as well.
210  uint32_t gpio_irqs_status;
211  CHECK_DIF_OK(dif_gpio_irq_get_state(&gpio, &gpio_irqs_status));
212  CHECK(gpio_irqs_status == (1 << expected_gpio_pin_irq),
213  "Incorrect GPIO irqs status {exp: %x, obs: %x}",
214  (1 << expected_gpio_pin_irq), gpio_irqs_status);
215 
216  // Read the gpio pin value to ensure the right value is being reflected.
217  bool pin_val;
218  CHECK_DIF_OK(dif_gpio_read(&gpio, expected_gpio_pin_irq, &pin_val));
219 
220  // Check if the pin value is set correctly.
221  CHECK(pin_val == expected_irq_edge, "Incorrect GPIO %d pin value (exp: %b)",
222  expected_gpio_pin_irq, expected_irq_edge);
223 
224  // Clear the interrupt at GPIO.
225  CHECK_DIF_OK(dif_gpio_irq_acknowledge(&gpio, gpio_pin_irq_fired));
226 
227  // Complete the IRQ at PLIC.
228  CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic, kPlicTarget, plic_irq_id));
229 }
230 
231 OTTF_DEFINE_TEST_CONFIG();
232 
233 void configure_pinmux(void) {
234  for (size_t i = 0; i < kDifGpioNumPins; ++i) {
235  // Assume that the pins in dt_gpio_pin_t are numbered 0, 1, and so on.
236  dt_periph_io_t periph_io =
237  dt_gpio_periph_io(kGpioDt, kDtGpioPeriphIoGpio0 + i);
238  dt_pad_t pad = kPinmuxTestutilsGpioPads[i];
239  CHECK_STATUS_OK(
240  pinmux_testutils_connect(&pinmux, periph_io, kDtPeriphIoDirInout, pad));
241  }
242 }
243 
244 bool test_main(void) {
245  // Initialize the pinmux.
246  CHECK_DIF_OK(dif_pinmux_init_from_dt(kPinmuxDt, &pinmux));
247  pinmux_testutils_init(&pinmux);
248  configure_pinmux();
249 
250  // Initialize the GPIO.
251  CHECK_DIF_OK(dif_gpio_init_from_dt(kGpioDt, &gpio));
252 
253  // Initialize the PLIC.
254  CHECK_DIF_OK(dif_rv_plic_init_from_dt(kRvPlicDt, &plic));
255  // Here we assume that the IRQs are numbered 0, 1, so that they correspond to
256  // GPIO numbers.
257  dt_plic_irq_id_t first_irq = dt_gpio_irq_to_plic_id(kGpioDt, kDtGpioIrqGpio0);
258  rv_plic_testutils_irq_range_enable(&plic, kPlicTarget, first_irq,
259  first_irq + kDifGpioNumPins - 1);
260 
261  // Enable the external IRQ at Ibex.
262  irq_global_ctrl(true);
263  irq_external_ctrl(true);
264 
265  // Run the tests.
266  uint32_t gpio_mask = pinmux_testutils_get_testable_gpios_mask();
267  gpio_output_test(&gpio, gpio_mask);
268  gpio_input_test(&gpio, gpio_mask);
269 
270  return true;
271 }