jh7110: get second ethernet kinda working
This commit is contained in:
parent
70eb6cfaed
commit
41944890b6
@ -322,7 +322,9 @@ impl PciBusSegment {
|
||||
|
||||
for i in 0..6 {
|
||||
if (1 << i) & bar_mask != 0 {
|
||||
let orig_value = config.bar(i).unwrap();
|
||||
let Some(orig_value) = config.bar(i) else {
|
||||
continue;
|
||||
};
|
||||
let size = unsafe { config.bar_size(i) };
|
||||
|
||||
if size != 0 {
|
||||
|
@ -1,17 +1,24 @@
|
||||
#![no_std]
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
use core::{mem::MaybeUninit, time::Duration};
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
clock::{ClockHandle, ResetHandle},
|
||||
device::{Device, DeviceInitContext},
|
||||
dma::DmaAllocator,
|
||||
interrupt::{FullIrq, InterruptHandler, IrqVector},
|
||||
};
|
||||
use device_tree::driver::{device_tree_driver, util::read_mac_address, Node, ProbeContext};
|
||||
use device_tree::driver::{
|
||||
device_tree_driver, util::read_mac_address, InitSequence, Node, ProbeContext,
|
||||
};
|
||||
use futures_util::task::AtomicWaker;
|
||||
use libk::{device::external_interrupt_controller, dma::DmaBuffer, error::Error, task::runtime};
|
||||
use libk::{
|
||||
device::external_interrupt_controller,
|
||||
dma::DmaBuffer,
|
||||
error::Error,
|
||||
task::runtime::{self, psleep, pwait},
|
||||
};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{event::BitmapEvent, sync::IrqSafeSpinlock, OneTimeInit};
|
||||
use regs::{
|
||||
@ -25,6 +32,7 @@ use regs::{
|
||||
use ring::{RxDescriptor, RxRing, TxDescriptor, TxRing};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
use ygg_driver_net_core::{
|
||||
ephy::{PhyAccess, GBESR},
|
||||
interface::{NetworkDevice, NetworkInterfaceType},
|
||||
RxPacket,
|
||||
};
|
||||
@ -49,8 +57,16 @@ struct Stmmac {
|
||||
base: PhysicalAddress,
|
||||
dma: OneTimeInit<Arc<dyn DmaAllocator>>,
|
||||
mac: MacAddress,
|
||||
resets: Vec<ResetHandle>,
|
||||
clocks: Vec<ClockHandle>,
|
||||
|
||||
clk_stmmaceth: ClockHandle,
|
||||
clk_pclk: ClockHandle,
|
||||
clk_ptp_ref: ClockHandle,
|
||||
clk_tx: ClockHandle,
|
||||
clk_gtx: ClockHandle,
|
||||
|
||||
rst_stmmaceth: ResetHandle,
|
||||
rst_ahb: ResetHandle,
|
||||
|
||||
irq: FullIrq,
|
||||
softirq_events: BitmapEvent<AtomicWaker>,
|
||||
|
||||
@ -176,12 +192,19 @@ impl Device for Stmmac {
|
||||
|
||||
log::info!("stmmac: setup {:#x}, mac={}", self.base, self.mac);
|
||||
|
||||
for clock in self.clocks.iter() {
|
||||
clock.enable()?;
|
||||
}
|
||||
for reset in self.resets.iter() {
|
||||
reset.deassert()?;
|
||||
}
|
||||
self.clk_stmmaceth.enable()?;
|
||||
self.clk_pclk.enable()?;
|
||||
self.clk_ptp_ref.enable()?;
|
||||
self.clk_gtx.enable()?;
|
||||
self.clk_tx.enable()?;
|
||||
|
||||
self.rst_ahb.deassert()?;
|
||||
|
||||
self.rst_stmmaceth.assert()?;
|
||||
psleep(Duration::from_millis(1));
|
||||
self.rst_stmmaceth.deassert()?;
|
||||
|
||||
psleep(Duration::from_millis(20));
|
||||
|
||||
let regs = unsafe { DeviceMemoryIo::<Regs>::map(self.base, Default::default()) }?;
|
||||
|
||||
@ -189,16 +212,11 @@ impl Device for Stmmac {
|
||||
|
||||
// Perform a software reset
|
||||
regs.DMA.DMAMR.modify(DMAMR::SWR::SET);
|
||||
|
||||
let mut timeout = 100000;
|
||||
while timeout > 0 && regs.DMA.DMAMR.matches_all(DMAMR::SWR::SET) {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
}
|
||||
if timeout == 0 {
|
||||
log::warn!("stmmac: reset timeout");
|
||||
return Err(Error::TimedOut);
|
||||
}
|
||||
pwait(
|
||||
Duration::from_millis(100),
|
||||
Duration::from_millis(10),
|
||||
|| regs.DMA.DMAMR.matches_all(DMAMR::SWR::CLEAR),
|
||||
)?;
|
||||
|
||||
// Setup DMA parameters
|
||||
// TODO get these params from device tree
|
||||
@ -312,6 +330,14 @@ impl Device for Stmmac {
|
||||
.MACPHYCSR
|
||||
.modify(MACPHYCSR::LUD::SET + MACPHYCSR::TC::SET);
|
||||
|
||||
// Setup the PHY
|
||||
// TODO autodiscover phy
|
||||
let phy = PhyAccess::new(&*regs, 0x00);
|
||||
let (id0, id1) = phy.id()?;
|
||||
log::info!("stmmac: PHY {id0:04x}:{id1:04x}");
|
||||
phy.reset(Duration::from_millis(100))?;
|
||||
phy.setup_link(true, GBESR::empty())?;
|
||||
|
||||
self.inner.init(Inner {
|
||||
regs: IrqSafeSpinlock::new(regs),
|
||||
|
||||
@ -361,21 +387,37 @@ impl NetworkDevice for Stmmac {
|
||||
device_tree_driver! {
|
||||
compatible: ["starfive,jh7110-dwmac"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let clocks = node.clocks()?.collect();
|
||||
let resets = node.resets()?.collect();
|
||||
|
||||
let clk_stmmaceth = node.named_clock("stmmaceth")?;
|
||||
let clk_pclk = node.named_clock("pclk")?;
|
||||
let clk_ptp_ref = node.named_clock("ptp_ref")?;
|
||||
let clk_tx = node.named_clock("tx")?;
|
||||
let clk_gtx = node.named_clock("gtx")?;
|
||||
|
||||
let rst_stmmaceth = node.named_reset("stmmaceth")?;
|
||||
let rst_ahb = node.named_reset("ahb")?;
|
||||
|
||||
let mac = read_mac_address(node)?;
|
||||
// TODO named_interrupt()
|
||||
let irq = node.interrupt(0)?;
|
||||
|
||||
context.sequence = Some(InitSequence::Late);
|
||||
|
||||
Some(Arc::new(Stmmac {
|
||||
base,
|
||||
clocks,
|
||||
resets,
|
||||
mac,
|
||||
irq,
|
||||
|
||||
clk_stmmaceth,
|
||||
clk_pclk,
|
||||
clk_ptp_ref,
|
||||
clk_tx,
|
||||
clk_gtx,
|
||||
rst_stmmaceth,
|
||||
rst_ahb,
|
||||
|
||||
softirq_events: BitmapEvent::new(AtomicWaker::new()),
|
||||
|
||||
dma: OneTimeInit::new(),
|
||||
|
@ -1,6 +1,4 @@
|
||||
use libk::error::Error;
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::{ReadOnly, ReadWrite},
|
||||
};
|
||||
@ -425,76 +423,3 @@ register_structs! {
|
||||
(0xC00 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
impl MacRegs {
|
||||
fn mdio_wait_busy(&self) -> Result<(), Error> {
|
||||
let mut timeout = 10000;
|
||||
while timeout > 0 && self.MACMDIOAR.matches_all(MACMDIOAR::GB::SET) {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
}
|
||||
if timeout == 0 {
|
||||
Err(Error::TimedOut)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mdio_read_c45(
|
||||
&self,
|
||||
phy_addr: u8,
|
||||
mmd_addr: u8,
|
||||
mii_reg: u8,
|
||||
csr_clk_range: u8,
|
||||
) -> Result<u16, Error> {
|
||||
self.mdio_wait_busy()?;
|
||||
self.MACMDIODR.write(MACMDIODR::RA.val(mii_reg as u32));
|
||||
self.MACMDIOAR.write(
|
||||
MACMDIOAR::CR.val(csr_clk_range as u32)
|
||||
+ MACMDIOAR::GOC::Read
|
||||
+ MACMDIOAR::PA.val(phy_addr as u32)
|
||||
+ MACMDIOAR::RDA.val(mmd_addr as u32)
|
||||
+ MACMDIOAR::C45E::SET
|
||||
+ MACMDIOAR::GB::SET,
|
||||
);
|
||||
self.mdio_wait_busy()?;
|
||||
Ok(self.MACMDIODR.read(MACMDIODR::GD) as u16)
|
||||
}
|
||||
|
||||
pub fn mdio_read_c22(
|
||||
&self,
|
||||
mii_addr: u8,
|
||||
mii_reg: u8,
|
||||
csr_clk_range: u8,
|
||||
) -> Result<u16, Error> {
|
||||
self.mdio_wait_busy()?;
|
||||
self.MACMDIOAR.write(
|
||||
MACMDIOAR::GOC::Read
|
||||
+ MACMDIOAR::CR.val(csr_clk_range as u32)
|
||||
+ MACMDIOAR::PA.val(mii_addr as u32)
|
||||
+ MACMDIOAR::RDA.val(mii_reg as u32)
|
||||
+ MACMDIOAR::GB::SET,
|
||||
);
|
||||
self.mdio_wait_busy()?;
|
||||
Ok(self.MACMDIODR.read(MACMDIODR::GD) as u16)
|
||||
}
|
||||
|
||||
pub fn mdio_write_c22(
|
||||
&self,
|
||||
mii_addr: u8,
|
||||
mii_reg: u8,
|
||||
value: u16,
|
||||
csr_clk_range: u8,
|
||||
) -> Result<(), Error> {
|
||||
self.mdio_wait_busy()?;
|
||||
self.MACMDIODR.write(MACMDIODR::GD.val(value as u32));
|
||||
self.MACMDIOAR.write(
|
||||
MACMDIOAR::GOC::Write
|
||||
+ MACMDIOAR::CR.val(csr_clk_range as u32)
|
||||
+ MACMDIOAR::PA.val(mii_addr as u32)
|
||||
+ MACMDIOAR::RDA.val(mii_reg as u32)
|
||||
+ MACMDIOAR::GB::SET,
|
||||
);
|
||||
self.mdio_wait_busy()
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,14 @@
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use tock_registers::register_structs;
|
||||
use core::time::Duration;
|
||||
|
||||
use libk::{error::Error, task::runtime::pwait};
|
||||
use mac::{MACMDIOAR, MACMDIODR};
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
register_structs,
|
||||
};
|
||||
use ygg_driver_net_core::ephy::MdioBus;
|
||||
|
||||
pub mod dma;
|
||||
pub mod mac;
|
||||
@ -14,3 +22,40 @@ register_structs! {
|
||||
(0x1200 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
fn mdio_wait_busy(&self) -> Result<(), Error> {
|
||||
pwait(Duration::from_millis(50), Duration::from_millis(1), || {
|
||||
self.MAC.MACMDIOAR.matches_all(MACMDIOAR::GB::CLEAR)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl MdioBus for Regs {
|
||||
fn mii_read(&self, phyaddr: u8, regaddr: u8) -> Result<u16, Error> {
|
||||
self.mdio_wait_busy()?;
|
||||
self.MAC.MACMDIOAR.write(
|
||||
MACMDIOAR::GOC::Read
|
||||
+ MACMDIOAR::CR.val(1)
|
||||
+ MACMDIOAR::PA.val(phyaddr as u32)
|
||||
+ MACMDIOAR::RDA.val(regaddr as u32)
|
||||
+ MACMDIOAR::GB::SET,
|
||||
);
|
||||
self.mdio_wait_busy()?;
|
||||
Ok(self.MAC.MACMDIODR.read(MACMDIODR::GD) as u16)
|
||||
}
|
||||
|
||||
fn mii_write(&self, phyaddr: u8, regaddr: u8, value: u16) -> Result<(), Error> {
|
||||
self.mdio_wait_busy()?;
|
||||
self.MAC.MACMDIODR.write(MACMDIODR::GD.val(value as u32));
|
||||
self.MAC.MACMDIOAR.write(
|
||||
MACMDIOAR::GOC::Write
|
||||
+ MACMDIOAR::CR.val(1)
|
||||
+ MACMDIOAR::PA.val(phyaddr as u32)
|
||||
+ MACMDIOAR::RDA.val(regaddr as u32)
|
||||
+ MACMDIOAR::GB::SET,
|
||||
);
|
||||
self.mdio_wait_busy()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,15 @@ pub use traits::{
|
||||
};
|
||||
pub use tree::{find_node, unflatten_device_tree, walk_device_tree, Node};
|
||||
|
||||
/// Specifies initialization sequence requirement for a driver
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum InitSequence {
|
||||
/// Driver can be initialized during early boot
|
||||
Early = 1,
|
||||
/// Driver must be initialized when sleep function is available
|
||||
Late = 2,
|
||||
}
|
||||
|
||||
/// Performs a walk of the device tree and initializes nodes which haven't already been
|
||||
/// initialized/probed.
|
||||
///
|
||||
@ -28,9 +37,10 @@ pub use tree::{find_node, unflatten_device_tree, walk_device_tree, Node};
|
||||
pub fn lazy_init<S: Fn(&Arc<Node>), F: Fn(&Arc<Node>, Error)>(
|
||||
success_handler: S,
|
||||
error_handler: F,
|
||||
sequence: InitSequence,
|
||||
) {
|
||||
walk_device_tree::<(), _>(|node| {
|
||||
match node.clone().lazy_init() {
|
||||
match node.clone().lazy_init(sequence) {
|
||||
Some(Ok(())) => success_handler(node),
|
||||
Some(Err(error)) => error_handler(node, error),
|
||||
None => (),
|
||||
@ -47,9 +57,10 @@ pub fn lazy_init<S: Fn(&Arc<Node>), F: Fn(&Arc<Node>, Error)>(
|
||||
pub fn init_irqs<S: Fn(&Arc<Node>), F: Fn(&Arc<Node>, Error)>(
|
||||
success_handler: S,
|
||||
error_handler: F,
|
||||
sequence: InitSequence,
|
||||
) {
|
||||
walk_device_tree::<(), _>(|node| {
|
||||
match node.clone().init_irqs() {
|
||||
match node.clone().init_irqs(sequence) {
|
||||
Some(Ok(())) => success_handler(node),
|
||||
Some(Err(error)) => error_handler(node, error),
|
||||
None => (),
|
||||
|
@ -43,7 +43,7 @@ pub fn lookup_phandle(phandle: Phandle, ensure_probed: bool) -> Option<Arc<Node>
|
||||
if let Some(node) = node.as_ref()
|
||||
&& ensure_probed
|
||||
{
|
||||
node.clone().probe()?;
|
||||
node.probe()?;
|
||||
}
|
||||
node
|
||||
}
|
||||
|
@ -11,12 +11,12 @@ use device_api::{
|
||||
|
||||
use crate::TProp;
|
||||
|
||||
use super::Node;
|
||||
use super::{InitSequence, Node};
|
||||
|
||||
/// Device tree driver interface
|
||||
pub trait Driver: Sync {
|
||||
/// Constructs a [Device] for a given matching node
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>>;
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>>;
|
||||
}
|
||||
|
||||
/// Device-tree based interrupt mapper/controller interface
|
||||
@ -46,6 +46,8 @@ pub trait DeviceTreeResetController {
|
||||
/// Context passed to the driver's `probe` function
|
||||
pub struct ProbeContext {
|
||||
pub(crate) bus: Option<Weak<dyn Bus>>,
|
||||
/// Can be used to set a specific initialization sequence for the device
|
||||
pub sequence: Option<InitSequence>,
|
||||
}
|
||||
|
||||
impl ProbeContext {
|
||||
|
@ -24,7 +24,7 @@ use super::{
|
||||
lookup_phandle, map_interrupt,
|
||||
registry::{register_phandle, DEVICE_TREE, DRIVERS, ROOT},
|
||||
DeviceTreeClockController, DeviceTreeInterruptController, DeviceTreeResetController, Driver,
|
||||
ProbeContext,
|
||||
InitSequence, ProbeContext,
|
||||
};
|
||||
|
||||
/// Represents a single node in the device tree, which may or may not:
|
||||
@ -48,29 +48,27 @@ pub struct Node {
|
||||
|
||||
// Driver/device info
|
||||
device: OneTimeInit<NodeDevice>,
|
||||
init_token: OneTimeInit<()>,
|
||||
|
||||
pub(crate) interrupt_controller: OneTimeInit<Arc<dyn DeviceTreeInterruptController>>,
|
||||
pub(crate) msi_controller: OneTimeInit<Arc<dyn MessageInterruptController>>,
|
||||
pub(crate) clock_controler: OneTimeInit<Arc<dyn DeviceTreeClockController>>,
|
||||
pub(crate) reset_controller: OneTimeInit<Arc<dyn DeviceTreeResetController>>,
|
||||
}
|
||||
|
||||
pub(crate) struct ProbedDevice {
|
||||
driver: &'static dyn Driver,
|
||||
sequence: InitSequence,
|
||||
init_token: OneTimeInit<Result<(), Error>>,
|
||||
irq_init_token: OneTimeInit<Result<(), Error>>,
|
||||
device: Arc<dyn Device>,
|
||||
}
|
||||
|
||||
enum NodeDevice {
|
||||
// Node probed, no device found
|
||||
Missing,
|
||||
// Node probed and driver found
|
||||
Present {
|
||||
driver: &'static dyn Driver,
|
||||
device: Arc<dyn Device>,
|
||||
},
|
||||
Present(ProbedDevice),
|
||||
}
|
||||
|
||||
// struct NodeDevice {
|
||||
// driver: &'static dyn Driver,
|
||||
// device: Arc<dyn Device>,
|
||||
// }
|
||||
|
||||
struct EnumerationContext {
|
||||
address_cells: usize,
|
||||
size_cells: usize,
|
||||
@ -79,23 +77,39 @@ struct EnumerationContext {
|
||||
}
|
||||
|
||||
impl NodeDevice {
|
||||
fn as_device(&self) -> Option<Arc<dyn Device>> {
|
||||
fn as_probed(&self) -> Option<&ProbedDevice> {
|
||||
match self {
|
||||
Self::Missing => None,
|
||||
Self::Present { device, .. } => Some(device.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn driver(&self) -> Option<&'static dyn Driver> {
|
||||
match self {
|
||||
Self::Missing => None,
|
||||
Self::Present { driver, .. } => Some(*driver),
|
||||
Self::Present(probed) => Some(probed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn probe_upwards(self: Arc<Self>) -> (Option<Arc<dyn Device>>, Option<Weak<dyn Bus>>) {
|
||||
fn probe_single(node: &Arc<Node>, cx: &mut ProbeContext) -> Option<ProbedDevice> {
|
||||
let compatible = node.compatible?;
|
||||
let drivers = DRIVERS.read();
|
||||
let driver = drivers.iter().find(|d| d.matches(compatible));
|
||||
if driver.is_none() {
|
||||
// log::warn!("No driver for {compatible:?}");
|
||||
}
|
||||
let driver = driver?;
|
||||
|
||||
let device = driver.imp.probe(node, cx);
|
||||
|
||||
// Move to early init unless driver wants to sleep
|
||||
let sequence = cx.sequence.unwrap_or(InitSequence::Early);
|
||||
|
||||
device.map(|device| ProbedDevice {
|
||||
driver: driver.imp,
|
||||
sequence,
|
||||
device,
|
||||
init_token: OneTimeInit::new(),
|
||||
irq_init_token: OneTimeInit::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn probe_upwards(self: &Arc<Self>) -> (Option<&ProbedDevice>, Option<Weak<dyn Bus>>) {
|
||||
let mut parent_bus = None;
|
||||
if let Some(parent) = self.parent.as_ref().and_then(Weak::upgrade) {
|
||||
let (_, bus) = parent.probe_upwards();
|
||||
@ -110,47 +124,33 @@ impl Node {
|
||||
}
|
||||
}
|
||||
|
||||
let cx = ProbeContext {
|
||||
let mut cx = ProbeContext {
|
||||
bus: parent_bus.clone(),
|
||||
sequence: None,
|
||||
};
|
||||
|
||||
let inner = self.device.or_init_with_opt(|| {
|
||||
let compatible = self.compatible?;
|
||||
let drivers = DRIVERS.read();
|
||||
let driver = drivers.iter().find(|d| d.matches(compatible));
|
||||
if driver.is_none() {
|
||||
// log::warn!("No driver for {compatible:?}");
|
||||
}
|
||||
let driver = driver?;
|
||||
|
||||
let device = driver.imp.probe(&self, &cx);
|
||||
|
||||
let slot = match device {
|
||||
Some(device) => NodeDevice::Present {
|
||||
driver: driver.imp,
|
||||
device,
|
||||
},
|
||||
let inner = self
|
||||
.device
|
||||
.or_init_with(|| match Self::probe_single(&self, &mut cx) {
|
||||
Some(probed) => NodeDevice::Present(probed),
|
||||
None => NodeDevice::Missing,
|
||||
};
|
||||
Some(slot)
|
||||
});
|
||||
let probed = inner.as_probed();
|
||||
|
||||
let device = inner.and_then(|d| d.as_device());
|
||||
|
||||
let bus = if let Some(device) = device.as_ref() {
|
||||
device.clone().as_bus().as_ref().map(Arc::downgrade)
|
||||
let bus = if let Some(probed) = probed.as_ref() {
|
||||
probed.device.clone().as_bus().as_ref().map(Arc::downgrade)
|
||||
} else {
|
||||
parent_bus
|
||||
};
|
||||
|
||||
(device, bus)
|
||||
(probed, bus)
|
||||
}
|
||||
|
||||
/// Performs a "probe" of the node by looking up a matching driver. If the node
|
||||
/// has a parent, its parent is probed first.
|
||||
///
|
||||
/// If the node has already been probed, the device reference is just returned instead.
|
||||
pub fn probe(self: Arc<Self>) -> Option<Arc<dyn Device>> {
|
||||
pub(crate) fn probe(self: &Arc<Self>) -> Option<&ProbedDevice> {
|
||||
let (device, _) = self.probe_upwards();
|
||||
device
|
||||
}
|
||||
@ -189,7 +189,8 @@ impl Node {
|
||||
|
||||
/// Returns the device driver associated with this node, if any was probed.
|
||||
pub fn driver(&self) -> Option<&'static dyn Driver> {
|
||||
self.device.try_get()?.driver()
|
||||
let probed = self.device.try_get()?.as_probed()?;
|
||||
Some(probed.driver)
|
||||
}
|
||||
|
||||
/// Performs a lazy initialization of the node:
|
||||
@ -203,17 +204,20 @@ impl Node {
|
||||
/// * `Some(Ok(()))` - device was probed and initialized (now or before).
|
||||
/// * `Some(Err(...))` - device was probed, but initialization failed.
|
||||
/// * `None` - no driver matched the device.
|
||||
pub fn lazy_init(self: Arc<Self>) -> Option<Result<(), Error>> {
|
||||
let device = self.clone().probe()?;
|
||||
let result = self.init_token.or_try_init_with(|| {
|
||||
let cx = self.make_init_context();
|
||||
unsafe { device.init(cx) }?;
|
||||
Ok(())
|
||||
});
|
||||
match result {
|
||||
Ok(()) => Some(Ok(())),
|
||||
Err(error) => Some(Err(error)),
|
||||
pub fn lazy_init(self: Arc<Self>, sequence: InitSequence) -> Option<Result<(), Error>> {
|
||||
let probed = self.probe()?;
|
||||
|
||||
// Needs to be initialized later
|
||||
if probed.sequence > sequence {
|
||||
return None;
|
||||
}
|
||||
|
||||
let state = probed.init_token.or_init_with(|| {
|
||||
let cx = self.make_init_context();
|
||||
unsafe { probed.device.clone().init(cx) }
|
||||
});
|
||||
|
||||
Some(*state)
|
||||
}
|
||||
|
||||
/// Performs an IRQ initialization for the node's device:
|
||||
@ -222,15 +226,20 @@ impl Node {
|
||||
/// 2. If [Node::lazy_init] succeeds and a device exists, calls [Device::init_irq].
|
||||
///
|
||||
/// Return value is the same as in [Node::lazy_init].
|
||||
pub fn init_irqs(self: Arc<Self>) -> Option<Result<(), Error>> {
|
||||
match self.clone().lazy_init() {
|
||||
pub fn init_irqs(self: Arc<Self>, sequence: InitSequence) -> Option<Result<(), Error>> {
|
||||
let probed = match self.clone().lazy_init(sequence) {
|
||||
Some(Ok(())) => {
|
||||
let device = self.device.get();
|
||||
let status = unsafe { device.as_device()?.init_irq() };
|
||||
Some(status)
|
||||
}
|
||||
Some(Err(_)) | None => None,
|
||||
device.as_probed()?
|
||||
}
|
||||
Some(Err(_)) | None => return None,
|
||||
};
|
||||
|
||||
let state = probed
|
||||
.irq_init_token
|
||||
.or_init_with(|| unsafe { probed.device.clone().init_irq() });
|
||||
|
||||
Some(*state)
|
||||
}
|
||||
|
||||
/// "Forces" an initialization of the device. This is a stricter version of [Node::lazy_init]
|
||||
@ -244,19 +253,20 @@ impl Node {
|
||||
/// * `Ok(())` - if probe/init succeeded.
|
||||
/// * `Err(Error::DoesNotExist)` - couldn't find a device/driver for this node.
|
||||
/// * `Err(other)` - initialization failed.
|
||||
pub fn force_init(self: Arc<Self>) -> Result<(), Error> {
|
||||
let device = self
|
||||
.clone()
|
||||
.probe()
|
||||
.ok_or(Error::DoesNotExist)
|
||||
.inspect_err(|_| log::error!("Does not exist: probe({:?})", self.name))?;
|
||||
pub fn force_init(self: Arc<Self>, sequence: InitSequence) -> Result<(), Error> {
|
||||
let probed = self.probe().ok_or(Error::DoesNotExist)?;
|
||||
|
||||
self.init_token.try_init_with_opt(|| {
|
||||
// Needs to be initialized later
|
||||
if probed.sequence > sequence {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let state = probed.init_token.try_init_with(|| {
|
||||
let cx = self.make_init_context();
|
||||
unsafe { device.init(cx) }?;
|
||||
Ok(())
|
||||
unsafe { probed.device.clone().init(cx) }
|
||||
})?;
|
||||
Ok(())
|
||||
|
||||
*state
|
||||
}
|
||||
|
||||
fn make_init_context(&self) -> DeviceInitContext {
|
||||
@ -364,8 +374,9 @@ impl Node {
|
||||
|
||||
/// Attempts to get a clock controller represented by this node, if any
|
||||
pub fn as_clock_controller(&self) -> Option<Arc<dyn ClockController>> {
|
||||
let device = self.device.try_get()?;
|
||||
device.as_device()?.as_clock_controller()
|
||||
todo!()
|
||||
// let device = self.device.try_get()?;
|
||||
// device.as_device()?.as_clock_controller()
|
||||
}
|
||||
|
||||
/// Attempts to get an interrupt controller represented by this node, if any
|
||||
@ -456,7 +467,6 @@ fn unflatten_node(
|
||||
parent,
|
||||
|
||||
device: OneTimeInit::new(),
|
||||
init_token: OneTimeInit::new(),
|
||||
|
||||
interrupt_controller: OneTimeInit::new(),
|
||||
msi_controller: OneTimeInit::new(),
|
||||
|
@ -7,7 +7,10 @@ use device_api::{
|
||||
interrupt::{IpiDeliveryTarget, IpiMessage},
|
||||
ResetDevice,
|
||||
};
|
||||
use device_tree::{driver::unflatten_device_tree, DeviceTree, DeviceTreeNodeExt};
|
||||
use device_tree::{
|
||||
driver::{unflatten_device_tree, InitSequence},
|
||||
DeviceTree, DeviceTreeNodeExt,
|
||||
};
|
||||
use kernel_arch::Architecture;
|
||||
use kernel_arch_riscv64::{
|
||||
mem::{self, KERNEL_VIRT_OFFSET},
|
||||
@ -225,6 +228,7 @@ impl Riscv64 {
|
||||
|node, error| {
|
||||
log::error!("{}: {error:?}", node.name().unwrap_or("<unknown>"));
|
||||
},
|
||||
InitSequence::Early,
|
||||
);
|
||||
device_tree::driver::init_irqs(
|
||||
|_| (),
|
||||
@ -234,6 +238,7 @@ impl Riscv64 {
|
||||
node.name().unwrap_or("<unknown>")
|
||||
);
|
||||
},
|
||||
InitSequence::Early,
|
||||
);
|
||||
|
||||
PciBusManager::probe_bus_devices()?;
|
||||
@ -283,7 +288,7 @@ impl Riscv64 {
|
||||
|
||||
if let Some(node) = node {
|
||||
log::info!("Probe chosen stdout: {:?}", node.name());
|
||||
node.force_init()?;
|
||||
node.force_init(InitSequence::Early)?;
|
||||
}
|
||||
|
||||
// No stdout
|
||||
|
@ -121,7 +121,7 @@ fn make_msi_map(node: &Arc<Node>) -> Option<PciMsiMap> {
|
||||
device_tree_driver! {
|
||||
compatible: ["pci-host-ecam-generic"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let ecam_base = node.map_base(context, 0)?;
|
||||
let ranges = node.property("ranges")?;
|
||||
|
||||
|
@ -58,7 +58,7 @@ impl Bus for SimpleBus {
|
||||
device_tree_driver! {
|
||||
compatible: ["simple-bus"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, _context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
// Format per DT spec: (child-bus-address, parent-bus-address, length)
|
||||
// Where:
|
||||
// child-bus-address: #address-cells of this node
|
||||
|
@ -63,7 +63,7 @@ impl DeviceTreeClockController for FixedClock {
|
||||
device_tree_driver! {
|
||||
compatible: ["fixed-clock"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, _context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let name = node.name()?;
|
||||
let frequency = node.property("clock-frequency")?.read_cell(0, 1)?;
|
||||
log::info!("fixed-clock {name}: {frequency}");
|
||||
|
@ -20,6 +20,14 @@ use tock_registers::{
|
||||
registers::ReadWrite,
|
||||
};
|
||||
|
||||
const PARENT_OSC: usize = 0;
|
||||
// const PARENT_GMAC0_RMII_REFIN: usize = 1;
|
||||
// const PARENT_GMAC0_RGMII_RXIN: usize = 2;
|
||||
const PARENT_STG_AXIAHB: usize = 3;
|
||||
// const PARENT_APB_BUS: usize = 4;
|
||||
// const PARENT_GMAC0_GTXCLK: usize = 5;
|
||||
// const PARENT_RTC_OSC: usize = 6;
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
Regs {
|
||||
@ -32,13 +40,24 @@ register_structs! {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum ClockRegister {
|
||||
Gate(u32),
|
||||
Gate(u32, ClockParent),
|
||||
#[allow(unused)]
|
||||
FixedDiv(u32, ClockParent),
|
||||
// TODO
|
||||
Fixed,
|
||||
Unimp,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum ClockParent {
|
||||
Int(u32),
|
||||
Ext(usize),
|
||||
}
|
||||
|
||||
/// JH7110 AONCRG driver
|
||||
pub struct Aoncrg {
|
||||
base: PhysicalAddress,
|
||||
clock_parents: [ClockHandle; 7],
|
||||
mapping: OneTimeInit<IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>>,
|
||||
}
|
||||
|
||||
@ -49,18 +68,54 @@ impl Aoncrg {
|
||||
})
|
||||
}
|
||||
|
||||
fn map_clock_index(index: u32) -> Option<(usize, ClockRegister)> {
|
||||
const CLOCK_MAP: &[(&'static str, usize, ClockRegister)] = &[
|
||||
("clk_osc", 0, ClockRegister::Unimp),
|
||||
("aon_apb_func_clk", 1, ClockRegister::Unimp),
|
||||
("ahb_gmac5_clk", 2, ClockRegister::Gate(31)),
|
||||
("axi_gmac5_clk", 3, ClockRegister::Gate(31)),
|
||||
("axi_gmac0_rmii_rtx_clk", 4, ClockRegister::Unimp),
|
||||
("gmac5_axi64_tx_clk", 5, ClockRegister::Unimp),
|
||||
("gmac5_axi64_clk_tx_inv", 6, ClockRegister::Gate(30)),
|
||||
fn clk_enable_int(&self, index: u32) -> Result<(), Error> {
|
||||
let (name, reg) = Self::map_clock_index(index)
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", index))?;
|
||||
let regs = self.ensure_init()?;
|
||||
|
||||
match reg {
|
||||
ClockRegister::Fixed => Ok(()),
|
||||
ClockRegister::Gate(bit, parent) => {
|
||||
self.clk_enable_parent(parent)?;
|
||||
log::info!("jh7110-aoncrg: enable {name:?} @ {index}");
|
||||
let lock = regs.lock();
|
||||
lock.CLOCKS[index as usize].set(lock.CLOCKS[index as usize].get() | (1 << bit));
|
||||
Ok(())
|
||||
}
|
||||
ClockRegister::Unimp => {
|
||||
log::warn!("jh7110-aoncrg: unimplemented clock {name:?}");
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
ClockRegister::FixedDiv(_, parent) => {
|
||||
self.clk_enable_parent(parent)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clk_enable_parent(&self, parent: ClockParent) -> Result<(), Error> {
|
||||
match parent {
|
||||
ClockParent::Int(index) => self.clk_enable_int(index),
|
||||
ClockParent::Ext(clock) => self.clock_parents[clock].enable(),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_clock_index(index: u32) -> Option<(&'static str, ClockRegister)> {
|
||||
use ClockParent::*;
|
||||
use ClockRegister::*;
|
||||
|
||||
const CLOCK_MAP: &[(&'static str, ClockRegister)] = &[
|
||||
/* 0 */ ("clk_osc", FixedDiv(4, Ext(PARENT_OSC))),
|
||||
/* 1 */ ("clk_aon_apb_func", Unimp),
|
||||
/* 2 */ ("clk_gmac5_ahb", Gate(31, Ext(PARENT_STG_AXIAHB))),
|
||||
/* 3 */ ("clk_gmac5_axi", Gate(31, Ext(PARENT_STG_AXIAHB))),
|
||||
/* 4 */ ("clk_gmac5_rmii_rtx", Unimp),
|
||||
/* 5 */ ("clk_gmac5_axi64_tx", Fixed),
|
||||
/* 6 */ ("clk_gmac5_axi64_tx_inv", Gate(30, Int(5))),
|
||||
];
|
||||
let (_, offset, mode) = CLOCK_MAP.get(index as usize)?;
|
||||
Some((*offset, *mode))
|
||||
|
||||
CLOCK_MAP.get(index as usize).copied()
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,21 +132,8 @@ impl Device for Aoncrg {
|
||||
|
||||
impl ClockController for Aoncrg {
|
||||
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
let (offset, mode) = clock
|
||||
.and_then(Self::map_clock_index)
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| log::warn!("jh7110-aoncrg: cannot map clock {clock:?}"))?;
|
||||
|
||||
let mapping = self.ensure_init()?;
|
||||
let regs = mapping.lock();
|
||||
match mode {
|
||||
ClockRegister::Gate(shift) => {
|
||||
log::info!("jh7110-aoncrg: enable clock {clock:?}: reg={offset}, bit={shift}");
|
||||
regs.CLOCKS[offset].set(1 << shift);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
let index = clock.ok_or(Error::InvalidArgument)?;
|
||||
self.clk_enable_int(index)
|
||||
}
|
||||
|
||||
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
@ -149,10 +191,22 @@ impl DeviceTreeResetController for Aoncrg {
|
||||
device_tree_driver! {
|
||||
compatible: ["starfive,jh7110-aoncrg"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
|
||||
let clock_parents = [
|
||||
node.named_clock("osc")?,
|
||||
node.named_clock("gmac0_rmii_refin")?,
|
||||
node.named_clock("gmac0_rgmii_rxin")?,
|
||||
node.named_clock("stg_axiahb")?,
|
||||
node.named_clock("apb_bus")?,
|
||||
node.named_clock("gmac0_gtxclk")?,
|
||||
node.named_clock("rtc_osc")?,
|
||||
];
|
||||
|
||||
let aoncrg = Arc::new(Aoncrg {
|
||||
base,
|
||||
clock_parents,
|
||||
mapping: OneTimeInit::new()
|
||||
});
|
||||
node.make_reset_controller(aoncrg.clone());
|
||||
|
@ -26,7 +26,6 @@ struct Syscrg {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum ClockParent {
|
||||
#[allow(unused)]
|
||||
Int(u32),
|
||||
Ext(usize),
|
||||
None,
|
||||
@ -37,9 +36,9 @@ enum ClockRegister {
|
||||
// Clock gate
|
||||
Gate(u32, ClockParent),
|
||||
// Clock inverter
|
||||
Inv(u32),
|
||||
// Clock delay selector (TODO)
|
||||
Delay,
|
||||
Inv(u32, ClockParent),
|
||||
// Clock divider (TODO)
|
||||
Div(ClockParent),
|
||||
Unimp,
|
||||
}
|
||||
|
||||
@ -51,27 +50,69 @@ impl Syscrg {
|
||||
})
|
||||
}
|
||||
|
||||
fn clk_enable_int(&self, index: u32, depth: u32) -> Result<(), Error> {
|
||||
let (name, reg) = Self::map_clock_index(index)
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", index))?;
|
||||
let regs = self.ensure_init()?;
|
||||
|
||||
match reg {
|
||||
ClockRegister::Gate(bit, parent) => {
|
||||
log::info!("jh7110-syscrg: enable {name:?} @ {index} /{depth}");
|
||||
self.clk_enable_parent(parent, depth)?;
|
||||
let mut lock = regs.lock();
|
||||
lock[index as usize] |= 1 << bit;
|
||||
Ok(())
|
||||
}
|
||||
ClockRegister::Inv(bit, parent) => {
|
||||
log::info!("jh7110-syscrg: enable clk inv {name:?} @ {index}");
|
||||
self.clk_enable_parent(parent, depth)?;
|
||||
let mut lock = regs.lock();
|
||||
lock[index as usize] |= 1 << bit;
|
||||
Ok(())
|
||||
}
|
||||
ClockRegister::Div(parent) => self.clk_enable_parent(parent, depth),
|
||||
ClockRegister::Unimp => {
|
||||
log::warn!("jh7110-syscrg: clock not implemented: {name:?}");
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clk_enable_parent(&self, parent: ClockParent, depth: u32) -> Result<(), Error> {
|
||||
match parent {
|
||||
ClockParent::Int(index) => self.clk_enable_int(index, depth + 1),
|
||||
ClockParent::Ext(clock) => self.parents.get(clock).ok_or(Error::DoesNotExist)?.enable(),
|
||||
ClockParent::None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_clock_index(index: u32) -> Option<(&'static str, ClockRegister)> {
|
||||
const CLOCKS: &[(&'static str, ClockRegister)] = &const {
|
||||
use ClockParent::*;
|
||||
use ClockRegister::*;
|
||||
|
||||
let mut t = [("", Unimp); 256];
|
||||
t[0x184 / 4] = ("clk_gmac5_axi64_ahb", Gate(31, None));
|
||||
t[0x188 / 4] = ("clk_gmac5_axi64_axi", Gate(31, None));
|
||||
t[0x18C / 4] = ("clk_gmac_source", Unimp);
|
||||
t[0x190 / 4] = ("clk_gmac1_gtx", Unimp);
|
||||
|
||||
t[0x01C / 4] = ("clk_axi_cfg0", Div(None));
|
||||
t[0x020 / 4] = ("clk_stg_axiahb", Div(Int(0x01C / 4)));
|
||||
t[0x024 / 4] = ("clk_ahb0", Gate(31, Int(0x020 / 4)));
|
||||
|
||||
t[0x184 / 4] = ("clk_gmac5_axi64_ahb", Gate(31, Int(0x024 / 4)));
|
||||
t[0x188 / 4] = ("clk_gmac5_axi64_axi", Gate(31, Int(0x020 / 4)));
|
||||
t[0x18C / 4] = ("clk_gmac_source", Div(None));
|
||||
t[0x190 / 4] = ("clk_gmac1_gtx", Gate(31, None));
|
||||
t[0x194 / 4] = ("clk_gmac1_rmii_rtx", Unimp);
|
||||
t[0x198 / 4] = ("clk_gmac5_axi64_ptp", Gate(31, None));
|
||||
t[0x198 / 4] = ("clk_gmac5_axi64_ptp", Gate(31, Int(0x18C / 4)));
|
||||
t[0x19C / 4] = ("clk_gmac5_axi64_rx", Unimp);
|
||||
t[0x1A0 / 4] = ("clk_gmac5_axi64_rx_inv", Inv(30));
|
||||
t[0x1A0 / 4] = ("clk_gmac5_axi64_rx_inv", Inv(30, Int(0x19C / 4)));
|
||||
t[0x1A4 / 4] = ("clk_gmac5_axi64_tx", Gate(31, None));
|
||||
t[0x1A8 / 4] = ("clk_gmac5_axi64_tx_inv", Inv(30));
|
||||
t[0x1AC / 4] = ("clk_gmac1_gtxc", Delay);
|
||||
t[0x1A8 / 4] = ("clk_gmac5_axi64_tx_inv", Inv(30, Int(0x1A4 / 4)));
|
||||
t[0x1AC / 4] = ("clk_gmac1_gtxc", Gate(31, Int(0x190 / 4)));
|
||||
t[0x1B0 / 4] = ("clk_gmac0_gtx", Gate(31, None));
|
||||
t[0x1B4 / 4] = ("clk_gmac0_ptp", Gate(31, None));
|
||||
t[0x1B4 / 4] = ("clk_gmac0_ptp", Gate(31, Int(0x18C / 4)));
|
||||
t[0x1B8 / 4] = ("clk_gmac_phy", Gate(31, None));
|
||||
t[0x1BC / 4] = ("clk_gmac0_gtxc", Delay);
|
||||
t[0x1BC / 4] = ("clk_gmac0_gtxc", Gate(31, Int(0x1B0 / 4)));
|
||||
|
||||
t[0x244 / 4] = ("clk_u0_uart_apb", Gate(31, None));
|
||||
t[0x248 / 4] = ("clk_u0_uart_core", Gate(31, Ext(PARENT_CLK_OSC)));
|
||||
@ -98,29 +139,7 @@ impl Device for Syscrg {
|
||||
impl ClockController for Syscrg {
|
||||
fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
let index = clock.ok_or(Error::InvalidArgument)?;
|
||||
let (name, reg) = Self::map_clock_index(index)
|
||||
.ok_or(Error::InvalidArgument)
|
||||
.inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", clock))?;
|
||||
let regs = self.ensure_init()?;
|
||||
let mut lock = regs.lock();
|
||||
|
||||
match reg {
|
||||
ClockRegister::Gate(bit, _) => {
|
||||
log::info!("jh7110-syscrg: enable {name:?}");
|
||||
lock[index as usize] |= 1 << bit;
|
||||
Ok(())
|
||||
}
|
||||
ClockRegister::Inv(bit) => {
|
||||
log::info!("jh7110-syscrg: enable clk inv {name:?}");
|
||||
lock[index as usize] |= 1 << bit;
|
||||
Ok(())
|
||||
}
|
||||
ClockRegister::Delay => Ok(()),
|
||||
ClockRegister::Unimp => {
|
||||
log::warn!("jh7110-syscrg: clock not implemented: {name:?}");
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
self.clk_enable_int(index, 0)
|
||||
}
|
||||
|
||||
fn disable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
|
||||
@ -146,7 +165,7 @@ impl ClockController for Syscrg {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
},
|
||||
ClockRegister::Unimp | ClockRegister::Delay | ClockRegister::Inv(_) => {
|
||||
ClockRegister::Unimp | ClockRegister::Div(_) | ClockRegister::Inv(_, _) => {
|
||||
log::warn!("jh7110-syscrg: unimplemented clock {:?}", name);
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
@ -159,25 +178,45 @@ impl ClockController for Syscrg {
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscrg {
|
||||
fn rst_trigger(&self, reset: u32, assert: bool) -> Result<(), Error> {
|
||||
let reg = (190 + reset / 32) as usize;
|
||||
let bit = reset % 32;
|
||||
let regs = self.ensure_init()?;
|
||||
let mut regs = regs.lock();
|
||||
|
||||
let expect = if assert {
|
||||
regs[reg] |= 1 << bit;
|
||||
1 << bit
|
||||
} else {
|
||||
regs[reg] &= !(1 << bit);
|
||||
0
|
||||
};
|
||||
|
||||
let mut timeout = 1 << 20;
|
||||
while timeout > 0 && regs[reg] & (1 << bit) != expect {
|
||||
core::hint::spin_loop();
|
||||
timeout -= 1;
|
||||
}
|
||||
|
||||
if timeout > 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
log::warn!("jh7110-syscrg: reset timeout {reset}");
|
||||
Err(Error::TimedOut)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResetController for Syscrg {
|
||||
fn assert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
|
||||
let reset = reset.ok_or(Error::InvalidArgument)?;
|
||||
let reg = reset / 32;
|
||||
let bit = reset % 32;
|
||||
let regs = self.ensure_init()?;
|
||||
|
||||
regs.lock()[190 + reg as usize] |= 1 << bit;
|
||||
Ok(())
|
||||
self.rst_trigger(reset, true)
|
||||
}
|
||||
|
||||
fn deassert_reset(&self, reset: Option<u32>) -> Result<(), Error> {
|
||||
let reset = reset.ok_or(Error::InvalidArgument)?;
|
||||
let reg = reset / 32;
|
||||
let bit = reset % 32;
|
||||
let regs = self.ensure_init()?;
|
||||
|
||||
regs.lock()[190 + reg as usize] &= !(1 << bit);
|
||||
Ok(())
|
||||
self.rst_trigger(reset, false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,7 +249,7 @@ impl DeviceTreeResetController for Syscrg {
|
||||
device_tree_driver! {
|
||||
compatible: ["starfive,jh7110-syscrg"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let osc = node.named_clock("osc")?;
|
||||
|
||||
|
@ -82,7 +82,7 @@ struct Context {
|
||||
enable: IrqSafeRwLock<DeviceMemoryIo<'static, ContextEnableRegs>>,
|
||||
control: IrqSafeRwLock<DeviceMemoryIo<'static, ContextControlRegs>>,
|
||||
// TODO scale the table depending on effective MAX_IRQS value
|
||||
table: IrqSafeRwLock<FixedInterruptTable<64>>,
|
||||
table: IrqSafeRwLock<FixedInterruptTable<128>>,
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
@ -288,7 +288,7 @@ fn map_context_to_hart(target: u32) -> Option<u32> {
|
||||
device_tree_driver! {
|
||||
compatible: ["starfive,jh7110-plic", "sifive,plic-1.0.0", "riscv,plic0"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let ndev = node.prop_usize("riscv,ndev")?;
|
||||
let iext = node.property("interrupts-extended")?;
|
||||
|
@ -190,7 +190,7 @@ impl DebugSink for Ns16550a {
|
||||
device_tree_driver!(
|
||||
compatible: ["ns16550a"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
log::debug!("ns16550a base = {base:#x}");
|
||||
let irq = node.interrupt(0)?;
|
||||
|
@ -284,7 +284,7 @@ impl TerminalOutput for Inner {
|
||||
device_tree_driver! {
|
||||
compatible: ["snps,dw-apb-uart"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0)?;
|
||||
let irq = node.interrupt(0)?;
|
||||
let clk_baud = node.named_clock("baudclk")?;
|
||||
|
@ -33,6 +33,29 @@ pub fn kinit() -> Result<(), Error> {
|
||||
assert!(!ArchitectureImpl::interrupt_mask());
|
||||
log::info!("In main");
|
||||
|
||||
// Initialize late device tree devices
|
||||
#[cfg(any(rust_analyzer, target_arch = "riscv64", target_arch = "aarch64"))]
|
||||
{
|
||||
use device_tree::driver::InitSequence;
|
||||
|
||||
device_tree::driver::lazy_init(
|
||||
|_| (),
|
||||
|node, error| {
|
||||
log::error!("{}: {error:?}", node.name().unwrap_or("<unknown>"));
|
||||
},
|
||||
InitSequence::Late,
|
||||
);
|
||||
device_tree::driver::init_irqs(
|
||||
|_| (),
|
||||
|node, error| {
|
||||
log::error!(
|
||||
"{}: irq init error: {error:?}",
|
||||
node.name().unwrap_or("<unknown>")
|
||||
);
|
||||
},
|
||||
InitSequence::Late,
|
||||
);
|
||||
}
|
||||
// Initialize PCI devices
|
||||
if let Err(error) = PciBusManager::setup_bus_devices(false) {
|
||||
log::error!("pci bus setup error: {error:?}");
|
||||
|
@ -1,9 +1,17 @@
|
||||
//! System function call handlers
|
||||
|
||||
use abi::{error::Error, io::RawFd, process::SignalEntryData, SyscallFunction};
|
||||
use abi::{
|
||||
error::Error,
|
||||
io::RawFd,
|
||||
process::{ExitCode, Signal, SignalEntryData},
|
||||
SyscallFunction,
|
||||
};
|
||||
use kernel_arch::task::TaskFrame;
|
||||
use libk::{
|
||||
task::process::{Process, ProcessIo},
|
||||
task::{
|
||||
process::{Process, ProcessIo},
|
||||
thread::Thread,
|
||||
},
|
||||
vfs::NodeRef,
|
||||
};
|
||||
use libk_util::sync::IrqSafeSpinlockGuard;
|
||||
@ -53,7 +61,10 @@ pub unsafe fn handle_signal_exit<F: TaskFrame>(frame: &mut F) {
|
||||
let saved_data: &SignalEntryData = match arg::ref_const(frame.argument() as _) {
|
||||
Ok(r) => r,
|
||||
Err(err) => {
|
||||
todo!("Invalid SignalEntryData pointer: {:?}", err)
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
log::warn!("#{}: invalid SignalEntryData struct: {err:?}", process.id);
|
||||
thread.exit_process(ExitCode::BySignal(Ok(Signal::MemoryAccessViolation)));
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user