Compare commits
No commits in common. "4e4ff512d9ee77179a056e7da71eda20ade4ef71" and "0bc941d789ef191a5fd97c31d6e3279371bde9b6" have entirely different histories.
4e4ff512d9
...
0bc941d789
64
src/boot.rs
64
src/boot.rs
|
@ -1,8 +1,7 @@
|
||||||
use r0::zero_bss;
|
use r0::zero_bss;
|
||||||
use vcell::VolatileCell;
|
use crate::regs::{RegisterR, RegisterW};
|
||||||
use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
use crate::cortex_a9::{asm, regs::*, mmu};
|
||||||
use crate::cortex_a9::{asm, regs::*, cache, mmu};
|
use crate::zynq::mpcore;
|
||||||
use crate::zynq::{slcr, mpcore};
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static mut __bss_start: u32;
|
static mut __bss_start: u32;
|
||||||
|
@ -10,8 +9,7 @@ extern "C" {
|
||||||
static mut __stack_start: u32;
|
static mut __stack_start: u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `0` means: wait for initialization by core0
|
static mut CORE1_STACK: u32 = 0;
|
||||||
static mut CORE1_STACK: VolatileCell<u32> = VolatileCell::new(0);
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
#[link_section = ".text.boot"]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -25,11 +23,15 @@ pub unsafe extern "C" fn _boot_cores() -> ! {
|
||||||
boot_core0();
|
boot_core0();
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
while CORE1_STACK.get() == 0 {
|
// Wait for a first `sev` so that `CORE1_STACK` is cleared
|
||||||
|
// by `zero_bss()` on core 0.
|
||||||
|
asm::wfe();
|
||||||
|
|
||||||
|
while CORE1_STACK == 0 {
|
||||||
asm::wfe();
|
asm::wfe();
|
||||||
}
|
}
|
||||||
|
|
||||||
SP.write(CORE1_STACK.get());
|
SP.write(CORE1_STACK);
|
||||||
boot_core1();
|
boot_core1();
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -100,45 +102,13 @@ fn l1_cache_init() {
|
||||||
dciall();
|
dciall();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Core1<S: AsMut<[u32]>> {
|
pub fn start_core1<T: AsMut<[u32]>>(mut stack: T) {
|
||||||
pub stack: S,
|
let stack = stack.as_mut();
|
||||||
}
|
let stack_start = &mut stack[stack.len() - 1];
|
||||||
|
unsafe {
|
||||||
impl<S: AsMut<[u32]>> Core1<S> {
|
CORE1_STACK = stack_start as *mut _ as u32;
|
||||||
pub fn stop(&self) {
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(true));
|
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(true));
|
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset and start core1
|
// wake up core1
|
||||||
///
|
asm::sev();
|
||||||
/// The stack must not be in OCM because core1 still has to
|
|
||||||
/// initialize its MMU before it can access DDR.
|
|
||||||
pub fn start(stack: S) -> Self {
|
|
||||||
let mut core = Core1 { stack };
|
|
||||||
|
|
||||||
// reset and stop (safe to repeat)
|
|
||||||
core.stop();
|
|
||||||
|
|
||||||
let stack = core.stack.as_mut();
|
|
||||||
let stack_start = &mut stack[stack.len() - 1];
|
|
||||||
unsafe {
|
|
||||||
CORE1_STACK.set(stack_start as *mut _ as u32);
|
|
||||||
}
|
|
||||||
// Ensure stack pointer has been written to cache
|
|
||||||
asm::dmb();
|
|
||||||
// Flush cache-line
|
|
||||||
cache::dccmvac(unsafe { &CORE1_STACK } as *const _ as u32);
|
|
||||||
|
|
||||||
// wake up core1
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(false));
|
|
||||||
});
|
|
||||||
|
|
||||||
core
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,14 +71,6 @@ pub fn dccimva(addr: usize) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// clear cache line by virtual address to point of coherency (DCCMVAC)
|
|
||||||
#[inline]
|
|
||||||
pub fn dccmvac(addr: u32) {
|
|
||||||
unsafe {
|
|
||||||
asm!("mcr p15, 0, $0, c7, c10, 1" :: "r" (addr) :: "volatile");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The DCCIVMA (data cache clear and invalidate) applied to the
|
/// The DCCIVMA (data cache clear and invalidate) applied to the
|
||||||
/// region of memory occupied by the argument. This does not modify
|
/// region of memory occupied by the argument. This does not modify
|
||||||
/// the argument, but due to the invalidate part (only ever needed if
|
/// the argument, but due to the invalidate part (only ever needed if
|
||||||
|
|
|
@ -2,6 +2,5 @@ pub mod asm;
|
||||||
pub mod regs;
|
pub mod regs;
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod mmu;
|
pub mod mmu;
|
||||||
pub mod mutex;
|
|
||||||
|
|
||||||
global_asm!(include_str!("exceptions.s"));
|
global_asm!(include_str!("exceptions.s"));
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
use core::ops::{Deref, DerefMut};
|
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use core::cell::UnsafeCell;
|
|
||||||
use super::asm::*;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn wait_for_update() {
|
|
||||||
wfe();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn signal_update() {
|
|
||||||
dsb();
|
|
||||||
sev();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Mutex<T> {
|
|
||||||
locked: AtomicBool,
|
|
||||||
inner: UnsafeCell<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<T: Send> Sync for Mutex<T> {}
|
|
||||||
unsafe impl<T: Send> Send for Mutex<T> {}
|
|
||||||
|
|
||||||
impl<T> Mutex<T> {
|
|
||||||
pub const fn new(inner: T) -> Self {
|
|
||||||
Mutex{
|
|
||||||
locked: AtomicBool::new(false),
|
|
||||||
inner: UnsafeCell::new(inner),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lock(&self) -> MutexGuard<T> {
|
|
||||||
while self.locked.compare_and_swap(false, true, Ordering::Acquire) {
|
|
||||||
while self.locked.load(Ordering::Relaxed) {
|
|
||||||
wait_for_update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dmb();
|
|
||||||
|
|
||||||
MutexGuard { mutex: self }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unlock(&self) {
|
|
||||||
dmb();
|
|
||||||
self.locked.store(false, Ordering::Release);
|
|
||||||
signal_update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MutexGuard<'a, T> {
|
|
||||||
mutex: &'a Mutex<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Deref for MutexGuard<'a, T> {
|
|
||||||
type Target = T;
|
|
||||||
fn deref(&self) -> &T {
|
|
||||||
unsafe { &*self.mutex.inner.get() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> DerefMut for MutexGuard<'a, T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut T {
|
|
||||||
unsafe { &mut *self.mutex.inner.get() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Drop for MutexGuard<'a, T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.mutex.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -38,7 +38,7 @@ pub fn main() {
|
||||||
|
|
||||||
let core1_stack = vec![0; 2048];
|
let core1_stack = vec![0; 2048];
|
||||||
println!("{} bytes stack for core1", core1_stack.len());
|
println!("{} bytes stack for core1", core1_stack.len());
|
||||||
boot::Core1::start(core1_stack);
|
boot::start_core1(core1_stack);
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
||||||
println!("Eth on");
|
println!("Eth on");
|
||||||
|
|
|
@ -129,7 +129,7 @@ pub struct RegisterBlock {
|
||||||
pub ocm_rst_ctrl: RW<u32>,
|
pub ocm_rst_ctrl: RW<u32>,
|
||||||
reserved4: [u32; 1],
|
reserved4: [u32; 1],
|
||||||
pub fpga_rst_ctrl: RW<u32>,
|
pub fpga_rst_ctrl: RW<u32>,
|
||||||
pub a9_cpu_rst_ctrl: A9CpuRstCtrl,
|
pub a9_cpu_rst_ctrl: RW<u32>,
|
||||||
reserved5: [u32; 1],
|
reserved5: [u32; 1],
|
||||||
pub rs_awdt_ctrl: RW<u32>,
|
pub rs_awdt_ctrl: RW<u32>,
|
||||||
reserved6: [u32; 2],
|
reserved6: [u32; 2],
|
||||||
|
@ -440,13 +440,6 @@ impl UartRstCtrl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register!(a9_cpu_rst_ctrl, A9CpuRstCtrl, RW, u32);
|
|
||||||
register_bit!(a9_cpu_rst_ctrl, peri_rst, 8);
|
|
||||||
register_bit!(a9_cpu_rst_ctrl, a9_clkstop1, 5);
|
|
||||||
register_bit!(a9_cpu_rst_ctrl, a9_clkstop0, 4);
|
|
||||||
register_bit!(a9_cpu_rst_ctrl, a9_rst1, 1);
|
|
||||||
register_bit!(a9_cpu_rst_ctrl, a9_rst0, 0);
|
|
||||||
|
|
||||||
register!(pss_rst_ctrl, PssRstCtrl, RW, u32);
|
register!(pss_rst_ctrl, PssRstCtrl, RW, u32);
|
||||||
register_bit!(pss_rst_ctrl, soft_rst, 1);
|
register_bit!(pss_rst_ctrl, soft_rst, 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue