refactor: orangepi3 gpio is now global gpio ctrl

This commit is contained in:
2021-10-07 15:40:12 +03:00
parent 7213791b92
commit 8d4a235e49
3 changed files with 129 additions and 52 deletions
+115 -35
View File
@@ -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
View File
@@ -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,
}
}
}