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