diff --git a/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs b/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs index 8d6e7b6..c975bad 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/gpio.rs @@ -9,12 +9,9 @@ use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; use tock_registers::registers::ReadWrite; -pub const PH0_UART0_TX: u32 = 2; -pub const PH1_UART0_RX: u32 = 2; - register_structs! { #[allow(non_snake_case)] - Regs { + CpuxPortRegs { (0x00 => CFG: [ReadWrite; 4]), (0x10 => DAT: ReadWrite), (0x14 => DRV: [ReadWrite; 2]), @@ -23,11 +20,37 @@ register_structs! { } } -pub(super) struct Gpio { - regs: IrqSafeNullLock>, +struct CpuxGpio { + regs: MemoryIo<[CpuxPortRegs; 5]>, } -impl Regs { +pub(super) struct Gpio { + cpux: IrqSafeNullLock, +} + +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct PinAddress(u32); + +impl PinAddress { + #[inline(always)] + pub const fn new(bank: u32, pin: u32) -> Self { + // TODO sanity checks + Self((bank << 16) | pin) + } + + #[inline(always)] + pub const fn bank(self) -> usize { + (self.0 >> 16) as usize + } + + #[inline(always)] + pub const fn pin(self) -> u32 { + self.0 & 0xFFFF + } +} + +impl CpuxPortRegs { #[inline] fn set_pin_cfg_inner(&self, pin: u32, cfg: u32) { let reg = pin >> 3; @@ -43,22 +66,13 @@ impl Regs { let tmp = self.PUL[reg as usize].get() & !(0x3 << shift); self.PUL[reg as usize].set(tmp | ((pul & 0x3) << shift)); } - } -impl Device for Gpio { - fn name(&self) -> &'static str { - "Allwinner H6 GPIO Controller" - } +impl CpuxGpio { + unsafe fn set_pin_config(&self, bank: usize, pin: u32, cfg: &PinConfig) -> Result<(), Errno> { + assert!((0..=7).contains(&bank)); + let regs = &self.regs[bank]; - unsafe fn enable(&self) -> Result<(), Errno> { - Ok(()) - } -} - -impl GpioDevice for Gpio { - unsafe fn set_pin_config(&self, pin: u32, cfg: &PinConfig) -> Result<(), Errno> { - let regs = self.regs.lock(); let pull = match cfg.pull { PullMode::None => 0, PullMode::Up => 1, @@ -86,35 +100,101 @@ impl GpioDevice for Gpio { Ok(()) } - fn get_pin_config(&self, _pin: u32) -> Result { + #[inline(always)] + fn read_pin(&self, bank: usize, pin: u32) -> bool { + self.regs[bank].DAT.get() & (1u32 << pin) != 0 + } + + #[inline(always)] + fn toggle_pin(&mut self, bank: usize, pin: u32) { + self.regs[bank] + .DAT + .set(self.regs[bank].DAT.get() ^ (1u32 << pin)) + } + + #[inline(always)] + fn write_pin(&mut self, bank: usize, pin: u32, value: bool) { + if value { + self.regs[bank] + .DAT + .set(self.regs[bank].DAT.get() | (1u32 << pin)) + } else { + self.regs[bank] + .DAT + .set(self.regs[bank].DAT.get() & !(1u32 << pin)) + } + } +} + +impl Device for Gpio { + fn name(&self) -> &'static str { + "Allwinner H6 GPIO Controller" + } + + unsafe fn enable(&self) -> Result<(), Errno> { + Ok(()) + } +} + +impl GpioDevice for Gpio { + type PinAddress = PinAddress; + + unsafe fn set_pin_config(&self, pin: PinAddress, cfg: &PinConfig) -> Result<(), Errno> { + let bank = pin.bank(); + let pin = pin.pin(); + + match bank { + 2..=7 => self.cpux.lock().set_pin_config(bank - 2, pin, cfg), + _ => unimplemented!(), + } + } + + fn get_pin_config(&self, _pin: PinAddress) -> Result { todo!() } - fn set_pin(&self, pin: u32) { - let regs = self.regs.lock(); - regs.DAT.set(regs.DAT.get() | (1 << pin)); + fn write_pin(&self, pin: PinAddress, state: bool) { + let bank = pin.bank(); + let pin = pin.pin(); + + match bank { + 2..=7 => self.cpux.lock().write_pin(bank - 2, pin, state), + _ => unimplemented!(), + } } - fn clear_pin(&self, pin: u32) { - let regs = self.regs.lock(); - regs.DAT.set(regs.DAT.get() & !(1 << pin)); + fn toggle_pin(&self, pin: PinAddress) { + let bank = pin.bank(); + let pin = pin.pin(); + + match bank { + 2..=7 => self.cpux.lock().toggle_pin(bank - 2, pin), + _ => unimplemented!(), + } } - fn toggle_pin(&self, pin: u32) { - let regs = self.regs.lock(); - regs.DAT.set(regs.DAT.get() ^ (1 << pin)); - } + fn read_pin(&self, pin: PinAddress) -> Result { + let bank = pin.bank(); + let pin = pin.pin(); - fn read_pin(&self, pin: u32) -> Result { - let regs = self.regs.lock(); - Ok(regs.DAT.get() & (1 << pin) != 0) + match bank { + 2..=7 => Ok(self.cpux.lock().read_pin(bank - 2, pin)), + _ => unimplemented!(), + } } } impl Gpio { + pub unsafe fn cfg_uart0_ph0_ph1(&self) -> Result<(), Errno> { + self.set_pin_config(PinAddress::new(7, 0), &PinConfig::alt(2))?; + self.set_pin_config(PinAddress::new(7, 1), &PinConfig::alt(2)) + } + pub const unsafe fn new(base: usize) -> Self { Self { - regs: IrqSafeNullLock::new(MemoryIo::new(base)), + cpux: IrqSafeNullLock::new(CpuxGpio { + regs: MemoryIo::new(base), + }), } } } diff --git a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs index 31cec7b..af05dd2 100644 --- a/kernel/src/arch/aarch64/mach_orangepi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_orangepi3/mod.rs @@ -5,7 +5,6 @@ use crate::arch::aarch64::{ timer::GenericTimer, }; use crate::dev::{ - gpio::{GpioDevice, PinConfig}, irq::{IntController, IntSource}, serial::SerialDevice, timer::TimestampSource, @@ -25,8 +24,7 @@ pub fn init_board() -> Result<(), Errno> { unsafe { GIC.enable()?; - GPIOH.set_pin_config(0, &PinConfig::alt(gpio::PH0_UART0_TX))?; - GPIOH.set_pin_config(1, &PinConfig::alt(gpio::PH1_UART0_RX))?; + GPIO.cfg_uart0_ph0_ph1()?; UART0.enable()?; UART0.init_irqs()?; @@ -59,7 +57,5 @@ pub fn intc() -> &'static impl IntController { static UART0: Uart = unsafe { Uart::new(UART0_BASE, IrqNumber::new(32)) }; static LOCAL_TIMER: GenericTimer = GenericTimer {}; -#[allow(dead_code)] -static GPIOD: Gpio = unsafe { Gpio::new(PIO_BASE + 0x24 * 3) }; -static GPIOH: Gpio = unsafe { Gpio::new(PIO_BASE + 0x24 * 7) }; +static GPIO: Gpio = unsafe { Gpio::new(PIO_BASE) }; static GIC: Gic = unsafe { Gic::new(GICD_BASE, GICC_BASE) }; diff --git a/kernel/src/dev/gpio.rs b/kernel/src/dev/gpio.rs index 5bd99be..7cf11fe 100644 --- a/kernel/src/dev/gpio.rs +++ b/kernel/src/dev/gpio.rs @@ -37,26 +37,27 @@ pub struct PinConfig { pub func: u32, } -// TODO separate traits for "single port controller" and "global gpio controller" /// Generic GPIO controller interface pub trait GpioDevice: Device { + /// Controller-specific address type for a single pin, + /// may include its bank and pin numbers + type PinAddress; + /// Initializes configuration for given pin /// /// # Safety /// /// Unsafe: changes physical pin configuration - unsafe fn set_pin_config(&self, pin: u32, cfg: &PinConfig) -> Result<(), Errno>; + unsafe fn set_pin_config(&self, pin: Self::PinAddress, cfg: &PinConfig) -> Result<(), Errno>; /// Returns current configuration of given pin - fn get_pin_config(&self, pin: u32) -> Result; + fn get_pin_config(&self, pin: Self::PinAddress) -> Result; - /// Sets `pin` to HIGH state - fn set_pin(&self, pin: u32); - /// Sets `pin` to LOW state - fn clear_pin(&self, pin: u32); + /// Sets `pin` to HIGH/LOW `state` + fn write_pin(&self, pin: Self::PinAddress, state: bool); /// Toggles `pin`'s HIGH/LOW state - fn toggle_pin(&self, pin: u32); + fn toggle_pin(&self, pin: Self::PinAddress); /// Returns `true` if input `pin` is in HIGH state - fn read_pin(&self, pin: u32) -> Result; + fn read_pin(&self, pin: Self::PinAddress) -> Result; } impl PinConfig { @@ -65,7 +66,7 @@ impl PinConfig { Self { mode: PinMode::Alt, pull: PullMode::None, - func + func, } } @@ -74,7 +75,7 @@ impl PinConfig { Self { mode: PinMode::Output, pull: PullMode::Down, - func: 0 + func: 0, } } }