earlgrey/
gpio.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! GPIO instantiation.
6
7use core::ops::{Index, IndexMut};
8
9use kernel::utilities::StaticRef;
10use lowrisc::gpio::GpioRegisters;
11pub use lowrisc::gpio::{pins, GpioBitfield, GpioPin};
12
13use crate::pinmux::PadConfig;
14use crate::pinmux_config::EarlGreyPinmuxConfig;
15use crate::registers::top_earlgrey::GPIO_BASE_ADDR;
16use crate::registers::top_earlgrey::{
17    MuxedPads, PinmuxInsel, PinmuxOutsel, PinmuxPeripheralIn, PINMUX_MIO_PERIPH_INSEL_IDX_OFFSET,
18};
19
20pub const GPIO_BASE: StaticRef<GpioRegisters> =
21    unsafe { StaticRef::new(GPIO_BASE_ADDR as *const GpioRegisters) };
22
23pub struct Port<'a> {
24    pins: [GpioPin<'a, PadConfig>; 32],
25}
26
27impl From<PinmuxPeripheralIn> for PinmuxOutsel {
28    fn from(pin: PinmuxPeripheralIn) -> Self {
29        match pin {
30            PinmuxPeripheralIn::GpioGpio0 => PinmuxOutsel::GpioGpio0,
31            PinmuxPeripheralIn::GpioGpio1 => PinmuxOutsel::GpioGpio1,
32            PinmuxPeripheralIn::GpioGpio2 => PinmuxOutsel::GpioGpio2,
33            PinmuxPeripheralIn::GpioGpio3 => PinmuxOutsel::GpioGpio3,
34            PinmuxPeripheralIn::GpioGpio4 => PinmuxOutsel::GpioGpio4,
35            PinmuxPeripheralIn::GpioGpio5 => PinmuxOutsel::GpioGpio5,
36            PinmuxPeripheralIn::GpioGpio6 => PinmuxOutsel::GpioGpio6,
37            PinmuxPeripheralIn::GpioGpio7 => PinmuxOutsel::GpioGpio7,
38            PinmuxPeripheralIn::GpioGpio8 => PinmuxOutsel::GpioGpio8,
39            PinmuxPeripheralIn::GpioGpio9 => PinmuxOutsel::GpioGpio9,
40            PinmuxPeripheralIn::GpioGpio10 => PinmuxOutsel::GpioGpio10,
41            PinmuxPeripheralIn::GpioGpio11 => PinmuxOutsel::GpioGpio11,
42            PinmuxPeripheralIn::GpioGpio12 => PinmuxOutsel::GpioGpio12,
43            PinmuxPeripheralIn::GpioGpio13 => PinmuxOutsel::GpioGpio13,
44            PinmuxPeripheralIn::GpioGpio14 => PinmuxOutsel::GpioGpio14,
45            PinmuxPeripheralIn::GpioGpio15 => PinmuxOutsel::GpioGpio15,
46            PinmuxPeripheralIn::GpioGpio16 => PinmuxOutsel::GpioGpio16,
47            PinmuxPeripheralIn::GpioGpio17 => PinmuxOutsel::GpioGpio17,
48            PinmuxPeripheralIn::GpioGpio18 => PinmuxOutsel::GpioGpio18,
49            PinmuxPeripheralIn::GpioGpio19 => PinmuxOutsel::GpioGpio19,
50            PinmuxPeripheralIn::GpioGpio20 => PinmuxOutsel::GpioGpio20,
51            PinmuxPeripheralIn::GpioGpio21 => PinmuxOutsel::GpioGpio21,
52            PinmuxPeripheralIn::GpioGpio22 => PinmuxOutsel::GpioGpio22,
53            PinmuxPeripheralIn::GpioGpio23 => PinmuxOutsel::GpioGpio23,
54            PinmuxPeripheralIn::GpioGpio24 => PinmuxOutsel::GpioGpio24,
55            PinmuxPeripheralIn::GpioGpio25 => PinmuxOutsel::GpioGpio25,
56            PinmuxPeripheralIn::GpioGpio26 => PinmuxOutsel::GpioGpio26,
57            PinmuxPeripheralIn::GpioGpio27 => PinmuxOutsel::GpioGpio27,
58            PinmuxPeripheralIn::GpioGpio28 => PinmuxOutsel::GpioGpio28,
59            PinmuxPeripheralIn::GpioGpio29 => PinmuxOutsel::GpioGpio29,
60            PinmuxPeripheralIn::GpioGpio30 => PinmuxOutsel::GpioGpio30,
61            PinmuxPeripheralIn::GpioGpio31 => PinmuxOutsel::GpioGpio31,
62            _ => PinmuxOutsel::ConstantHighZ,
63        }
64    }
65}
66
67// This function use extract GPIO mapping from initial pinmux configurations
68pub fn gpio_pad_config<Layout: EarlGreyPinmuxConfig>(pin: PinmuxPeripheralIn) -> PadConfig {
69    match Layout::INPUT[pin as usize] {
70        // Current implementation don't support Output only GPIO
71        PinmuxInsel::ConstantZero | PinmuxInsel::ConstantOne => PadConfig::Unconnected,
72        input_selector => {
73            if let Ok(pad) = MuxedPads::try_from(
74                input_selector as u32 - PINMUX_MIO_PERIPH_INSEL_IDX_OFFSET as u32,
75            ) {
76                let out: PinmuxOutsel = Layout::OUTPUT[pad as usize];
77                // Checking for bi-directional I/O
78                if out == PinmuxOutsel::from(pin) {
79                    PadConfig::InOut(pad, pin, out)
80                } else {
81                    PadConfig::Input(pad, pin)
82                }
83            } else {
84                // Upper match checked for unconnected pad so in this
85                // place we probably have some invalid value in INPUT array.
86                PadConfig::Unconnected
87            }
88        }
89    }
90}
91
92// Configuring first all GPIO based on board layout
93impl Port<'_> {
94    pub fn new<Layout: EarlGreyPinmuxConfig>() -> Self {
95        Self {
96            // Intentionally prevent splitting GpioPin to multiple line
97            #[rustfmt::skip]
98            pins: [
99                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio0), pins::pin0),
100                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio1), pins::pin1),
101                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio2), pins::pin2),
102                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio3), pins::pin3),
103                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio4), pins::pin4),
104                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio5), pins::pin5),
105                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio6), pins::pin6),
106                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio7), pins::pin7),
107                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio8), pins::pin8),
108                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio9), pins::pin9),
109                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio10), pins::pin10),
110                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio11), pins::pin11),
111                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio12), pins::pin12),
112                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio13), pins::pin13),
113                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio14), pins::pin14),
114                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio15), pins::pin15),
115                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio16), pins::pin16),
116                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio17), pins::pin17),
117                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio18), pins::pin18),
118                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio19), pins::pin19),
119                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio20), pins::pin20),
120                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio21), pins::pin21),
121                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio22), pins::pin22),
122                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio23), pins::pin23),
123                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio24), pins::pin24),
124                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio25), pins::pin25),
125                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio26), pins::pin26),
126                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio27), pins::pin27),
127                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio28), pins::pin28),
128                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio29), pins::pin29),
129                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio30), pins::pin30),
130                GpioPin::new(GPIO_BASE, gpio_pad_config::<Layout>(PinmuxPeripheralIn::GpioGpio31), pins::pin31),
131            ],
132        }
133    }
134}
135
136impl<'a> Index<usize> for Port<'a> {
137    type Output = GpioPin<'a, PadConfig>;
138
139    fn index(&self, index: usize) -> &GpioPin<'a, PadConfig> {
140        &self.pins[index]
141    }
142}
143
144impl<'a> IndexMut<usize> for Port<'a> {
145    fn index_mut(&mut self, index: usize) -> &mut GpioPin<'a, PadConfig> {
146        &mut self.pins[index]
147    }
148}