dtb: Apply bus mappings
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
use super::InterruptController;
|
||||
use crate::dtb::irqchip::{InterruptHandler, IrqDesc};
|
||||
use crate::dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqDesc},
|
||||
};
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use fdt::{node::FdtNode, Fdt};
|
||||
use log::info;
|
||||
@@ -40,12 +43,12 @@ impl GenericInterruptController {
|
||||
}
|
||||
pub fn parse(fdt: &Fdt) -> Result<(usize, usize, usize, usize)> {
|
||||
if let Some(node) = fdt.find_compatible(&["arm,cortex-a15-gic", "arm,gic-400"]) {
|
||||
return GenericInterruptController::parse_inner(&node);
|
||||
return GenericInterruptController::parse_inner(fdt, &node);
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
fn parse_inner(node: &FdtNode) -> Result<(usize, usize, usize, usize)> {
|
||||
fn parse_inner(fdt: &Fdt, node: &FdtNode) -> Result<(usize, usize, usize, usize)> {
|
||||
//assert address_cells == 0x2, size_cells == 0x2
|
||||
let reg = node.reg().unwrap();
|
||||
let mut regs = (0, 0, 0, 0);
|
||||
@@ -55,9 +58,10 @@ impl GenericInterruptController {
|
||||
if chunk.size.is_none() {
|
||||
break;
|
||||
}
|
||||
let addr = get_mmio_address(fdt, node, &chunk).unwrap();
|
||||
match idx {
|
||||
0 => (regs.0, regs.1) = (chunk.starting_address as usize, chunk.size.unwrap()),
|
||||
2 => (regs.2, regs.3) = (chunk.starting_address as usize, chunk.size.unwrap()),
|
||||
0 => (regs.0, regs.1) = (addr, chunk.size.unwrap()),
|
||||
2 => (regs.2, regs.3) = (addr, chunk.size.unwrap()),
|
||||
_ => break,
|
||||
}
|
||||
idx += 2;
|
||||
|
||||
@@ -3,7 +3,10 @@ use core::arch::asm;
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
|
||||
use super::{gic::GicDistIf, InterruptController};
|
||||
use crate::dtb::irqchip::{InterruptHandler, IrqDesc};
|
||||
use crate::dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqDesc},
|
||||
};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
@@ -46,16 +49,19 @@ impl GicV3 {
|
||||
|
||||
// Read registers
|
||||
let mut chunks = node.reg().unwrap();
|
||||
if let Some(gicd) = chunks.next() {
|
||||
if let Some(gicd) = chunks.next()
|
||||
&& let Some(addr) = get_mmio_address(fdt, &node, &gicd)
|
||||
{
|
||||
unsafe {
|
||||
self.gic_dist_if
|
||||
.init(crate::PHYS_OFFSET + gicd.starting_address as usize);
|
||||
self.gic_dist_if.init(crate::PHYS_OFFSET + addr);
|
||||
}
|
||||
}
|
||||
for _ in 0..gicrs {
|
||||
if let Some(gicr) = chunks.next() {
|
||||
self.gicrs
|
||||
.push((gicr.starting_address as usize, gicr.size.unwrap()));
|
||||
self.gicrs.push((
|
||||
get_mmio_address(fdt, &node, &gicr).unwrap(),
|
||||
gicr.size.unwrap(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ use fdt::{node::FdtNode, Fdt};
|
||||
use log::{debug, error, info};
|
||||
|
||||
use super::InterruptController;
|
||||
use crate::dtb::irqchip::{InterruptHandler, IrqDesc, IRQ_CHIP};
|
||||
use crate::dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqDesc, IRQ_CHIP},
|
||||
};
|
||||
use syscall::{
|
||||
error::{Error, EINVAL},
|
||||
Result,
|
||||
@@ -64,15 +67,15 @@ impl Bcm2835ArmInterruptController {
|
||||
}
|
||||
pub fn parse(fdt: &Fdt) -> Result<(usize, usize, Option<usize>)> {
|
||||
if let Some(node) = fdt.find_compatible(&["brcm,bcm2836-armctrl-ic"]) {
|
||||
return unsafe { Bcm2835ArmInterruptController::parse_inner(&node) };
|
||||
return unsafe { Bcm2835ArmInterruptController::parse_inner(fdt, &node) };
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
unsafe fn parse_inner(node: &FdtNode) -> Result<(usize, usize, Option<usize>)> {
|
||||
unsafe fn parse_inner(fdt: &Fdt, node: &FdtNode) -> Result<(usize, usize, Option<usize>)> {
|
||||
//assert address_cells == 0x1, size_cells == 0x1
|
||||
let mem = node.reg().unwrap().nth(0).unwrap();
|
||||
let base = mem.starting_address as u32;
|
||||
let base = get_mmio_address(fdt, node, &mem).unwrap();
|
||||
let size = mem.size.unwrap() as u32;
|
||||
let mut ret_virq = None;
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use super::InterruptController;
|
||||
use crate::dtb::irqchip::{InterruptHandler, IrqDesc};
|
||||
use crate::dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptHandler, IrqDesc},
|
||||
};
|
||||
use core::{
|
||||
arch::asm,
|
||||
ptr::{read_volatile, write_volatile},
|
||||
@@ -68,16 +71,17 @@ impl Bcm2836ArmInterruptController {
|
||||
}
|
||||
pub fn parse(fdt: &Fdt) -> Result<(usize, usize)> {
|
||||
if let Some(node) = fdt.find_compatible(&["brcm,bcm2836-l1-intc"]) {
|
||||
return Bcm2836ArmInterruptController::parse_inner(&node);
|
||||
return Bcm2836ArmInterruptController::parse_inner(fdt, &node);
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
fn parse_inner(node: &FdtNode) -> Result<(usize, usize)> {
|
||||
fn parse_inner(fdt: &Fdt, node: &FdtNode) -> Result<(usize, usize)> {
|
||||
//assert address_cells == 0x1, size_cells == 0x1
|
||||
let reg = node.reg().unwrap().nth(0).unwrap();
|
||||
let addr = get_mmio_address(fdt, node, ®).unwrap();
|
||||
|
||||
Ok((reg.starting_address as usize, reg.size.unwrap()))
|
||||
Ok((addr, reg.size.unwrap()))
|
||||
}
|
||||
|
||||
unsafe fn init(&mut self) {
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
use crate::{dtb::get_mmio_address, time};
|
||||
use core::ptr::read_volatile;
|
||||
|
||||
use crate::time;
|
||||
|
||||
static RTC_DR: usize = 0x000;
|
||||
|
||||
pub unsafe fn init(fdt: &fdt::Fdt) {
|
||||
if let Some(node) = fdt.find_compatible(&["arm,pl031"]) {
|
||||
match node.reg().and_then(|mut iter| iter.next()) {
|
||||
Some(reg) => {
|
||||
let mut rtc = Pl031rtc {
|
||||
phys: reg.starting_address as usize,
|
||||
};
|
||||
match node
|
||||
.reg()
|
||||
.and_then(|mut iter| iter.next())
|
||||
.and_then(|region| get_mmio_address(fdt, &node, ®ion))
|
||||
{
|
||||
Some(phys) => {
|
||||
let mut rtc = Pl031rtc { phys };
|
||||
log::info!("PL031 RTC at {:#x}", rtc.phys);
|
||||
*time::START.lock() = (rtc.time() as u128) * time::NANOS_PER_SEC;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use crate::{
|
||||
arch::{device::irqchip::hlic, start::BOOT_HART_ID},
|
||||
dtb::irqchip::{InterruptController, InterruptHandler, IrqDesc, IRQ_CHIP},
|
||||
dtb::{
|
||||
get_mmio_address,
|
||||
irqchip::{InterruptController, InterruptHandler, IrqDesc, IRQ_CHIP},
|
||||
},
|
||||
};
|
||||
use core::{mem, num::NonZero, sync::atomic::Ordering};
|
||||
use fdt::Fdt;
|
||||
@@ -120,15 +123,14 @@ impl InterruptController for Plic {
|
||||
|
||||
// MMIO region
|
||||
let reg = my_node.reg().unwrap().next().unwrap();
|
||||
let addr = get_mmio_address(&fdt, &my_node, ®).unwrap();
|
||||
// Specifies how many external interrupts are supported by this controller.
|
||||
let ndev = my_node
|
||||
.property("riscv,ndev")
|
||||
.and_then(|x| x.as_usize())
|
||||
.unwrap();
|
||||
|
||||
unsafe {
|
||||
self.regs = reg.starting_address.add(crate::PHYS_OFFSET) as *mut PlicRegs;
|
||||
}
|
||||
self.regs = (addr + crate::PHYS_OFFSET) as *mut PlicRegs;
|
||||
self.ndev = ndev;
|
||||
|
||||
self.virq_base = *irq_idx;
|
||||
|
||||
+46
-6
@@ -4,7 +4,11 @@ use crate::startup::memory::{register_memory_region, BootloaderMemoryKind};
|
||||
use alloc::vec::Vec;
|
||||
use byteorder::{ByteOrder, BE};
|
||||
use core::slice;
|
||||
use fdt::{node::NodeProperty, Fdt};
|
||||
use fdt::{
|
||||
node::{FdtNode, NodeProperty},
|
||||
standard_nodes::MemoryRegion,
|
||||
Fdt,
|
||||
};
|
||||
use log::debug;
|
||||
use spin::once::Once;
|
||||
|
||||
@@ -114,21 +118,56 @@ pub fn register_dev_memory_ranges(dt: &Fdt) {
|
||||
);
|
||||
}
|
||||
|
||||
// also add all soc-internal devices please because they might not be shown in ranges
|
||||
// also add all soc-internal devices because they might not be shown in ranges
|
||||
// (identity-mapped soc bus may have empty ranges)
|
||||
for device in soc_node.children() {
|
||||
if let Some(reg) = device.reg() {
|
||||
for entry in reg {
|
||||
if let Some(size) = entry.size {
|
||||
let addr = entry.starting_address as usize;
|
||||
log::debug!("soc device {} 0x{:08x} 0x{:08x}", device.name, addr, size);
|
||||
|
||||
register_memory_region(addr, size, BootloaderMemoryKind::Device);
|
||||
if let Some(mapped_addr) = get_mmio_address(dt, &device, &entry) {
|
||||
debug!(
|
||||
"soc device {} 0x{:08x} -> 0x{:08x} size 0x{:08x}",
|
||||
device.name, addr, mapped_addr, size
|
||||
);
|
||||
register_memory_region(mapped_addr, size, BootloaderMemoryKind::Device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mmio_address(fdt: &Fdt, _device: &FdtNode, region: &MemoryRegion) -> Option<usize> {
|
||||
/* DT spec 2.3.8 "ranges":
|
||||
* The ranges property provides a means of defining a mapping or translation between
|
||||
* the address space of the bus (the child address space) and the address space of the bus
|
||||
* node’s parent (the parent address space).
|
||||
* If the property is defined with an <empty> value, it specifies that the parent and child
|
||||
* address space is identical, and no address translation is required.
|
||||
* If the property is not present in a bus node, it is assumed that no mapping exists between
|
||||
* children of the node and the parent address space.
|
||||
*/
|
||||
|
||||
// FIXME assumes all the devices are connected to CPUs via the /soc bus
|
||||
let mut mapped_addr = region.starting_address as usize;
|
||||
let size = region.size.unwrap_or(0).saturating_sub(1);
|
||||
let last_address = mapped_addr.saturating_add(size);
|
||||
if let Some(parent) = fdt.find_node("/soc") {
|
||||
let mut ranges = parent.ranges().map(|f| f.peekable())?;
|
||||
if ranges.peek().is_some() {
|
||||
let parent_range = ranges.find(|x| {
|
||||
x.child_bus_address <= mapped_addr && last_address - x.child_bus_address <= x.size
|
||||
})?;
|
||||
mapped_addr = parent_range
|
||||
.parent_bus_address
|
||||
.checked_add(mapped_addr - parent_range.child_bus_address)?;
|
||||
let _ = mapped_addr.checked_add(size)?;
|
||||
}
|
||||
}
|
||||
Some(mapped_addr)
|
||||
}
|
||||
|
||||
pub fn diag_uart_range<'a>(dtb: &'a Fdt) -> Option<(usize, usize, bool, bool, &'a str)> {
|
||||
let stdout_path = dtb.chosen().stdout()?;
|
||||
let uart_node = stdout_path.node();
|
||||
@@ -140,9 +179,10 @@ pub fn diag_uart_range<'a>(dtb: &'a Fdt) -> Option<(usize, usize, bool, bool, &'
|
||||
|
||||
let mut reg = uart_node.reg()?;
|
||||
let memory = reg.nth(0)?;
|
||||
let address = get_mmio_address(dtb, &uart_node, &memory)?;
|
||||
|
||||
Some((
|
||||
memory.starting_address as usize,
|
||||
address,
|
||||
memory.size?,
|
||||
skip_init,
|
||||
cts_event_walkaround,
|
||||
|
||||
Reference in New Issue
Block a user