#[cfg(target_arch = "aarch64")]
use ax_arm_pl031::Rtc as Pl031Rtc;
use log::{debug, info};
use rdrive::{PlatformDevice, probe::OnProbeError, register::FdtInfo};
#[cfg(target_arch = "riscv64")]
use riscv_goldfish::Rtc as GoldfishRtc;
use crate::mmio::iomap;
#[cfg(target_arch = "aarch64")]
crate::model_register!(
name: "pl031 rtc",
level: ProbeLevel::PostKernel,
priority: ProbePriority::DEFAULT,
probe_kinds: &[ProbeKind::Fdt {
compatibles: &["arm,pl031"],
on_probe: probe_pl031
}],
);
#[cfg(target_arch = "riscv64")]
crate::model_register!(
name: "goldfish rtc",
level: ProbeLevel::PostKernel,
priority: ProbePriority::DEFAULT,
probe_kinds: &[ProbeKind::Fdt {
compatibles: &["google,goldfish-rtc"],
on_probe: probe_goldfish
}],
);
#[cfg(target_arch = "aarch64")]
fn probe_pl031(info: FdtInfo<'_>, _plat_dev: PlatformDevice) -> Result<(), OnProbeError> {
let mmio_base = map_first_reg(&info)?;
let rtc = unsafe { Pl031Rtc::new(mmio_base.as_ptr().cast()) };
init_epoch_offset(info.node.name(), u64::from(rtc.get_unix_timestamp()))
}
#[cfg(target_arch = "riscv64")]
fn probe_goldfish(info: FdtInfo<'_>, _plat_dev: PlatformDevice) -> Result<(), OnProbeError> {
let mmio_base = map_first_reg(&info)?;
let rtc = GoldfishRtc::new(mmio_base.as_ptr() as usize);
init_epoch_offset(info.node.name(), rtc.get_unix_timestamp())
}
fn map_first_reg(info: &FdtInfo<'_>) -> Result<core::ptr::NonNull<u8>, OnProbeError> {
let regs = info.node.regs();
let Some(base_reg) = regs.first() else {
return Err(OnProbeError::other(alloc::format!(
"[{}] has no reg",
info.node.name()
)));
};
let mmio_size = base_reg.size.unwrap_or(0x1000);
iomap(base_reg.address as usize, mmio_size as usize)
}
fn init_epoch_offset(node_name: &str, unix_timestamp: u64) -> Result<(), OnProbeError> {
if unix_timestamp == 0 {
return Err(OnProbeError::other(alloc::format!(
"[{node_name}] returned zero unix timestamp"
)));
}
let epoch_time_nanos = unix_timestamp * 1_000_000_000;
if axklib::time::try_init_epoch_offset(epoch_time_nanos) {
info!("Initialized wall clock from {node_name}");
} else {
debug!("Skipping RTC {node_name} because epoch offset is already initialized",);
}
Ok(())
}