opentitanlib/test_utils/
pinmux_config.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 std::cmp;
6use std::collections::HashMap;
7use std::time::Duration;
8
9use anyhow::Result;
10
11use ot_hal::dif::pinmux::PinmuxPadAttr;
12use ot_hal::top::earlgrey::{PinmuxInsel, PinmuxMioOut, PinmuxOutsel, PinmuxPeripheralIn};
13
14use crate::io::uart::Uart;
15use crate::test_utils::e2e_command::TestCommand;
16use crate::test_utils::rpc::{ConsoleRecv, ConsoleSend};
17use crate::test_utils::status::Status;
18
19// Create aliases for the C names of these types so that the ujson
20// created structs can access these structures by their C names.
21#[allow(non_camel_case_types)]
22type pinmux_peripheral_in_t = PinmuxPeripheralIn;
23#[allow(non_camel_case_types)]
24type pinmux_insel_t = PinmuxInsel;
25#[allow(non_camel_case_types)]
26type pinmux_mio_out_t = PinmuxMioOut;
27#[allow(non_camel_case_types)]
28type pinmux_outsel_t = PinmuxOutsel;
29
30// Bring in the auto-generated sources.
31include!(env!("pinmux_config"));
32
33/// Capacity of a single configuration message.
34const CONFIG_CAP: usize = 16;
35
36impl PinmuxConfig {
37    pub fn configure(
38        uart: &dyn Uart,
39        inputs: Option<&HashMap<PinmuxPeripheralIn, PinmuxInsel>>,
40        outputs: Option<&HashMap<PinmuxMioOut, PinmuxOutsel>>,
41        attrs: Option<&HashMap<PinmuxMioOut, PinmuxPadAttr>>,
42    ) -> Result<()> {
43        // The PinmuxConfig struct can carry a limited number of input
44        // and output configurations.  We'll take the whole config and
45        // chunk it into as many PinmuxConfig commands as necessary.
46
47        let mut inputs: Vec<_> = inputs
48            .into_iter()
49            .flat_map(HashMap::iter)
50            .map(|(&key, &value)| (key, value))
51            .collect();
52        let mut outputs: Vec<_> = outputs
53            .into_iter()
54            .flat_map(HashMap::iter)
55            .map(|(&key, &value)| (key, value))
56            .collect();
57        let mut attrs: Vec<_> = attrs
58            .into_iter()
59            .flat_map(HashMap::iter)
60            .map(|(&key, &value)| (key, value.bits()))
61            .collect();
62
63        let len = cmp::max(cmp::max(inputs.len(), outputs.len()), attrs.len())
64            .next_multiple_of(CONFIG_CAP);
65
66        inputs.resize_with(len, Default::default);
67        outputs.resize_with(len, Default::default);
68        attrs.resize_with(len, Default::default);
69
70        while !inputs.is_empty() && !outputs.is_empty() && !attrs.is_empty() {
71            let (in_peripherals, in_selectors) = inputs.drain(..CONFIG_CAP).unzip();
72            let (out_mios, out_selectors) = outputs.drain(..CONFIG_CAP).unzip();
73            let (attr_mios, attr_flags) = attrs.drain(..CONFIG_CAP).unzip();
74
75            let config = PinmuxConfig {
76                input: PinmuxInputSelection {
77                    peripheral: in_peripherals,
78                    selector: in_selectors,
79                },
80                output: PinmuxOutputSelection {
81                    mio: out_mios,
82                    selector: out_selectors,
83                },
84                attrs: PinmuxAttrConfig {
85                    mio: attr_mios,
86                    flags: attr_flags,
87                },
88            };
89
90            TestCommand::PinmuxConfig.send(uart)?;
91            config.send(uart)?;
92            Status::recv(uart, Duration::from_secs(300), false)?;
93        }
94
95        Ok(())
96    }
97}