pinctrl: basic support for gpio

This commit is contained in:
2025-07-31 00:03:45 +03:00
parent 06a6e11dab
commit 062db06473
16 changed files with 588 additions and 13 deletions
+69
View File
@@ -0,0 +1,69 @@
use alloc::sync::Arc;
use yggdrasil_abi::error::Error;
use crate::device::Device;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InputPinBias {
PullUp,
PullDown,
Floating,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OutputPinBias {
PushPull,
OpenDrain,
HighZ,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GpioPinLevel {
High,
Low,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SinglePinDirection {
Output,
Input,
}
pub struct GpioPinConfig {
pub input: bool,
pub output: bool,
pub input_bias: Option<InputPinBias>,
pub output_bias: Option<OutputPinBias>,
pub active_level: GpioPinLevel,
pub initial_level: GpioPinLevel,
}
pub struct PinHandle {
pub index: u32,
pub config: GpioPinConfig,
pub parent: Arc<dyn GpioController>,
}
pub trait GpioController: Device {
fn write_gpio(&self, pin: &PinHandle, value: bool) -> Result<(), Error>;
fn read_gpio(&self, pin: &PinHandle) -> Result<bool, Error>;
fn setup_gpio(&self, pin: &PinHandle, event: Option<u64>) -> Result<(), Error>;
}
impl PinHandle {
pub fn configure(&self) -> Result<(), Error> {
self.parent.setup_gpio(self, None)
}
}
impl GpioPinConfig {
pub fn force_single_direction(&self) -> Option<SinglePinDirection> {
match (self.input, self.output) {
(true, false) => Some(SinglePinDirection::Input),
(false, true) => Some(SinglePinDirection::Output),
(false, false) => None,
(true, true) => None,
}
}
}
+1
View File
@@ -7,6 +7,7 @@ extern crate alloc;
pub mod bus;
pub mod clock;
pub mod device;
pub mod gpio;
pub mod interrupt;
pub mod serial;
pub mod timer;
@@ -2,11 +2,12 @@
use alloc::sync::Arc;
use device_api::{
clock::{ClockHandle, ResetHandle},
gpio::PinHandle,
interrupt::FullIrq,
};
use fdt_rs::spec::Phandle;
use crate::{DeviceTreePropertyRead, TProp};
use crate::{driver::DeviceTreeGpioPins, DeviceTreePropertyRead, TProp};
use super::{lookup_phandle, Node};
@@ -20,6 +21,12 @@ pub(crate) struct ResetIter<'dt> {
pub(crate) offset: usize,
}
pub(crate) struct GpioIter<'o, 'dt> {
pub(crate) options: &'o DeviceTreeGpioPins,
pub(crate) gpios: TProp<'dt>,
pub(crate) offset: usize,
}
impl Iterator for ClockIter<'_> {
type Item = ClockHandle;
@@ -52,6 +59,22 @@ impl Iterator for ResetIter<'_> {
}
}
impl Iterator for GpioIter<'_, '_> {
type Item = PinHandle;
fn next(&mut self) -> Option<Self::Item> {
if self.offset >= self.gpios.len() {
return None;
}
let phandle = self.gpios.read_cell(self.offset, 1)? as Phandle;
let gpioc = lookup_phandle(phandle, true)?;
let gpioc = gpioc.as_pin_controller()?;
let (pin, len) = gpioc.map_gpio(&self.gpios, self.offset + 1, self.options)?;
self.offset += len + 1;
Some(pin)
}
}
// Interrupt controller handling
/// Reads interrupt information, as interpreted by `interrupt_controller`, from `property` at a
+11
View File
@@ -1,6 +1,7 @@
//! Device tree-based driver definitions
use alloc::sync::Arc;
use device_api::gpio::GpioPinLevel;
use yggdrasil_abi::error::Error;
mod controller;
@@ -22,6 +23,16 @@ pub use traits::{
};
pub use tree::{find_node, unflatten_device_tree, walk_device_tree, Node};
/// Contextual information about a GPIO pin being configured
pub struct DeviceTreeGpioPins {
/// Whether to enable input on the pin
pub input: bool,
/// Whether to enable output on the pin
pub output: bool,
/// Initial level to configure the GPIO with
pub initial_level: GpioPinLevel,
}
/// Specifies initialization sequence requirement for a driver
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum InitSequence {
+10 -1
View File
@@ -6,11 +6,12 @@ use device_api::{
bus::Bus,
clock::{ClockHandle, ResetHandle},
device::Device,
gpio::PinHandle,
interrupt::{ExternalInterruptController, FullIrq},
};
use libk::error::Error;
use crate::TProp;
use crate::{driver::DeviceTreeGpioPins, TProp};
use super::{InitSequence, Node};
@@ -56,6 +57,14 @@ pub struct ProbeContext {
pub trait DeviceTreePinController {
/// Configure a pin group
fn configure_pin_group(self: Arc<Self>, pins: &Arc<Node>) -> Result<(), Error>;
/// Reads GPIO pin information from `property` at given `offset` and maps it to a
/// [PinHandle], returning the handle + the size of the GPIO entry.
fn map_gpio(
self: Arc<Self>,
property: &TProp,
offset: usize,
info: &DeviceTreeGpioPins,
) -> Option<(PinHandle, usize)>;
}
impl ProbeContext {
+22 -1
View File
@@ -9,6 +9,7 @@ use device_api::{
bus::Bus,
clock::{ClockController, ClockHandle, ResetHandle},
device::{Device, DeviceInitContext},
gpio::PinHandle,
interrupt::{ExternalInterruptController, FullIrq, MessageInterruptController},
};
use fdt_rs::spec::Phandle;
@@ -18,7 +19,9 @@ use libk_util::OneTimeInit;
use yggdrasil_abi::error::Error;
use crate::{
driver::{traits::DeviceTreePinController, DeviceTreeSyscon},
driver::{
controller::GpioIter, traits::DeviceTreePinController, DeviceTreeGpioPins, DeviceTreeSyscon,
},
tree, DeviceTree, DeviceTreeNodeExt, DeviceTreePropertyRead, TNode, TProp,
};
@@ -349,6 +352,24 @@ impl Node {
.map(|range| PhysicalAddress::from_u64(range.start))
}
/// Returns an iterator over the node's defined `gpios`
pub fn gpios<'a>(
&self,
options: &'a DeviceTreeGpioPins,
) -> Option<impl Iterator<Item = PinHandle> + 'a> {
let gpios = self.property("gpios")?;
Some(GpioIter {
gpios,
options,
offset: 0,
})
}
/// Returns a `gpios` entry with given index
pub fn gpio(&self, options: &DeviceTreeGpioPins, index: usize) -> Option<PinHandle> {
self.gpios(options)?.nth(index)
}
/// Returns an input `clock` handle for a given reset name
pub fn named_clock(&self, name: &str) -> Option<ClockHandle> {
self.property("clock-names")?
+42 -2
View File
@@ -1,12 +1,15 @@
//! General helpers and utilities for device tree drivers
use alloc::sync::Arc;
use device_api::interrupt::{FullIrq, MessageInterruptController};
use device_api::{
gpio::{GpioPinConfig, GpioPinLevel, InputPinBias, OutputPinBias},
interrupt::{FullIrq, MessageInterruptController},
};
use fdt_rs::prelude::PropReader;
use yggdrasil_abi::net::MacAddress;
use crate::{
driver::{lookup_phandle, map_interrupt_at},
driver::{lookup_phandle, map_interrupt_at, DeviceTreeGpioPins},
DeviceTreePropertyRead, TProp,
};
@@ -272,3 +275,40 @@ pub fn read_mac_address(node: &Arc<Node>) -> Option<MacAddress> {
let mac_bytes: [u8; 6] = property.raw().try_into().ok()?;
Some(MacAddress::from(mac_bytes))
}
/// Parse a generic gpio configuration from the device tree 1-cell format
pub fn generic_gpio_config(cell: u32, gpio: &DeviceTreeGpioPins) -> GpioPinConfig {
const GPIO_ACTIVE_LOW: u32 = 1 << 0;
const GPIO_SINGLE_ENDED: u32 = 1 << 1;
const GPIO_LINE_OPEN_DRAIN: u32 = 1 << 2;
const GPIO_PULL_UP: u32 = 1 << 4;
const GPIO_PULL_DOWN: u32 = 1 << 5;
const GPIO_PULL_DISABLE: u32 = 1 << 6;
const GPIO_OPEN_DRAIN: u32 = GPIO_LINE_OPEN_DRAIN | GPIO_SINGLE_ENDED;
let active_level = if cell & GPIO_ACTIVE_LOW != 0 {
GpioPinLevel::Low
} else {
GpioPinLevel::High
};
let output_bias = match cell & (GPIO_SINGLE_ENDED | GPIO_LINE_OPEN_DRAIN) {
0 => Some(OutputPinBias::PushPull),
GPIO_OPEN_DRAIN | GPIO_SINGLE_ENDED => Some(OutputPinBias::OpenDrain),
_ => None,
};
let input_bias = match cell & (GPIO_PULL_UP | GPIO_PULL_DOWN | GPIO_PULL_DISABLE) {
GPIO_PULL_DISABLE => Some(InputPinBias::Floating),
GPIO_PULL_UP => Some(InputPinBias::PullUp),
GPIO_PULL_DOWN => Some(InputPinBias::PullDown),
_ => None,
};
GpioPinConfig {
input: gpio.input,
output: gpio.output,
initial_level: gpio.initial_level,
input_bias,
output_bias,
active_level,
}
}
+44
View File
@@ -0,0 +1,44 @@
use core::sync::atomic::{AtomicU64, Ordering};
use alloc::{boxed::Box, collections::BTreeMap};
use device_api::gpio::PinHandle;
use libk_util::{ring::LossyRingQueue, sync::spin_rwlock::IrqSafeRwLock};
use yggdrasil_abi::error::Error;
static GPIO_EVENT_QUEUE: LossyRingQueue<u64> = LossyRingQueue::with_capacity(64);
static GPIO_EVENT_MAP: IrqSafeRwLock<BTreeMap<u64, Box<dyn Fn() + Send>>> =
IrqSafeRwLock::new(BTreeMap::new());
static GPIO_EVENT_ID: AtomicU64 = AtomicU64::new(1);
pub trait GpioEvent {
fn configure_with_interrupt(&self, handler: Box<dyn Fn() + Send>) -> Result<(), Error>;
}
impl GpioEvent for PinHandle {
fn configure_with_interrupt(&self, handler: Box<dyn Fn() + Send>) -> Result<(), Error> {
let ev = bind_gpio_event(handler);
self.parent.setup_gpio(self, Some(ev))
}
}
pub async fn gpio_event_handler_task() {
loop {
let id = GPIO_EVENT_QUEUE.read().await;
let lock = GPIO_EVENT_MAP.read();
if let Some(handler) = lock.get(&id) {
handler();
}
}
}
pub fn bind_gpio_event(handler: Box<dyn Fn() + Send>) -> u64 {
let id = GPIO_EVENT_ID.fetch_add(1, Ordering::Acquire);
GPIO_EVENT_MAP.write().insert(id, handler);
id
}
pub fn signal_gpio_event(ev: u64) {
GPIO_EVENT_QUEUE.write(ev);
}
+1
View File
@@ -36,6 +36,7 @@ pub mod arch;
pub mod config;
pub mod debug;
pub mod device;
pub mod event;
pub mod fs;
pub mod module;
pub mod random;
+130
View File
@@ -0,0 +1,130 @@
//! GPIO drivers
use abi::error::Error;
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use device_api::{
device::{Device, DeviceInitContext},
gpio::{GpioPinLevel, PinHandle},
};
use device_tree::driver::{device_tree_driver, DeviceTreeGpioPins, Node, ProbeContext};
use libk::event::GpioEvent;
struct LedPin {
name: String,
handle: PinHandle,
}
struct KeyPin {
name: String,
handle: PinHandle,
}
trait Pin: Sized + Send + Sync + 'static {
fn from_device_tree(node: &Arc<Node>) -> Option<Self>;
fn configure(&self) -> Result<(), Error>;
fn name(&self) -> &str;
}
struct PinGroup<P: Pin> {
name: String,
pins: Vec<P>,
}
impl<P: Pin> PinGroup<P> {
fn from_device_tree(node: &Arc<Node>) -> Option<Arc<dyn Device>> {
let pins = node
.children()
.filter_map(P::from_device_tree)
.collect::<Vec<_>>();
if pins.is_empty() {
return None;
}
let name = node.name().unwrap_or("pin-group");
Some(Arc::new(Self {
pins,
name: name.into(),
}))
}
}
impl<P: Pin> Device for PinGroup<P> {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
for pin in self.pins.iter() {
if let Err(error) = pin.configure() {
log::error!("gpio {} setup error: {:?}", pin.name(), error);
}
}
Ok(())
}
fn display_name(&self) -> &str {
&self.name
}
}
impl Pin for LedPin {
fn from_device_tree(node: &Arc<Node>) -> Option<Self> {
let handle = node.gpio(
&DeviceTreeGpioPins {
input: false,
output: true,
initial_level: GpioPinLevel::Low,
},
0,
)?;
let name = node.name().unwrap_or("gpio-led").into();
Some(Self { name, handle })
}
fn configure(&self) -> Result<(), Error> {
self.handle.configure()
}
fn name(&self) -> &str {
&self.name
}
}
impl Pin for KeyPin {
fn from_device_tree(node: &Arc<Node>) -> Option<Self> {
let handle = node.gpio(
&DeviceTreeGpioPins {
input: true,
output: false,
initial_level: GpioPinLevel::Low,
},
0,
)?;
let name = node.name().unwrap_or("gpio-key").into();
Some(Self { name, handle })
}
fn configure(&self) -> Result<(), Error> {
let name = self.name.clone();
self.handle.configure_with_interrupt(Box::new(move || {
log::info!("GPIO key {name:?} triggered");
}))
}
fn name(&self) -> &str {
&self.name
}
}
device_tree_driver! {
compatible: ["gpio-leds"],
driver: {
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
PinGroup::<LedPin>::from_device_tree(node)
}
}
}
device_tree_driver! {
compatible: ["gpio-keys"],
driver: {
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
PinGroup::<KeyPin>::from_device_tree(node)
}
}
}
+1
View File
@@ -6,6 +6,7 @@ use libk_util::OneTimeInit;
pub mod bus;
pub mod clock;
pub mod display;
pub mod gpio;
pub mod interrupt;
pub mod mbox;
pub mod pinctrl;
+59 -3
View File
@@ -2,12 +2,17 @@ use abi::error::Error;
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::FullIrq,
gpio::{GpioController, PinHandle},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::{
driver::{device_tree_driver, DeviceTreePinController, Node, ProbeContext},
DeviceTreePropertyRead,
driver::{
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
Node, ProbeContext,
},
DeviceTreePropertyRead, TProp,
};
use libk::device::external_interrupt_controller;
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
@@ -137,6 +142,12 @@ impl Device for Bcm2711Gpio {
regs.configure_pin_interrupts(pin, false, false, false, false);
}
let intc = external_interrupt_controller()?;
for irq in self.irqs.iter() {
intc.register_irq(irq.irq, irq.options, self.clone())?;
intc.enable_irq(irq.irq)?;
}
Ok(())
}
@@ -145,6 +156,33 @@ impl Device for Bcm2711Gpio {
}
}
impl InterruptHandler for Bcm2711Gpio {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
log::warn!("TODO: handle bcm2711-gpio interrupts");
false
}
}
impl GpioController for Bcm2711Gpio {
fn setup_gpio(&self, pin: &PinHandle, _event: Option<u64>) -> Result<(), Error> {
log::warn!(
"TOOD: bcm2711 gpio pin #{} setup: input={}, output={}",
pin.index,
pin.config.input,
pin.config.output
);
Ok(())
}
fn read_gpio(&self, _pin: &PinHandle) -> Result<bool, Error> {
todo!()
}
fn write_gpio(&self, _pin: &PinHandle, _value: bool) -> Result<(), Error> {
todo!()
}
}
impl DeviceTreePinController for Bcm2711Gpio {
fn configure_pin_group(self: Arc<Self>, group: &Arc<Node>) -> Result<(), Error> {
let pins = group.property("brcm,pins").ok_or(Error::InvalidArgument)?;
@@ -171,6 +209,24 @@ impl DeviceTreePinController for Bcm2711Gpio {
Ok(())
}
fn map_gpio(
self: Arc<Self>,
property: &TProp,
offset: usize,
info: &DeviceTreeGpioPins,
) -> Option<(PinHandle, usize)> {
let (pin, options) = property.read_cells_at(offset, (1, 1))?;
let config = generic_gpio_config(options as u32, info);
Some((
PinHandle {
index: pin as u32,
config,
parent: self,
},
2,
))
}
}
device_tree_driver! {
+42 -3
View File
@@ -3,14 +3,15 @@ use alloc::{sync::Arc, vec::Vec};
use device_api::{
clock::{ClockHandle, ResetHandle},
device::{Device, DeviceInitContext},
gpio::{GpioController, PinHandle},
};
use device_tree::{
driver::{
device_tree_driver,
util::{GenericPinctrlBiasConfig, GenericPinctrlConfig},
DeviceTreePinController, Node, ProbeContext,
util::{generic_gpio_config, GenericPinctrlBiasConfig, GenericPinctrlConfig},
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext,
},
DeviceTreePropertyRead,
DeviceTreePropertyRead, TProp,
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
@@ -267,6 +268,26 @@ impl<R: GpioRegs> Device for Gpio<R> {
}
}
impl<R: GpioRegs> GpioController for Gpio<R> {
fn setup_gpio(&self, pin: &PinHandle, _event: Option<u64>) -> Result<(), Error> {
log::warn!(
"TODO: setup gpio #{} input={}, output={}",
pin.index,
pin.config.input,
pin.config.output
);
Err(Error::NotImplemented)
}
fn read_gpio(&self, _pin: &PinHandle) -> Result<bool, Error> {
Err(Error::NotImplemented)
}
fn write_gpio(&self, _pin: &PinHandle, _value: bool) -> Result<(), Error> {
Err(Error::NotImplemented)
}
}
impl<R: GpioRegs> DeviceTreePinController for Gpio<R> {
fn configure_pin_group(self: Arc<Self>, pins: &Arc<Node>) -> Result<(), Error> {
self.ensure_init()?;
@@ -283,6 +304,24 @@ impl<R: GpioRegs> DeviceTreePinController for Gpio<R> {
}
Ok(())
}
fn map_gpio(
self: Arc<Self>,
property: &TProp,
offset: usize,
info: &DeviceTreeGpioPins,
) -> Option<(PinHandle, usize)> {
let (pin, options) = property.read_cells_at(offset, (1, 1))?;
let config = generic_gpio_config(options as u32, info);
Some((
PinHandle {
index: pin as u32,
config,
parent: self,
},
2,
))
}
}
impl GpioRegs for SysRegs {
+128 -1
View File
@@ -1,13 +1,25 @@
use core::sync::atomic::{AtomicU64, Ordering};
use abi::error::Error;
use alloc::{sync::Arc, vec::Vec};
use device_api::{
clock::{ClockHandle, ResetHandle},
device::{Device, DeviceInitContext},
gpio::{GpioController, GpioPinLevel, PinHandle, SinglePinDirection},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{device_tree_driver, DeviceTreePinController, Node, ProbeContext};
use device_tree::{
driver::{
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
Node, ProbeContext,
},
DeviceTreePropertyRead, TProp,
};
use libk::{device::external_interrupt_controller, event::signal_gpio_event};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
interfaces::{Readable, Writeable},
register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
@@ -35,8 +47,10 @@ register_structs! {
struct Pl061 {
#[allow(unused)]
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
irq: FullIrq,
clocks: Vec<ClockHandle>,
resets: Vec<ResetHandle>,
gpio_events: [AtomicU64; 8],
}
impl Device for Pl061 {
@@ -47,6 +61,14 @@ impl Device for Pl061 {
for reset in self.resets.iter() {
reset.deassert()?;
}
Ok(())
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
@@ -55,11 +77,113 @@ impl Device for Pl061 {
}
}
impl InterruptHandler for Pl061 {
fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
let status = {
let lock = self.regs.lock();
let val = lock.GPIOMIS.get();
lock.GPIOIC.set(0xFF);
val
};
for bit in 0..8 {
let ev = self.gpio_events[bit].load(Ordering::Acquire);
if ev != 0 {
signal_gpio_event(ev);
}
}
status != 0
}
}
impl GpioController for Pl061 {
fn write_gpio(&self, _pin: &PinHandle, _value: bool) -> Result<(), Error> {
todo!()
}
fn read_gpio(&self, _pin: &PinHandle) -> Result<bool, Error> {
todo!()
}
fn setup_gpio(&self, pin: &PinHandle, event: Option<u64>) -> Result<(), Error> {
let regs = self.regs.lock();
let direction = pin
.config
.force_single_direction()
.ok_or(Error::InvalidArgument)
.inspect_err(|_| {
log::warn!(
"pl061: gpio #{} has invalid direction input={}, output={}",
pin.index,
pin.config.input,
pin.config.output
)
})?;
// Enable software control
regs.GPIOAFSEL.set(regs.GPIOAFSEL.get() & !(1 << pin.index));
match direction {
SinglePinDirection::Output => {
log::info!("pl061: gpio #{} set as output", pin.index);
regs.GPIODIR.set(regs.GPIODIR.get() | (1 << pin.index));
// Disable interrupt
regs.GPIOIE.set(regs.GPIOIE.get() & !(1 << pin.index));
let level = match pin.config.initial_level {
GpioPinLevel::Low => 0,
GpioPinLevel::High => 1,
};
let mut val = regs.GPIODATA[0].get();
val &= !(1 << pin.index);
val |= level << pin.index;
regs.GPIODATA[0].set(val);
}
SinglePinDirection::Input => {
log::info!("pl061: gpio #{} set as input", pin.index);
regs.GPIODIR.set(regs.GPIODIR.get() & !(1 << pin.index));
if let Some(event) = event {
self.gpio_events[pin.index as usize].store(event, Ordering::Release);
regs.GPIOIS.set(regs.GPIOIS.get() & !(1 << pin.index));
regs.GPIOIBE.set(regs.GPIOIBE.get() & !(1 << pin.index));
regs.GPIOIEV.set(regs.GPIOIEV.get() | (1 << pin.index));
regs.GPIOIE.set(regs.GPIOIE.get() | (1 << pin.index));
regs.GPIOIC.set(1 << pin.index);
}
}
}
Ok(())
}
}
impl DeviceTreePinController for Pl061 {
fn configure_pin_group(self: Arc<Self>, _pins: &Arc<Node>) -> Result<(), Error> {
// TODO implement this when I get some board with this pinctrl
todo!()
}
fn map_gpio(
self: Arc<Self>,
property: &TProp,
offset: usize,
info: &DeviceTreeGpioPins,
) -> Option<(PinHandle, usize)> {
let (pin, options) = property.read_cells_at(offset, (1, 1))?;
let config = generic_gpio_config(options as u32, info);
Some((
PinHandle {
index: pin as u32,
config,
parent: self,
},
2,
))
}
}
device_tree_driver! {
@@ -76,14 +200,17 @@ device_tree_driver! {
} else {
Vec::new()
};
let irq = node.interrupt(0)?;
let base = node.map_base(context, 0)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let pinctrl = Arc::new(Pl061 {
regs: IrqSafeSpinlock::new(regs),
irq,
clocks,
resets,
gpio_events: [const { AtomicU64::new(0) }; 8]
});
node.make_pin_controller(pinctrl.clone());
+3
View File
@@ -37,6 +37,7 @@ pub fn kinit() -> Result<(), Error> {
#[cfg(any(rust_analyzer, target_arch = "riscv64", target_arch = "aarch64"))]
{
use device_tree::driver::InitSequence;
use libk::event;
device_tree::driver::lazy_init(
|_| (),
@@ -55,6 +56,8 @@ pub fn kinit() -> Result<(), Error> {
},
InitSequence::Late,
);
runtime::spawn(event::gpio_event_handler_task()).ok();
}
// Initialize PCI devices
if let Err(error) = PciBusManager::setup_bus_devices(false) {