* Peripheral ref/sha (#312) * Add SHA to list of peripherals to be created * Refactor SHA peripheral to use PeripheralRef * Update SHA examples to get them building again * Fix async time drivers * Fix usb otg * Fix s3 Co-authored-by: Jesse Braham <jessebraham@users.noreply.github.com>
240 lines
7.0 KiB
Rust
240 lines
7.0 KiB
Rust
//! Control CPU Cores
|
|
|
|
use core::marker::PhantomData;
|
|
|
|
use xtensa_lx::set_stack_pointer;
|
|
|
|
use crate::Cpu;
|
|
|
|
static mut START_CORE1_FUNCTION: Option<&'static mut (dyn FnMut() + 'static)> = None;
|
|
|
|
/// Will park the APP (second) core when dropped
|
|
#[must_use]
|
|
pub struct AppCoreGuard<'a> {
|
|
phantom: PhantomData<&'a ()>,
|
|
}
|
|
|
|
impl<'a> Drop for AppCoreGuard<'a> {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
internal_park_core(Cpu::AppCpu);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
CoreAlreadyRunning,
|
|
}
|
|
|
|
/// Control CPU Cores
|
|
pub struct CpuControl {
|
|
_cpu_control: crate::system::CpuControl,
|
|
}
|
|
|
|
unsafe fn internal_park_core(core: Cpu) {
|
|
let rtc_control = crate::peripherals::RTC_CNTL::PTR;
|
|
let rtc_control = &*rtc_control;
|
|
|
|
match core {
|
|
Cpu::ProCpu => {
|
|
rtc_control
|
|
.sw_cpu_stall
|
|
.modify(|_, w| w.sw_stall_procpu_c1().bits(0x21));
|
|
rtc_control
|
|
.options0
|
|
.modify(|_, w| w.sw_stall_procpu_c0().bits(0x02));
|
|
}
|
|
Cpu::AppCpu => {
|
|
rtc_control
|
|
.sw_cpu_stall
|
|
.modify(|_, w| w.sw_stall_appcpu_c1().bits(0x21));
|
|
rtc_control
|
|
.options0
|
|
.modify(|_, w| w.sw_stall_appcpu_c0().bits(0x02));
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CpuControl {
|
|
pub fn new(cpu_control: crate::system::CpuControl) -> CpuControl {
|
|
CpuControl {
|
|
_cpu_control: cpu_control,
|
|
}
|
|
}
|
|
|
|
/// Park the given core
|
|
pub unsafe fn park_core(&mut self, core: Cpu) {
|
|
internal_park_core(core);
|
|
}
|
|
|
|
/// Unpark the given core
|
|
pub fn unpark_core(&mut self, core: Cpu) {
|
|
let rtc_control = crate::peripherals::RTC_CNTL::PTR;
|
|
let rtc_control = unsafe { &*rtc_control };
|
|
|
|
match core {
|
|
Cpu::ProCpu => {
|
|
rtc_control
|
|
.sw_cpu_stall
|
|
.modify(|_, w| unsafe { w.sw_stall_procpu_c1().bits(0) });
|
|
rtc_control
|
|
.options0
|
|
.modify(|_, w| unsafe { w.sw_stall_procpu_c0().bits(0) });
|
|
}
|
|
Cpu::AppCpu => {
|
|
rtc_control
|
|
.sw_cpu_stall
|
|
.modify(|_, w| unsafe { w.sw_stall_appcpu_c1().bits(0) });
|
|
rtc_control
|
|
.options0
|
|
.modify(|_, w| unsafe { w.sw_stall_appcpu_c0().bits(0) });
|
|
}
|
|
}
|
|
}
|
|
|
|
fn flush_cache(&mut self, core: Cpu) {
|
|
let dport_control = crate::peripherals::DPORT::PTR;
|
|
let dport_control = unsafe { &*dport_control };
|
|
|
|
match core {
|
|
Cpu::ProCpu => {
|
|
dport_control
|
|
.pro_cache_ctrl
|
|
.modify(|_, w| w.pro_cache_flush_ena().clear_bit());
|
|
dport_control
|
|
.pro_cache_ctrl
|
|
.modify(|_, w| w.pro_cache_flush_ena().set_bit());
|
|
while dport_control
|
|
.pro_cache_ctrl
|
|
.read()
|
|
.pro_cache_flush_done()
|
|
.bit_is_clear()
|
|
{}
|
|
|
|
dport_control
|
|
.pro_cache_ctrl
|
|
.modify(|_, w| w.pro_cache_flush_ena().clear_bit());
|
|
}
|
|
Cpu::AppCpu => {
|
|
dport_control
|
|
.app_cache_ctrl
|
|
.modify(|_, w| w.app_cache_flush_ena().clear_bit());
|
|
dport_control
|
|
.app_cache_ctrl
|
|
.modify(|_, w| w.app_cache_flush_ena().set_bit());
|
|
while dport_control
|
|
.app_cache_ctrl
|
|
.read()
|
|
.app_cache_flush_done()
|
|
.bit_is_clear()
|
|
{}
|
|
dport_control
|
|
.app_cache_ctrl
|
|
.modify(|_, w| w.app_cache_flush_ena().clear_bit());
|
|
}
|
|
};
|
|
}
|
|
|
|
fn enable_cache(&mut self, core: Cpu) {
|
|
let spi0 = unsafe { &(*crate::peripherals::SPI0::ptr()) };
|
|
|
|
let dport_control = crate::peripherals::DPORT::PTR;
|
|
let dport_control = unsafe { &*dport_control };
|
|
|
|
match core {
|
|
Cpu::ProCpu => {
|
|
spi0.cache_fctrl.modify(|_, w| w.cache_req_en().set_bit());
|
|
dport_control
|
|
.pro_cache_ctrl
|
|
.modify(|_, w| w.pro_cache_enable().set_bit());
|
|
}
|
|
Cpu::AppCpu => {
|
|
spi0.cache_fctrl.modify(|_, w| w.cache_req_en().set_bit());
|
|
dport_control
|
|
.app_cache_ctrl
|
|
.modify(|_, w| w.app_cache_enable().set_bit());
|
|
}
|
|
};
|
|
}
|
|
|
|
unsafe fn start_core1_init() -> ! {
|
|
extern "C" {
|
|
static mut _stack_end_cpu1: u32;
|
|
}
|
|
|
|
// disables interrupts
|
|
xtensa_lx::interrupt::set_mask(0);
|
|
|
|
// reset cycle compare registers
|
|
xtensa_lx::timer::set_ccompare0(0);
|
|
xtensa_lx::timer::set_ccompare1(0);
|
|
xtensa_lx::timer::set_ccompare2(0);
|
|
|
|
// set stack pointer to end of memory: no need to retain stack up to this point
|
|
set_stack_pointer(&mut _stack_end_cpu1);
|
|
|
|
match START_CORE1_FUNCTION.take() {
|
|
Some(entry) => (*entry)(),
|
|
None => panic!("No start function set"),
|
|
}
|
|
|
|
panic!("Return from second core's entry");
|
|
}
|
|
|
|
/// Start the APP (second) core
|
|
///
|
|
/// The second core will start running the closure `entry`.
|
|
///
|
|
/// Dropping the returned guard will park the core.
|
|
pub fn start_app_core(
|
|
&mut self,
|
|
entry: &mut (dyn FnMut() + Send),
|
|
) -> Result<AppCoreGuard, Error> {
|
|
let dport_control = crate::peripherals::DPORT::PTR;
|
|
let dport_control = unsafe { &*dport_control };
|
|
|
|
if !xtensa_lx::is_debugger_attached()
|
|
&& dport_control
|
|
.appcpu_ctrl_b
|
|
.read()
|
|
.appcpu_clkgate_en()
|
|
.bit_is_set()
|
|
{
|
|
return Err(Error::CoreAlreadyRunning);
|
|
}
|
|
|
|
self.flush_cache(Cpu::AppCpu);
|
|
self.enable_cache(Cpu::AppCpu);
|
|
|
|
unsafe {
|
|
let entry_fn: &'static mut (dyn FnMut() + 'static) = core::mem::transmute(entry);
|
|
START_CORE1_FUNCTION = Some(entry_fn);
|
|
}
|
|
|
|
dport_control.appcpu_ctrl_d.write(|w| unsafe {
|
|
w.appcpu_boot_addr()
|
|
.bits(Self::start_core1_init as *const u32 as u32)
|
|
});
|
|
|
|
dport_control
|
|
.appcpu_ctrl_b
|
|
.modify(|_, w| w.appcpu_clkgate_en().set_bit());
|
|
dport_control
|
|
.appcpu_ctrl_c
|
|
.modify(|_, w| w.appcpu_runstall().clear_bit());
|
|
dport_control
|
|
.appcpu_ctrl_a
|
|
.modify(|_, w| w.appcpu_resetting().set_bit());
|
|
dport_control
|
|
.appcpu_ctrl_a
|
|
.modify(|_, w| w.appcpu_resetting().clear_bit());
|
|
|
|
self.unpark_core(Cpu::AppCpu);
|
|
|
|
Ok(AppCoreGuard {
|
|
phantom: PhantomData::default(),
|
|
})
|
|
}
|
|
}
|