opentitanlib/test_utils/
gpio.rs

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
5use anyhow::Result;
6use std::time::Duration;
7
8use ot_hal::top::earlgrey::{PinmuxOutsel, PinmuxPeripheralIn};
9
10use crate::io::uart::Uart;
11use crate::test_utils::e2e_command::TestCommand;
12use crate::test_utils::rpc::{ConsoleRecv, ConsoleSend};
13use crate::test_utils::status::Status;
14
15// Bring in the auto-generated sources.
16include!(env!("gpio"));
17
18/// Number of pins of each GPIO instance.
19pub const GPIO_PINS: u32 = 32;
20
21/// Pinmux peripheral input and output select of pin 0 of each GPIO instance.
22pub static GPIO_INSTANCES: [(PinmuxPeripheralIn, PinmuxOutsel); 2] = [
23    (PinmuxPeripheralIn::Gpio0Gpio0, PinmuxOutsel::Gpio0Gpio0),
24    (PinmuxPeripheralIn::Gpio1Gpio0, PinmuxOutsel::Gpio1Gpio0),
25];
26
27/// Returns the pinmux peripheral input of a pin of a GPIO instance.
28pub fn peripheral_in(instance: u8, pin: u32) -> PinmuxPeripheralIn {
29    assert!(pin < GPIO_PINS, "GPIO pin {pin} out of range");
30    let (base, _) = GPIO_INSTANCES[usize::from(instance)];
31    PinmuxPeripheralIn(u32::from(base) + pin)
32}
33
34/// Returns the pinmux output select of a pin of a GPIO instance.
35pub fn outsel(instance: u8, pin: u32) -> PinmuxOutsel {
36    assert!(pin < GPIO_PINS, "GPIO pin {pin} out of range");
37    let (_, base) = GPIO_INSTANCES[usize::from(instance)];
38    PinmuxOutsel(u32::from(base) + pin)
39}
40
41/// Returns the pin index of a GPIO peripheral input within its GPIO instance.
42pub fn input_pin(input: PinmuxPeripheralIn) -> u32 {
43    GPIO_INSTANCES
44        .iter()
45        .map(|(base, _)| u32::from(input).wrapping_sub(u32::from(*base)))
46        .find(|i| *i < GPIO_PINS)
47        .expect("not a GPIO peripheral input")
48}
49
50/// Returns the pin index of a GPIO output select within its GPIO instance.
51pub fn output_pin(output: PinmuxOutsel) -> u32 {
52    GPIO_INSTANCES
53        .iter()
54        .map(|(_, base)| u32::from(output).wrapping_sub(u32::from(*base)))
55        .find(|i| *i < GPIO_PINS)
56        .expect("not a GPIO output select")
57}
58
59impl GpioSet {
60    fn execute(&self, uart: &dyn Uart) -> Result<()> {
61        TestCommand::GpioSet.send(uart)?;
62        self.send(uart)?;
63        Status::recv(uart, Duration::from_secs(300), false, false)?;
64        Ok(())
65    }
66
67    pub fn write(uart: &dyn Uart, instance: u8, pin: u32, state: bool) -> Result<()> {
68        let payload = GpioSet {
69            instance,
70            action: GpioAction::Write,
71            pin_mask: pin,
72            state: state.into(),
73        };
74        payload.execute(uart)
75    }
76    pub fn set_enabled(uart: &dyn Uart, instance: u8, pin: u32, state: bool) -> Result<()> {
77        let payload = GpioSet {
78            instance,
79            action: GpioAction::SetEnabled,
80            pin_mask: pin,
81            state: state.into(),
82        };
83        payload.execute(uart)
84    }
85
86    pub fn write_all(uart: &dyn Uart, instance: u8, state: u32) -> Result<()> {
87        let payload = GpioSet {
88            instance,
89            action: GpioAction::WriteAll,
90            pin_mask: 0,
91            state,
92        };
93        payload.execute(uart)
94    }
95    pub fn set_enabled_all(uart: &dyn Uart, instance: u8, state: u32) -> Result<()> {
96        let payload = GpioSet {
97            instance,
98            action: GpioAction::SetEnabledAll,
99            pin_mask: 0,
100            state,
101        };
102        payload.execute(uart)
103    }
104
105    pub fn write_masked(uart: &dyn Uart, instance: u8, mask: u32, state: u32) -> Result<()> {
106        let payload = GpioSet {
107            instance,
108            action: GpioAction::WriteMasked,
109            pin_mask: mask,
110            state,
111        };
112        payload.execute(uart)
113    }
114    pub fn set_enabled_masked(uart: &dyn Uart, instance: u8, mask: u32, state: u32) -> Result<()> {
115        let payload = GpioSet {
116            instance,
117            action: GpioAction::SetEnabledMasked,
118            pin_mask: mask,
119            state,
120        };
121        payload.execute(uart)
122    }
123    pub fn set_input_noise_filter(
124        uart: &dyn Uart,
125        instance: u8,
126        mask: u32,
127        state: u32,
128    ) -> Result<()> {
129        let payload = GpioSet {
130            instance,
131            action: GpioAction::SetInputNoiseFilter,
132            pin_mask: mask,
133            state,
134        };
135        payload.execute(uart)
136    }
137    pub fn irq_restore_all(uart: &dyn Uart, instance: u8, state: u32) -> Result<()> {
138        let payload = GpioSet {
139            instance,
140            action: GpioAction::IrqRestoreAll,
141            pin_mask: 0,
142            state,
143        };
144        payload.execute(uart)
145    }
146    pub fn irq_disable_all(uart: &dyn Uart, instance: u8, state: u32) -> Result<()> {
147        let payload = GpioSet {
148            instance,
149            action: GpioAction::IrqDisableAll,
150            pin_mask: 0,
151            state,
152        };
153        payload.execute(uart)
154    }
155    pub fn irq_acknowledge_all(uart: &dyn Uart, instance: u8) -> Result<()> {
156        let payload = GpioSet {
157            instance,
158            action: GpioAction::IrqAcknowledgeAll,
159            pin_mask: 0,
160            state: 0,
161        };
162        payload.execute(uart)
163    }
164    pub fn irq_set_trigger(
165        uart: &dyn Uart,
166        instance: u8,
167        state: u32,
168        trigger: String,
169    ) -> Result<()> {
170        match trigger.as_str() {
171            "rising" => {
172                let payload = GpioSet {
173                    instance,
174                    action: GpioAction::IrqSetTriggerRisingEdge,
175                    pin_mask: 0,
176                    state,
177                };
178                payload.execute(uart)
179            }
180            "falling" => {
181                let payload = GpioSet {
182                    instance,
183                    action: GpioAction::IrqSetTriggerFallingEdge,
184                    pin_mask: 0,
185                    state,
186                };
187                payload.execute(uart)
188            }
189            "high" => {
190                let payload = GpioSet {
191                    instance,
192                    action: GpioAction::IrqSetTriggerHigh,
193                    pin_mask: 0,
194                    state,
195                };
196                payload.execute(uart)
197            }
198            "low" => {
199                let payload = GpioSet {
200                    instance,
201                    action: GpioAction::IrqSetTriggerLow,
202                    pin_mask: 0,
203                    state,
204                };
205                payload.execute(uart)
206            }
207            _ => {
208                log::error!("unsupport trigger: {:?}", trigger);
209                Ok(())
210            }
211        }
212    }
213}
214
215impl GpioGet {
216    pub fn read_all(uart: &dyn Uart, instance: u8) -> Result<u32> {
217        TestCommand::GpioGet.send(uart)?;
218        GpioGetRequest { instance }.send(uart)?;
219        let data = GpioGet::recv(uart, Duration::from_secs(300), false, false)?;
220        Ok(data.state)
221    }
222}