refactor: orangepi3 gpio is now global gpio ctrl
This commit is contained in:
@@ -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<u32>; 4]),
|
||||
(0x10 => DAT: ReadWrite<u32>),
|
||||
(0x14 => DRV: [ReadWrite<u32>; 2]),
|
||||
@@ -23,11 +20,37 @@ register_structs! {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Gpio {
|
||||
regs: IrqSafeNullLock<MemoryIo<Regs>>,
|
||||
struct CpuxGpio {
|
||||
regs: MemoryIo<[CpuxPortRegs; 5]>,
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
pub(super) struct Gpio {
|
||||
cpux: IrqSafeNullLock<CpuxGpio>,
|
||||
}
|
||||
|
||||
#[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<PinConfig, Errno> {
|
||||
#[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<PinConfig, Errno> {
|
||||
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<bool, Errno> {
|
||||
let bank = pin.bank();
|
||||
let pin = pin.pin();
|
||||
|
||||
fn read_pin(&self, pin: u32) -> Result<bool, Errno> {
|
||||
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),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IrqNumber = IrqNumber> {
|
||||
|
||||
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) };
|
||||
|
||||
+12
-11
@@ -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<PinConfig, Errno>;
|
||||
fn get_pin_config(&self, pin: Self::PinAddress) -> Result<PinConfig, Errno>;
|
||||
|
||||
/// 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<bool, Errno>;
|
||||
fn read_pin(&self, pin: Self::PinAddress) -> Result<bool, Errno>;
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user