use core::fmt::{self, Display, Formatter};
use core::ops::Deref;
use crate::error::{PropertyError, StandardError};
use crate::fdt::{Fdt, FdtNode};
use crate::standard::Reg;
use crate::{Cells, Node, Property};
impl<'a> Fdt<'a> {
pub fn memory(self) -> Result<Memory<FdtNode<'a>>, StandardError> {
let node = self
.find_node("/memory")
.ok_or(StandardError::MemoryMissing)?;
Ok(Memory { node })
}
#[must_use]
pub fn reserved_memory(self) -> Option<impl Iterator<Item = ReservedMemory<FdtNode<'a>>>> {
Some(
self.find_node("/reserved-memory")?
.children()
.map(|node| ReservedMemory { node }),
)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Memory<N> {
node: N,
}
impl<N> Deref for Memory<N> {
type Target = N;
fn deref(&self) -> &Self::Target {
&self.node
}
}
impl<N: Display> Display for Memory<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.node.fmt(f)
}
}
impl<'a, N: Node<'a>> Memory<N> {
pub fn initial_mapped_area(
&self,
) -> Result<Option<impl Iterator<Item = InitialMappedArea> + use<'a, N>>, PropertyError> {
if let Some(property) = self.node.property("initial-mapped-area") {
Ok(Some(
property
.as_prop_encoded_array([2, 2, 1])?
.map(|chunk| InitialMappedArea::from_cells(chunk)),
))
} else {
Ok(None)
}
}
#[must_use]
pub fn hotpluggable(&self) -> bool {
self.node.property("hotpluggable").is_some()
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct InitialMappedArea {
pub effective_address: u64,
pub physical_address: u64,
pub size: u32,
}
impl InitialMappedArea {
#[expect(
clippy::unwrap_used,
reason = "The Cells passed are always the correct size"
)]
fn from_cells([ea, pa, size]: [Cells; 3]) -> Self {
Self {
effective_address: ea.to_int().unwrap(),
physical_address: pa.to_int().unwrap(),
size: size.to_int().unwrap(),
}
}
}
#[derive(Clone, Copy, Debug)]
pub struct ReservedMemory<N> {
node: N,
}
impl<N> Deref for ReservedMemory<N> {
type Target = N;
fn deref(&self) -> &Self::Target {
&self.node
}
}
impl<N: Display> Display for ReservedMemory<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.node.fmt(f)
}
}
impl<'a, N: Node<'a>> ReservedMemory<N> {
pub fn size(&self) -> Result<Option<Cells<'a>>, PropertyError> {
self.node
.property("size")
.map(|value| value.as_cells())
.transpose()
}
pub fn alignment(&self) -> Result<Option<Cells<'a>>, PropertyError> {
self.node
.property("alignment")
.map(|value| value.as_cells())
.transpose()
}
pub fn no_map(&self) -> bool {
self.node.property("no-map").is_some()
}
pub fn no_map_fixup(&self) -> bool {
self.node.property("no-map-fixup").is_some()
}
pub fn reusable(&self) -> bool {
self.node.property("reusable").is_some()
}
}
impl<'a> ReservedMemory<FdtNode<'a>> {
pub fn alloc_ranges(
&self,
) -> Result<Option<impl Iterator<Item = Reg<'a>> + use<'a>>, StandardError> {
let address_cells = self.node.parent_address_space.address_cells as usize;
let size_cells = self.node.parent_address_space.size_cells as usize;
if let Some(property) = self.property("alloc_ranges") {
Ok(Some(
property
.as_prop_encoded_array([address_cells, size_cells])?
.map(Reg::from_cells),
))
} else {
Ok(None)
}
}
}