#![allow(dead_code)]
use tock_registers::{register_bitfields, register_structs, registers::ReadWrite};
use crate::rstc::{Rstc, RSTC_BASE};
pub const SEC_SYS_BASE: usize = 0x020B0000;
pub const SOFT_CPU_RSTN_ADDR: usize = RSTC_BASE + 0x024;
register_bitfields! [
u32,
pub SEC_SYS_CTRL [
SEC_CPU_EN OFFSET(13) NUMBITS(1) []
],
pub SEC_SYS_BOOT_ADDR_L [
ADDR_L OFFSET(0) NUMBITS(32) []
],
pub SEC_SYS_BOOT_ADDR_H [
ADDR_H OFFSET(0) NUMBITS(32) []
]
];
register_structs! {
pub SecSysRegisters {
(0x000 => _reserved0),
(0x004 => pub ctrl: ReadWrite<u32, SEC_SYS_CTRL::Register>),
(0x008 => _reserved1),
(0x020 => pub boot_addr_l: ReadWrite<u32, SEC_SYS_BOOT_ADDR_L::Register>),
(0x024 => pub boot_addr_h: ReadWrite<u32, SEC_SYS_BOOT_ADDR_H::Register>),
(0x028 => @END),
}
}
pub struct SecSys {
regs: &'static SecSysRegisters,
}
impl SecSys {
pub unsafe fn new() -> Self {
unsafe {
Self {
regs: &*(SEC_SYS_BASE as *const SecSysRegisters),
}
}
}
pub unsafe fn from_base_address(base: usize) -> Self {
unsafe {
Self {
regs: &*(base as *const SecSysRegisters),
}
}
}
pub fn enable_secondary_cpu(&self) {
use tock_registers::interfaces::ReadWriteable;
self.regs.ctrl.modify(SEC_SYS_CTRL::SEC_CPU_EN::SET);
}
pub fn disable_secondary_cpu(&self) {
use tock_registers::interfaces::ReadWriteable;
self.regs.ctrl.modify(SEC_SYS_CTRL::SEC_CPU_EN::CLEAR);
}
pub fn is_secondary_cpu_enabled(&self) -> bool {
use tock_registers::interfaces::Readable;
self.regs.ctrl.is_set(SEC_SYS_CTRL::SEC_CPU_EN)
}
pub fn set_boot_address(&self, addr: u64) {
use tock_registers::interfaces::Writeable;
self.regs
.boot_addr_l
.write(SEC_SYS_BOOT_ADDR_L::ADDR_L.val(addr as u32));
self.regs
.boot_addr_h
.write(SEC_SYS_BOOT_ADDR_H::ADDR_H.val((addr >> 32) as u32));
}
pub fn get_boot_address(&self) -> u64 {
use tock_registers::interfaces::Readable;
let low = self.regs.boot_addr_l.read(SEC_SYS_BOOT_ADDR_L::ADDR_L) as u64;
let high = self.regs.boot_addr_h.read(SEC_SYS_BOOT_ADDR_H::ADDR_H) as u64;
(high << 32) | low
}
pub unsafe fn start_secondary_core(&self, entry: u64) {
unsafe {
let rstc = Rstc::from_base_address(RSTC_BASE);
rstc.assert_cpu_sys_reset(2);
self.enable_secondary_cpu();
self.set_boot_address(entry);
#[cfg(target_arch = "riscv64")]
{
core::arch::asm!("fence.i");
}
#[cfg(target_arch = "riscv32")]
{
core::arch::asm!("fence.i");
}
#[cfg(not(any(target_arch = "riscv64", target_arch = "riscv32")))]
{
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
rstc.release_cpu_sys_reset(2);
#[cfg(target_arch = "riscv64")]
{
core::arch::asm!("fence.i");
}
#[cfg(target_arch = "riscv32")]
{
core::arch::asm!("fence.i");
}
#[cfg(not(any(target_arch = "riscv64", target_arch = "riscv32")))]
{
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
}
}
pub fn regs(&self) -> &'static SecSysRegisters {
self.regs
}
}
pub unsafe fn start_secondary_core(entry: u64) {
unsafe {
let sec_sys = SecSys::new();
sec_sys.start_secondary_core(entry);
}
}
pub unsafe fn start_secondary_core_raw(entry: u64) {
unsafe {
let rst_ptr = SOFT_CPU_RSTN_ADDR as *mut u32;
let sec_ctrl_ptr = (SEC_SYS_BASE + 0x004) as *mut u32;
let boot_addr_l_ptr = (SEC_SYS_BASE + 0x020) as *mut u32;
let boot_addr_h_ptr = (SEC_SYS_BASE + 0x024) as *mut u32;
const CPUSYS2_MASK: u32 = 1 << 6;
const SEC_CPU_EN_MASK: u32 = 1 << 13;
let rst_val = rst_ptr.read_volatile();
rst_ptr.write_volatile(rst_val & !CPUSYS2_MASK);
let ctrl_val = sec_ctrl_ptr.read_volatile();
sec_ctrl_ptr.write_volatile(ctrl_val | SEC_CPU_EN_MASK);
boot_addr_l_ptr.write_volatile(entry as u32);
boot_addr_h_ptr.write_volatile((entry >> 32) as u32);
#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
{
core::arch::asm!("fence.i");
}
#[cfg(not(any(target_arch = "riscv64", target_arch = "riscv32")))]
{
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
let rst_val = rst_ptr.read_volatile();
rst_ptr.write_volatile(rst_val | CPUSYS2_MASK);
#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
{
core::arch::asm!("fence.i");
}
#[cfg(not(any(target_arch = "riscv64", target_arch = "riscv32")))]
{
core::sync::atomic::fence(core::sync::atomic::Ordering::SeqCst);
}
}
}