Software APIs
gpio_intr_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 #include <stdbool.h>
6 #include <stdint.h>
7 
8 #include "sw/device/lib/base/status.h"
14 #include "sw/device/lib/runtime/irq.h"
16 #include "sw/device/lib/testing/json/command.h"
17 #include "sw/device/lib/testing/json/gpio.h"
18 #include "sw/device/lib/testing/json/pinmux_config.h"
19 #include "sw/device/lib/testing/rv_plic_testutils.h"
20 #include "sw/device/lib/testing/test_framework/check.h"
21 #include "sw/device/lib/testing/test_framework/ottf_isrs.h"
23 #include "sw/device/lib/testing/test_framework/ujson_ottf.h"
24 #include "sw/device/lib/ujson/ujson.h"
25 
27 
28 OTTF_DEFINE_TEST_CONFIG(.enable_uart_flow_control = true);
29 
30 static dif_gpio_t gpio;
31 static dif_pinmux_t pinmux;
32 static dif_uart_t uart0;
33 static dif_rv_plic_t plic;
34 static const uint32_t kExpected_intr[] = {17, 18, 19, 20, 21,
35  22, 25, 26, 27, 28};
36 static uint32_t intr_index = 0;
37 
38 status_t command_processor(ujson_t *uj) {
39  while (true) {
40  test_command_t command;
41  TRY(ujson_deserialize_test_command_t(uj, &command));
42  switch (command) {
43  case kTestCommandGpioSet:
44  RESP_ERR(uj, gpio_set(uj, &gpio));
45  break;
46  case kTestCommandGpioGet:
47  RESP_ERR(uj, gpio_get(uj, &gpio));
48  break;
49  case kTestCommandPinmuxConfig:
50  RESP_ERR(uj, pinmux_config(uj, &pinmux));
51  break;
52  default:
53  LOG_ERROR("Unrecognized command: %d", command);
54  RESP_ERR(uj, INVALID_ARGUMENT());
55  }
56  }
57  // We should never reach here.
58  return INTERNAL();
59 }
60 
61 /**
62  * Provides external irq handling for this test.
63  *
64  * This function overrides the default OTTF external ISR.
65  */
66 
67 void ottf_external_isr(uint32_t *exc_info) {
68  // Find which interrupt fired at PLIC by claiming it.
69  dif_rv_plic_irq_id_t plic_irq_id;
70  CHECK_DIF_OK(
72  // Check if it is the right peripheral.
75 
76  // Hyper debug tests get uart interrupt by design.
77  // Filter uart interrupt.
78  if (peripheral == kTopEarlgreyPlicPeripheralUart0) {
79  // Complete the IRQ at PLIC.
81  plic_irq_id));
82  return;
83  }
84 
85  // For each test, interrupt triggers in order.
86  // Once all interrupts are triggered, `intr_index` will be set to 0 for the
87  // next test.
88  if (peripheral == kTopEarlgreyPlicPeripheralGpio) {
89  // Correlate the interrupt fired from GPIO.
90  uint32_t gpio_pin_irq_fired = plic_irq_id - kTopEarlgreyPlicIrqIdGpioGpio0;
91  CHECK(gpio_pin_irq_fired == kExpected_intr[intr_index],
92  "Unexpected interrupt rcv:%d exp:%d", gpio_pin_irq_fired,
93  kExpected_intr[intr_index]);
94  intr_index += 1;
95  if (intr_index == ARRAYSIZE(kExpected_intr)) {
96  intr_index = 0;
97  LOG_INFO("index back to 0");
98  }
99 
100  // To test low frequency level interrupt,
101  // handler need to disable interrupt before it clear.
102  // Interrupt is enabled by the host right before the test.
103  // Disable and clear the interrupt at GPIO.
104  CHECK_DIF_OK(dif_gpio_irq_set_enabled(&gpio, gpio_pin_irq_fired,
106  CHECK_DIF_OK(dif_gpio_irq_acknowledge(&gpio, gpio_pin_irq_fired));
108  plic_irq_id));
109  }
110 }
111 
112 bool test_main(void) {
113  CHECK_DIF_OK(dif_pinmux_init(
115  CHECK_DIF_OK(
116  dif_gpio_init(mmio_region_from_addr(TOP_EARLGREY_GPIO_BASE_ADDR), &gpio));
117  CHECK_DIF_OK(dif_rv_plic_init(
119  CHECK_DIF_OK(dif_uart_init(
121 
122  rv_plic_testutils_irq_range_enable(
125 
126  // Anker for the host
127  LOG_INFO("gpio_intr_test ");
128 
129  ujson_t uj = ujson_ottf_console();
130 
131  status_t s = command_processor(&uj);
132  LOG_INFO("status = %r", s);
133  return status_ok(s);
134 }