peripherals/gpio: port AST1060 GPIO driver from aspeed-rust Add gpio peripheral driver to ast10x0_peripherals crate, ported from aspeed-rust/src/gpio.rs. Follows the crate's established driver pattern: - types.rs: type states (Input, Output, PushPull, OpenDrain, PullUp, PullDown, Floating, Tristate), mode traits, InterruptMode, GpioExt, GpioError - registers.rs: GpioRegisters wrapping *const gpio::RegisterBlock with PhantomData<*const ()>, unsafe new(ptr) and new_global() constructors - mod.rs: gpio_macro! adapted to use GpioRegisters; all 21 bank instantiations A-U Update lib.rs and BUILD.bazel accordingly.
diff --git a/target/ast10x0/peripherals/BUILD.bazel b/target/ast10x0/peripherals/BUILD.bazel index 09db01b..5e10fb2 100644 --- a/target/ast10x0/peripherals/BUILD.bazel +++ b/target/ast10x0/peripherals/BUILD.bazel
@@ -9,6 +9,9 @@ rust_library( name = "peripherals", srcs = [ + "gpio/mod.rs", + "gpio/registers.rs", + "gpio/types.rs", "hace/aes.rs", "hace/constants.rs", "hace/context.rs",
diff --git a/target/ast10x0/peripherals/gpio/mod.rs b/target/ast10x0/peripherals/gpio/mod.rs new file mode 100644 index 0000000..5a91cef --- /dev/null +++ b/target/ast10x0/peripherals/gpio/mod.rs
@@ -0,0 +1,675 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! AST10x0 GPIO peripheral driver. +//! +//! Each GPIO bank (A–U) is exposed as a sub-module (`gpioa`, `gpiob`, …). +//! Obtain a bank via `GPIOX::new_global()` (unsafe), then call `split()` to +//! get the individual typed pins. + +mod registers; +mod types; + +pub use registers::GpioRegisters; +pub use types::{ + Floating, GpioError, GpioExt, Input, InputMode, InterruptMode, OpenDrain, OpenDrainMode, + Output, OutputMode, PullDown, PullUp, PushPull, Tristate, +}; + +macro_rules! gpio_macro { + ($GPIOX:ident, $gpiox:ident, $x:literal, $pos:literal, $data_val_reg:ident, + $dir_reg:ident, $int_en_reg:ident, $int_sen_t0:ident, + $int_sen_t1:ident, $int_sen_t2:ident, $int_sts_reg:ident, + $rst_tolerant_reg:ident, $deb1_reg:ident, $deb2_reg:ident, + $cmd_src0_reg:ident, $cmd_src1_reg:ident, $data_read_reg:ident, + $intput_mask_reg:ident, [ + $($PXi:ident: ($pxi:ident, $i:literal, $MODE:ty),)+ + ]) => { + + pub mod $gpiox { + use super::*; + use ast1060_pac as device; + use core::marker::PhantomData; + use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin}; + + pub struct $GPIOX { + _regs: GpioRegisters, + } + + impl $GPIOX { + /// Create a GPIO bank instance from a [`GpioRegisters`] handle. + /// + /// # Safety + /// + /// Caller must ensure exclusive access to the GPIO register block is + /// coordinated for the lifetime of this value. + pub const unsafe fn new(regs: GpioRegisters) -> Self { + Self { _regs: regs } + } + + /// Create a GPIO bank instance using the global GPIO register block. + /// + /// # Safety + /// + /// Caller must ensure exclusive access to the singleton GPIO peripheral + /// is coordinated for the lifetime of this value. + pub unsafe fn new_global() -> Self { + Self { + _regs: unsafe { GpioRegisters::new_global() }, + } + } + + /// Initialize command-source and debounce registers for this bank. + pub fn init(&self) { + let p = self._regs.regs(); + p.$cmd_src0_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(0xff << $pos)) + }); + p.$cmd_src1_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(0xff << $pos)) + }); + p.$deb1_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(0xff << $pos)) + }); + p.$deb2_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(0xff << $pos)) + }); + } + } + + pub struct Parts { + $( + pub $pxi: $PXi<$MODE>, + )+ + } + + impl GpioExt for $GPIOX { + type Parts = Parts; + + fn split(self) -> Self::Parts { + Parts { + $( + $pxi: $PXi { + _mode: PhantomData, + }, + )+ + } + } + } + + $( + pub struct $PXi<MODE> { + _mode: PhantomData<MODE>, + } + + impl<MODE> $PXi<MODE> { + /// Configures the pin as a pulled-down input. + #[must_use] + pub fn into_pull_down_input(self) -> $PXi<Input<PullDown>> { + let p = unsafe { &*device::Gpio::ptr() }; + p.$dir_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$data_val_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + $PXi { _mode: PhantomData } + } + + /// Configures the pin as a pulled-up input. + #[must_use] + pub fn into_pull_up_input(self) -> $PXi<Input<PullUp>> { + let p = unsafe { &*device::Gpio::ptr() }; + p.$dir_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$data_val_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + $PXi { _mode: PhantomData } + } + + /// Configures the pin as an open-drain output. + #[must_use] + pub fn into_open_drain_output<ODM>(self) -> $PXi<Output<OpenDrain<ODM>>> + where + ODM: OpenDrainMode, + { + let p = unsafe { &*device::Gpio::ptr() }; + p.$data_val_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + p.$dir_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + $PXi { _mode: PhantomData } + } + + /// Configures the pin as a push-pull output. + #[must_use] + pub fn into_push_pull_output(self) -> $PXi<Output<PushPull>> { + let p = unsafe { &*device::Gpio::ptr() }; + p.$dir_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + p.$data_val_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + $PXi { _mode: PhantomData } + } + } + + impl<MODE> StatefulOutputPin for $PXi<Output<MODE>> + where + MODE: OutputMode, + { + fn is_set_high(&mut self) -> Result<bool, Self::Error> { + let p = unsafe { &*device::Gpio::ptr() }; + Ok( + (p.$data_read_reg().read().bits() & (1u32 << ($pos + $i))) + == (1u32 << ($pos + $i)), + ) + } + + fn is_set_low(&mut self) -> Result<bool, Self::Error> { + self.is_set_high().map(|v| !v) + } + } + + impl<MODE> OutputPin for $PXi<Output<MODE>> + where + MODE: OutputMode, + { + fn set_high(&mut self) -> Result<(), Self::Error> { + let p = unsafe { &*device::Gpio::ptr() }; + p.$data_val_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + Ok(()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + let p = unsafe { &*device::Gpio::ptr() }; + p.$data_val_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + Ok(()) + } + } + + impl<MODE> InputPin for $PXi<Input<MODE>> + where + MODE: InputMode, + { + fn is_high(&mut self) -> Result<bool, Self::Error> { + let p = unsafe { &*device::Gpio::ptr() }; + Ok( + (p.$data_read_reg().read().bits() & (1u32 << ($pos + $i))) + == (1u32 << ($pos + $i)), + ) + } + + fn is_low(&mut self) -> Result<bool, Self::Error> { + self.is_high().map(|v| !v) + } + } + + impl<MODE> $PXi<Input<MODE>> + where + MODE: InputMode, + { + /// Enable or disable interrupts on this pin. + pub fn set_interrupt_mode(&mut self, mode: InterruptMode) { + let p = unsafe { &*device::Gpio::ptr() }; + match mode { + InterruptMode::LevelHigh => { + p.$int_sen_t0().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + p.$int_sen_t1().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + p.$int_sen_t2().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$int_en_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + } + InterruptMode::LevelLow => { + p.$int_sen_t0().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$int_sen_t1().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + p.$int_sen_t2().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$int_en_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + } + InterruptMode::EdgeRising => { + p.$int_sen_t0().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + p.$int_sen_t1().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$int_sen_t2().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$int_en_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + } + InterruptMode::EdgeFalling => { + p.$int_sen_t0().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$int_sen_t1().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + p.$int_sen_t2().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + // Note: original uses `| !` (OR with NOT) here, preserved + // faithfully. + p.$int_en_reg().modify(|r, w| unsafe { + w.bits(r.bits() | !(1u32 << ($pos + $i))) + }); + } + InterruptMode::EdgeBoth => { + p.$int_sen_t2().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + p.$int_en_reg().modify(|r, w| unsafe { + w.bits(r.bits() | (1u32 << ($pos + $i))) + }); + } + InterruptMode::Disabled => { + p.$int_en_reg().modify(|r, w| unsafe { + w.bits(r.bits() & !(1u32 << ($pos + $i))) + }); + } + } + } + + /// Returns the current interrupt-pending status for this pin. + #[must_use] + pub fn get_interrupt_status(&self) -> bool { + let p = unsafe { &*device::Gpio::ptr() }; + (p.$int_sts_reg().read().bits() & (1u32 << ($pos + $i))) + == (1u32 << ($pos + $i)) + } + + /// Clear the pending interrupt for this pin. + pub fn clear_interrupt(&self) { + let p = unsafe { &*device::Gpio::ptr() }; + p.$int_sts_reg().write(|w| unsafe { w.bits(1u32 << ($pos + $i)) }); + } + + /// Set the command-source bits for this pin. + pub fn set_cmd_src(&self, cmd_src0: u32, cmd_src1: u32) { + let p = unsafe { &*device::Gpio::ptr() }; + p.$cmd_src0_reg().modify(|r, w| unsafe { + w.bits( + (r.bits() & !(1u32 << ($pos + $i))) + | (cmd_src0 << ($pos + $i)), + ) + }); + p.$cmd_src1_reg().modify(|r, w| unsafe { + w.bits( + (r.bits() & !(1u32 << ($pos + $i))) + | (cmd_src1 << ($pos + $i)), + ) + }); + } + + /// Select the debounce timer for this pin. + pub fn select_debounce_timer(&self, deb_setting1: u32, deb_setting2: u32) { + let p = unsafe { &*device::Gpio::ptr() }; + p.$deb1_reg().modify(|r, w| unsafe { + w.bits( + (r.bits() & !(1u32 << ($pos + $i))) + | (deb_setting1 << ($pos + $i)), + ) + }); + p.$deb2_reg().modify(|r, w| unsafe { + w.bits( + (r.bits() & !(1u32 << ($pos + $i))) + | (deb_setting2 << ($pos + $i)), + ) + }); + } + } + + impl<MODE> embedded_hal::digital::ErrorType for $PXi<MODE> { + type Error = GpioError; + } + )+ + } + }; +} + +// GPIO ABCD — register group 0x000–0x01c +gpio_macro!( + GPIOA, gpioa, 'a', 0, gpio000, gpio004, gpio008, gpio00c, gpio010, gpio014, gpio018, + gpio01c, gpio040, gpio044, gpio060, gpio064, gpio0c0, gpio1d0, + [ + PA0: (pa0, 0, Tristate), + PA1: (pa1, 1, Tristate), + PA2: (pa2, 2, Tristate), + PA3: (pa3, 3, Tristate), + PA4: (pa4, 4, Tristate), + PA5: (pa5, 5, Tristate), + PA6: (pa6, 6, Tristate), + PA7: (pa7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOB, gpiob, 'b', 8, gpio000, gpio004, gpio008, gpio00c, gpio010, gpio014, gpio018, + gpio01c, gpio040, gpio044, gpio060, gpio064, gpio0c0, gpio1d0, + [ + PB0: (pb0, 0, Tristate), + PB1: (pb1, 1, Tristate), + PB2: (pb2, 2, Tristate), + PB3: (pb3, 3, Tristate), + PB4: (pb4, 4, Tristate), + PB5: (pb5, 5, Tristate), + PB6: (pb6, 6, Tristate), + PB7: (pb7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOC, gpioc, 'c', 16, gpio000, gpio004, gpio008, gpio00c, gpio010, gpio014, gpio018, + gpio01c, gpio040, gpio044, gpio060, gpio064, gpio0c0, gpio1d0, + [ + PC0: (pc0, 0, Tristate), + PC1: (pc1, 1, Tristate), + PC2: (pc2, 2, Tristate), + PC3: (pc3, 3, Tristate), + PC4: (pc4, 4, Tristate), + PC5: (pc5, 5, Tristate), + PC6: (pc6, 6, Tristate), + PC7: (pc7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOD, gpiod, 'd', 24, gpio000, gpio004, gpio008, gpio00c, gpio010, gpio014, gpio018, + gpio01c, gpio040, gpio044, gpio060, gpio064, gpio0c0, gpio1d0, + [ + PD0: (pd0, 0, Tristate), + PD1: (pd1, 1, Tristate), + PD2: (pd2, 2, Tristate), + PD3: (pd3, 3, Tristate), + PD4: (pd4, 4, Tristate), + PD5: (pd5, 5, Tristate), + PD6: (pd6, 6, Tristate), + PD7: (pd7, 7, Tristate), + ] +); + +// GPIO EFGH — register group 0x020–0x03c +gpio_macro!( + GPIOE, gpioe, 'e', 0, gpio020, gpio024, gpio028, gpio02c, gpio030, gpio034, gpio038, + gpio03c, gpio048, gpio04c, gpio068, gpio06c, gpio0c4, gpio1d4, + [ + PE0: (pe0, 0, Tristate), + PE1: (pe1, 1, Tristate), + PE2: (pe2, 2, Tristate), + PE3: (pe3, 3, Tristate), + PE4: (pe4, 4, Tristate), + PE5: (pe5, 5, Tristate), + PE6: (pe6, 6, Tristate), + PE7: (pe7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOF, gpiof, 'f', 8, gpio020, gpio024, gpio028, gpio02c, gpio030, gpio034, gpio038, + gpio03c, gpio048, gpio04c, gpio068, gpio06c, gpio0c4, gpio1d4, + [ + PF0: (pf0, 0, Tristate), + PF1: (pf1, 1, Tristate), + PF2: (pf2, 2, Tristate), + PF3: (pf3, 3, Tristate), + PF4: (pf4, 4, Tristate), + PF5: (pf5, 5, Tristate), + PF6: (pf6, 6, Tristate), + PF7: (pf7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOG, gpiog, 'g', 16, gpio020, gpio024, gpio028, gpio02c, gpio030, gpio034, gpio038, + gpio03c, gpio048, gpio04c, gpio068, gpio06c, gpio0c4, gpio1d4, + [ + PG0: (pg0, 0, Tristate), + PG1: (pg1, 1, Tristate), + PG2: (pg2, 2, Tristate), + PG3: (pg3, 3, Tristate), + PG4: (pg4, 4, Tristate), + PG5: (pg5, 5, Tristate), + PG6: (pg6, 6, Tristate), + PG7: (pg7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOH, gpioh, 'h', 24, gpio020, gpio024, gpio028, gpio02c, gpio030, gpio034, gpio038, + gpio03c, gpio048, gpio04c, gpio068, gpio06c, gpio0c4, gpio1d4, + [ + PH0: (ph0, 0, Tristate), + PH1: (ph1, 1, Tristate), + PH2: (ph2, 2, Tristate), + PH3: (ph3, 3, Tristate), + PH4: (ph4, 4, Tristate), + PH5: (ph5, 5, Tristate), + PH6: (ph6, 6, Tristate), + PH7: (ph7, 7, Tristate), + ] +); + +// GPIO IJKL — register group 0x070–0x0b8 +gpio_macro!( + GPIOI, gpioi, 'i', 0, gpio070, gpio074, gpio098, gpio09c, gpio0a0, gpio0a4, gpio0a8, + gpio0ac, gpio0b0, gpio0b4, gpio090, gpio094, gpio0b8, gpio0c8, + [ + PI0: (pi0, 0, Tristate), + PI1: (pi1, 1, Tristate), + PI2: (pi2, 2, Tristate), + PI3: (pi3, 3, Tristate), + PI4: (pi4, 4, Tristate), + PI5: (pi5, 5, Tristate), + PI6: (pi6, 6, Tristate), + PI7: (pi7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOJ, gpioj, 'j', 8, gpio070, gpio074, gpio098, gpio09c, gpio0a0, gpio0a4, gpio0a8, + gpio0ac, gpio0b0, gpio0b4, gpio090, gpio094, gpio0b8, gpio0c8, + [ + PJ0: (pj0, 0, Tristate), + PJ1: (pj1, 1, Tristate), + PJ2: (pj2, 2, Tristate), + PJ3: (pj3, 3, Tristate), + PJ4: (pj4, 4, Tristate), + PJ5: (pj5, 5, Tristate), + PJ6: (pj6, 6, Tristate), + PJ7: (pj7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOK, gpiok, 'k', 16, gpio070, gpio074, gpio098, gpio09c, gpio0a0, gpio0a4, gpio0a8, + gpio0ac, gpio0b0, gpio0b4, gpio090, gpio094, gpio0b8, gpio0c8, + [ + PK0: (pk0, 0, Tristate), + PK1: (pk1, 1, Tristate), + PK2: (pk2, 2, Tristate), + PK3: (pk3, 3, Tristate), + PK4: (pk4, 4, Tristate), + PK5: (pk5, 5, Tristate), + PK6: (pk6, 6, Tristate), + PK7: (pk7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOL, gpiol, 'l', 24, gpio070, gpio074, gpio098, gpio09c, gpio0a0, gpio0a4, gpio0a8, + gpio0ac, gpio0b0, gpio0b4, gpio090, gpio094, gpio0b8, gpio0c8, + [ + PL0: (pl0, 0, Tristate), + PL1: (pl1, 1, Tristate), + PL2: (pl2, 2, Tristate), + PL3: (pl3, 3, Tristate), + PL4: (pl4, 4, Tristate), + PL5: (pl5, 5, Tristate), + PL6: (pl6, 6, Tristate), + PL7: (pl7, 7, Tristate), + ] +); + +// GPIO MNOP — register group 0x078–0x108 +gpio_macro!( + GPIOM, gpiom, 'm', 0, gpio078, gpio07c, gpio0e8, gpio0ec, gpio0f0, gpio0f4, gpio0f8, + gpio0fc, gpio100, gpio104, gpio0e0, gpio0e4, gpio0cc, gpio108, + [ + PM0: (pm0, 0, Tristate), + PM1: (pm1, 1, Tristate), + PM2: (pm2, 2, Tristate), + PM3: (pm3, 3, Tristate), + PM4: (pm4, 4, Tristate), + PM5: (pm5, 5, Tristate), + PM6: (pm6, 6, Tristate), + PM7: (pm7, 7, Tristate), + ] +); + +gpio_macro!( + GPION, gpion, 'n', 8, gpio078, gpio07c, gpio0e8, gpio0ec, gpio0f0, gpio0f4, gpio0f8, + gpio0fc, gpio100, gpio104, gpio0e0, gpio0e4, gpio0cc, gpio108, + [ + PN0: (pn0, 0, Tristate), + PN1: (pn1, 1, Tristate), + PN2: (pn2, 2, Tristate), + PN3: (pn3, 3, Tristate), + PN4: (pn4, 4, Tristate), + PN5: (pn5, 5, Tristate), + PN6: (pn6, 6, Tristate), + PN7: (pn7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOO, gpioo, 'o', 16, gpio078, gpio07c, gpio0e8, gpio0ec, gpio0f0, gpio0f4, gpio0f8, + gpio0fc, gpio100, gpio104, gpio0e0, gpio0e4, gpio0cc, gpio108, + [ + PO0: (po0, 0, Tristate), + PO1: (po1, 1, Tristate), + PO2: (po2, 2, Tristate), + PO3: (po3, 3, Tristate), + PO4: (po4, 4, Tristate), + PO5: (po5, 5, Tristate), + PO6: (po6, 6, Tristate), + PO7: (po7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOP, gpiop, 'p', 24, gpio078, gpio07c, gpio0e8, gpio0ec, gpio0f0, gpio0f4, gpio0f8, + gpio0fc, gpio100, gpio104, gpio0e0, gpio0e4, gpio0cc, gpio108, + [ + PP0: (pp0, 0, Tristate), + PP1: (pp1, 1, Tristate), + PP2: (pp2, 2, Tristate), + PP3: (pp3, 3, Tristate), + PP4: (pp4, 4, Tristate), + PP5: (pp5, 5, Tristate), + PP6: (pp6, 6, Tristate), + PP7: (pp7, 7, Tristate), + ] +); + +// GPIO QRST — register group 0x080–0x138 +gpio_macro!( + GPIOQ, gpioq, 'q', 0, gpio080, gpio084, gpio118, gpio11c, gpio120, gpio124, gpio128, + gpio12c, gpio130, gpio134, gpio110, gpio114, gpio0d0, gpio138, + [ + PQ0: (pq0, 0, Tristate), + PQ1: (pq1, 1, Tristate), + PQ2: (pq2, 2, Tristate), + PQ3: (pq3, 3, Tristate), + PQ4: (pq4, 4, Tristate), + PQ5: (pq5, 5, Tristate), + PQ6: (pq6, 6, Tristate), + PQ7: (pq7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOR, gpior, 'r', 8, gpio080, gpio084, gpio118, gpio11c, gpio120, gpio124, gpio128, + gpio12c, gpio130, gpio134, gpio110, gpio114, gpio0d0, gpio138, + [ + PR0: (pr0, 0, Tristate), + PR1: (pr1, 1, Tristate), + PR2: (pr2, 2, Tristate), + PR3: (pr3, 3, Tristate), + PR4: (pr4, 4, Tristate), + PR5: (pr5, 5, Tristate), + PR6: (pr6, 6, Tristate), + PR7: (pr7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOS, gpios, 's', 16, gpio080, gpio084, gpio118, gpio11c, gpio120, gpio124, gpio128, + gpio12c, gpio130, gpio134, gpio110, gpio114, gpio0d0, gpio138, + [ + PS0: (ps0, 0, Tristate), + PS1: (ps1, 1, Tristate), + PS2: (ps2, 2, Tristate), + PS3: (ps3, 3, Tristate), + PS4: (ps4, 4, Tristate), + PS5: (ps5, 5, Tristate), + PS6: (ps6, 6, Tristate), + PS7: (ps7, 7, Tristate), + ] +); + +gpio_macro!( + GPIOT, gpiot, 't', 24, gpio080, gpio084, gpio118, gpio11c, gpio120, gpio124, gpio128, + gpio12c, gpio130, gpio134, gpio110, gpio114, gpio0d0, gpio138, + [ + PT0: (pt0, 0, Tristate), + PT1: (pt1, 1, Tristate), + PT2: (pt2, 2, Tristate), + PT3: (pt3, 3, Tristate), + PT4: (pt4, 4, Tristate), + PT5: (pt5, 5, Tristate), + PT6: (pt6, 6, Tristate), + PT7: (pt7, 7, Tristate), + ] +); + +// GPIO U — register group 0x088–0x168 +gpio_macro!( + GPIOU, gpiou, 'u', 0, gpio088, gpio08c, gpio148, gpio14c, gpio150, gpio154, gpio158, + gpio15c, gpio160, gpio164, gpio140, gpio144, gpio0d4, gpio168, + [ + PU0: (pu0, 0, Tristate), + PU1: (pu1, 1, Tristate), + PU2: (pu2, 2, Tristate), + PU3: (pu3, 3, Tristate), + PU4: (pu4, 4, Tristate), + PU5: (pu5, 5, Tristate), + PU6: (pu6, 6, Tristate), + PU7: (pu7, 7, Tristate), + ] +);
diff --git a/target/ast10x0/peripherals/gpio/registers.rs b/target/ast10x0/peripherals/gpio/registers.rs new file mode 100644 index 0000000..a9e243b --- /dev/null +++ b/target/ast10x0/peripherals/gpio/registers.rs
@@ -0,0 +1,52 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! AST10x0 GPIO low-level register accessor. + +use ast1060_pac as device; +use core::marker::PhantomData; + +/// Safe wrapper around the AST1060 GPIO register block. +pub struct GpioRegisters { + base: *const device::gpio::RegisterBlock, + /// Prevent `Send` and `Sync`. + /// + /// MMIO register blocks must not be transferred across threads or + /// shared by reference due to potential side effects and lack of + /// synchronization guarantees. + _not_send_sync: PhantomData<*const ()>, +} + +impl GpioRegisters { + /// Create a register accessor from a raw GPIO register block pointer. + /// + /// # Safety + /// + /// - `base` must be a valid, non-null pointer to the AST1060 GPIO register block. + /// - The block must remain valid for the lifetime of this value. + /// - Caller must enforce exclusive (or otherwise coordinated) access to the + /// register block for the duration of use. + pub const unsafe fn new(base: *const device::gpio::RegisterBlock) -> Self { + Self { + base, + _not_send_sync: PhantomData, + } + } + + /// Create a register accessor for the global GPIO instance. + /// + /// # Safety + /// + /// Caller must ensure exclusive access to the singleton GPIO peripheral is + /// coordinated for the lifetime of this value. + pub unsafe fn new_global() -> Self { + // SAFETY: Caller upholds the singleton access contract. + unsafe { Self::new(device::Gpio::ptr()) } + } + + #[inline] + pub(crate) fn regs(&self) -> &device::gpio::RegisterBlock { + // SAFETY: Constructor guarantees a valid, non-null register block pointer. + unsafe { &*self.base } + } +}
diff --git a/target/ast10x0/peripherals/gpio/types.rs b/target/ast10x0/peripherals/gpio/types.rs new file mode 100644 index 0000000..bd054bf --- /dev/null +++ b/target/ast10x0/peripherals/gpio/types.rs
@@ -0,0 +1,113 @@ +// Licensed under the Apache-2.0 license +// SPDX-License-Identifier: Apache-2.0 + +//! GPIO type states, traits, and error types. + +use core::marker::PhantomData; + +/// All input modes implement this trait. +pub trait InputMode {} + +/// All output modes implement this trait. +pub trait OutputMode {} + +/// `OpenDrain` modes implement this trait. +pub trait OpenDrainMode { + /// Returns whether pull-up is enabled. + fn pup() -> bool; +} + +/// Input mode (type state). +pub struct Input<MODE> +where + MODE: InputMode, +{ + pub(super) _mode: PhantomData<MODE>, +} + +/// Sub-mode of Input: Floating input (type state). +pub struct Floating; +impl InputMode for Floating {} +impl OpenDrainMode for Floating { + fn pup() -> bool { + false + } +} + +/// Sub-mode of Input: Pulled down input (type state). +pub struct PullDown; +impl InputMode for PullDown {} + +/// Sub-mode of Input: Pulled up input (type state). +pub struct PullUp; +impl InputMode for PullUp {} +impl OpenDrainMode for PullUp { + fn pup() -> bool { + true + } +} + +/// Tri-state mode (type state). +pub struct Tristate; + +/// Output mode (type state). +pub struct Output<MODE> +where + MODE: OutputMode, +{ + pub(super) _mode: PhantomData<MODE>, +} + +/// Sub-mode of Output: Push-pull output (type state). +pub struct PushPull; +impl OutputMode for PushPull {} +impl OutputMode for PullDown {} +impl OutputMode for PullUp {} + +/// Sub-mode of Output: Open drain output (type state). +pub struct OpenDrain<ODM> +where + ODM: OpenDrainMode, +{ + pub(super) _pull: PhantomData<ODM>, +} +impl<ODM> OutputMode for OpenDrain<ODM> where ODM: OpenDrainMode {} + +/// Sets when a GPIO pin triggers an interrupt. +pub enum InterruptMode { + /// Interrupt when level is low. + LevelLow, + /// Interrupt when level is high. + LevelHigh, + /// Interrupt on rising edge. + EdgeRising, + /// Interrupt on falling edge. + EdgeFalling, + /// Interrupt on both rising and falling edges. + EdgeBoth, + /// Disable interrupts on this pin. + Disabled, +} + +/// Extension trait to split a GPIO bank peripheral into individual pins. +pub trait GpioExt { + /// The type returned by [`split`](GpioExt::split). + type Parts; + + /// Consume the bank peripheral and return its individual pins. + fn split(self) -> Self::Parts; +} + +/// Error type for GPIO operations. +#[derive(Debug)] +pub enum GpioError { + Unknown, +} + +impl embedded_hal::digital::Error for GpioError { + fn kind(&self) -> embedded_hal::digital::ErrorKind { + match self { + GpioError::Unknown => embedded_hal::digital::ErrorKind::Other, + } + } +}
diff --git a/target/ast10x0/peripherals/lib.rs b/target/ast10x0/peripherals/lib.rs index 0e497a0..8d2303d 100644 --- a/target/ast10x0/peripherals/lib.rs +++ b/target/ast10x0/peripherals/lib.rs
@@ -3,6 +3,7 @@ #![no_std] +pub mod gpio; pub mod hace; pub mod i2c; pub mod i3c;