forked from M-Labs/zynq-rs
Merge branch 'master' of git.m-labs.hk:M-Labs/zc706 into sdio-registers
This commit is contained in:
commit
4acee21c05
|
@ -66,6 +66,7 @@ dependencies = [
|
||||||
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9 0.0.0",
|
||||||
"libregister 0.0.0",
|
"libregister 0.0.0",
|
||||||
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -97,14 +98,13 @@ dependencies = [
|
||||||
"libboard_zynq 0.0.0",
|
"libboard_zynq 0.0.0",
|
||||||
"libcortex_a9 0.0.0",
|
"libcortex_a9 0.0.0",
|
||||||
"libregister 0.0.0",
|
"libregister 0.0.0",
|
||||||
"linked_list_allocator 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"linked_list_allocator 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked_list_allocator"
|
name = "linked_list_allocator"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -170,7 +170,7 @@ dependencies = [
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum compiler_builtins 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "38f18416546abfbf8d801c555a0e99524453e7214f9cc9107ad49de3d5948ccc"
|
"checksum compiler_builtins 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "38f18416546abfbf8d801c555a0e99524453e7214f9cc9107ad49de3d5948ccc"
|
||||||
"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
|
"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
|
||||||
"checksum linked_list_allocator 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1070ea54beccbfd3a3987aca6440f94cc1e0b447c2d979d8c7f761e265417e4"
|
"checksum linked_list_allocator 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d6b60501dd4c850950bb43f970d544f6ce04e0ca021da2db2538fbe9d923f19e"
|
||||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||||
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
|
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
|
||||||
"checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
|
"checksum nb 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1411551beb3c11dedfb0a90a0fa256b47d28b9ec2cdff34c25a2fa59e45dbdc"
|
||||||
|
|
|
@ -49,9 +49,10 @@ let
|
||||||
name = "${crate}";
|
name = "${crate}";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
crateSubdir = crate;
|
crateSubdir = crate;
|
||||||
cargoSha256 = "0wqsxbcphcf240mqfglckl0lz82f19g1jlcf3xk73aflpyxk5pmm";
|
cargoSha256 = "0xlynsr94dyv0g41qwk5490w3wnzd5g70msaih6mcbgr3v4s2q34";
|
||||||
cargoFeatures = features;
|
cargoFeatures = features;
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
|
dontFixup = true;
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
inherit pkgs rustPlatform rustcSrc gcc;
|
inherit pkgs rustPlatform rustcSrc gcc;
|
||||||
|
|
|
@ -12,7 +12,7 @@ fn main() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("cargo:rustc-link-search={}", out.display());
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
|
||||||
// Only re-run the build script when memory.x is changed,
|
// Only re-run the build script when link.x is changed,
|
||||||
// instead of when any part of the source code changes.
|
// instead of when any part of the source code changes.
|
||||||
println!("cargo:rerun-if-changed=link.x");
|
println!("cargo:rerun-if-changed=link.x");
|
||||||
}
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
ENTRY(_boot_cores);
|
||||||
|
|
||||||
|
/* Provide some defaults */
|
||||||
|
PROVIDE(Reset = _boot_cores);
|
||||||
|
PROVIDE(UndefinedInstruction = Reset);
|
||||||
|
PROVIDE(SoftwareInterrupt = Reset);
|
||||||
|
PROVIDE(PrefetchAbort = Reset);
|
||||||
|
PROVIDE(DataAbort = Reset);
|
||||||
|
PROVIDE(ReservedException = Reset);
|
||||||
|
PROVIDE(IRQ = Reset);
|
||||||
|
PROVIDE(FIQ = Reset);
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
/* 256 kB On-Chip Memory */
|
||||||
|
OCM : ORIGIN = 0, LENGTH = 0x30000
|
||||||
|
OCM3 : ORIGIN = 0xFFFF0000, LENGTH = 0x10000
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
KEEP(*(.text.exceptions));
|
||||||
|
*(.text.boot);
|
||||||
|
*(.text .text.*);
|
||||||
|
} > OCM
|
||||||
|
|
||||||
|
.rodata : ALIGN(4)
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.*);
|
||||||
|
} > OCM
|
||||||
|
|
||||||
|
.data : ALIGN(4)
|
||||||
|
{
|
||||||
|
*(.data .data.*);
|
||||||
|
} > OCM
|
||||||
|
|
||||||
|
.bss (NOLOAD) : ALIGN(4)
|
||||||
|
{
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss .bss.*);
|
||||||
|
. = ALIGN(4);
|
||||||
|
__bss_end = .;
|
||||||
|
} > OCM
|
||||||
|
|
||||||
|
.stack1 (NOLOAD) : ALIGN(8) {
|
||||||
|
__stack1_end = .;
|
||||||
|
. += 0x200;
|
||||||
|
__stack1_start = .;
|
||||||
|
} > OCM
|
||||||
|
|
||||||
|
.stack0 (NOLOAD) : ALIGN(8) {
|
||||||
|
__stack0_end = .;
|
||||||
|
. = ORIGIN(OCM) + LENGTH(OCM) - 8;
|
||||||
|
__stack0_start = .;
|
||||||
|
} > OCM
|
||||||
|
|
||||||
|
/DISCARD/ :
|
||||||
|
{
|
||||||
|
/* Unused exception related info that only wastes space */
|
||||||
|
*(.ARM.exidx);
|
||||||
|
*(.ARM.exidx.*);
|
||||||
|
*(.ARM.extab.*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(SIZEOF(.stack0) >= 0x1000, "less than 4 KB left for stack");
|
|
@ -6,7 +6,6 @@ extern crate alloc;
|
||||||
use core::{mem::transmute, task::Poll};
|
use core::{mem::transmute, task::Poll};
|
||||||
use alloc::{borrow::ToOwned, collections::BTreeMap, format};
|
use alloc::{borrow::ToOwned, collections::BTreeMap, format};
|
||||||
use log::info;
|
use log::info;
|
||||||
use embedded_hal::timer::CountDown;
|
|
||||||
use libregister::RegisterR;
|
use libregister::RegisterR;
|
||||||
use libcortex_a9::{mutex::Mutex, sync_channel::{self, sync_channel}};
|
use libcortex_a9::{mutex::Mutex, sync_channel::{self, sync_channel}};
|
||||||
use libboard_zynq::{
|
use libboard_zynq::{
|
||||||
|
@ -17,8 +16,6 @@ use libboard_zynq::{
|
||||||
wire::{EthernetAddress, IpAddress, IpCidr},
|
wire::{EthernetAddress, IpAddress, IpCidr},
|
||||||
iface::{NeighborCache, EthernetInterfaceBuilder, Routes},
|
iface::{NeighborCache, EthernetInterfaceBuilder, Routes},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
socket::SocketSet,
|
|
||||||
socket::{TcpSocket, TcpSocketBuffer},
|
|
||||||
},
|
},
|
||||||
time::Milliseconds,
|
time::Milliseconds,
|
||||||
};
|
};
|
||||||
|
@ -32,14 +29,12 @@ mod ps7_init;
|
||||||
|
|
||||||
const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
|
const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
|
||||||
|
|
||||||
static mut STACK_CORE1: [u32; 512] = [0; 512];
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main_core0() {
|
pub fn main_core0() {
|
||||||
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
|
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
|
||||||
println!("\nzc706 main");
|
println!("\nzc706 main");
|
||||||
|
|
||||||
libsupport_zynq::logger::init().unwrap();
|
libboard_zynq::logger::init().unwrap();
|
||||||
log::set_max_level(log::LevelFilter::Trace);
|
log::set_max_level(log::LevelFilter::Trace);
|
||||||
|
|
||||||
info!("Boot mode: {:?}", zynq::slcr::RegisterBlock::new().boot_mode.read().boot_mode_pins());
|
info!("Boot mode: {:?}", zynq::slcr::RegisterBlock::new().boot_mode.read().boot_mode_pins());
|
||||||
|
@ -49,7 +44,7 @@ pub fn main_core0() {
|
||||||
#[cfg(feature = "target_cora_z7_10")]
|
#[cfg(feature = "target_cora_z7_10")]
|
||||||
const CPU_FREQ: u32 = 650_000_000;
|
const CPU_FREQ: u32 = 650_000_000;
|
||||||
|
|
||||||
println!("Setup clock sources...");
|
info!("Setup clock sources...");
|
||||||
ArmPll::setup(2 * CPU_FREQ);
|
ArmPll::setup(2 * CPU_FREQ);
|
||||||
Clocks::set_cpu_freq(CPU_FREQ);
|
Clocks::set_cpu_freq(CPU_FREQ);
|
||||||
#[cfg(feature = "target_zc706")]
|
#[cfg(feature = "target_zc706")]
|
||||||
|
@ -57,9 +52,9 @@ pub fn main_core0() {
|
||||||
IoPll::setup(1_000_000_000);
|
IoPll::setup(1_000_000_000);
|
||||||
libboard_zynq::stdio::drop_uart();
|
libboard_zynq::stdio::drop_uart();
|
||||||
}
|
}
|
||||||
println!("PLLs set up");
|
info!("PLLs set up");
|
||||||
let clocks = zynq::clocks::Clocks::get();
|
let clocks = zynq::clocks::Clocks::get();
|
||||||
println!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x());
|
info!("CPU Clocks: {}/{}/{}/{}", clocks.cpu_6x4x(), clocks.cpu_3x2x(), clocks.cpu_2x(), clocks.cpu_1x());
|
||||||
|
|
||||||
let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode();
|
let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode();
|
||||||
let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) };
|
let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) };
|
||||||
|
@ -79,6 +74,7 @@ pub fn main_core0() {
|
||||||
ddr.memtest();
|
ddr.memtest();
|
||||||
ram::init_alloc_ddr(&mut ddr);
|
ram::init_alloc_ddr(&mut ddr);
|
||||||
|
|
||||||
|
#[cfg(dev)]
|
||||||
for i in 0..=1 {
|
for i in 0..=1 {
|
||||||
let mut flash_io = flash.manual_mode(i);
|
let mut flash_io = flash.manual_mode(i);
|
||||||
// println!("rdcr={:02X}", flash_io.rdcr());
|
// println!("rdcr={:02X}", flash_io.rdcr());
|
||||||
|
@ -111,41 +107,13 @@ pub fn main_core0() {
|
||||||
flash_io.erase(0);
|
flash_io.erase(0);
|
||||||
});
|
});
|
||||||
flash_io.write_enabled(|flash_io| {
|
flash_io.write_enabled(|flash_io| {
|
||||||
flash_io.program(0, [0x23054223; (0x100 >> 2)].iter().cloned());
|
flash_io.program(0, [0x23054223; 0x100 >> 2].iter().cloned());
|
||||||
});
|
});
|
||||||
|
|
||||||
flash = flash_io.stop();
|
flash = flash_io.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut tx, mut rx) = sync_channel::sync_channel(0);
|
let core1 = boot::Core1::start();
|
||||||
task::spawn(async move {
|
|
||||||
println!("outer task");
|
|
||||||
while let Some(item) = *rx.async_recv().await {
|
|
||||||
println!("received {}", item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
task::spawn(async {
|
|
||||||
for i in 1..=3 {
|
|
||||||
println!("outer task2: {}", i);
|
|
||||||
task::r#yield().await;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
task::block_on(async {
|
|
||||||
task::spawn(async {
|
|
||||||
println!("inner task");
|
|
||||||
});
|
|
||||||
|
|
||||||
for i in 1..=10 {
|
|
||||||
println!("yield {}", i);
|
|
||||||
task::r#yield().await;
|
|
||||||
tx.async_send(Some(i)).await;
|
|
||||||
}
|
|
||||||
tx.async_send(None).await;
|
|
||||||
});
|
|
||||||
|
|
||||||
let core1_stack = unsafe { &mut STACK_CORE1[..] };
|
|
||||||
println!("{} bytes stack for core1", core1_stack.len());
|
|
||||||
let core1 = boot::Core1::start(core1_stack);
|
|
||||||
|
|
||||||
let (mut core1_req, rx) = sync_channel(10);
|
let (mut core1_req, rx) = sync_channel(10);
|
||||||
*CORE1_REQ.lock() = Some(rx);
|
*CORE1_REQ.lock() = Some(rx);
|
||||||
|
@ -160,13 +128,6 @@ pub fn main_core0() {
|
||||||
});
|
});
|
||||||
core1.disable();
|
core1.disable();
|
||||||
|
|
||||||
libcortex_a9::asm::dsb();
|
|
||||||
print!("Core1 stack [{:08X}..{:08X}]:", &core1.stack[0] as *const _ as u32, &core1.stack[core1.stack.len() - 1] as *const _ as u32);
|
|
||||||
for w in core1.stack {
|
|
||||||
print!(" {:08X}", w);
|
|
||||||
}
|
|
||||||
println!(".");
|
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
||||||
println!("Eth on");
|
println!("Eth on");
|
||||||
|
|
||||||
|
@ -189,23 +150,13 @@ pub fn main_core0() {
|
||||||
unsafe { transmute(tx_descs.as_mut_slice()) },
|
unsafe { transmute(tx_descs.as_mut_slice()) },
|
||||||
unsafe { transmute(tx_buffers.as_mut_slice()) },
|
unsafe { transmute(tx_buffers.as_mut_slice()) },
|
||||||
);
|
);
|
||||||
// loop {
|
|
||||||
// match eth.recv_next() {
|
|
||||||
// Ok(None) => {},
|
|
||||||
// Ok(Some(pkt)) => println!("received {} bytes", pkt.len()),
|
|
||||||
// Err(e) => println!("e: {:?}", e),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
println!("iface...");
|
|
||||||
let ethernet_addr = EthernetAddress(HWADDR);
|
let ethernet_addr = EthernetAddress(HWADDR);
|
||||||
// IP stack
|
// IP stack
|
||||||
let local_addr = IpAddress::v4(192, 168, 1, 51);
|
let local_addr = IpAddress::v4(192, 168, 1, 51);
|
||||||
let mut ip_addrs = [IpCidr::new(local_addr, 24)];
|
let mut ip_addrs = [IpCidr::new(local_addr, 24)];
|
||||||
let mut routes_storage = vec![None; 4];
|
let routes = Routes::new(BTreeMap::new());
|
||||||
let routes = Routes::new(/*BTreeMap::new()*/ &mut routes_storage[..]);
|
let neighbor_cache = NeighborCache::new(BTreeMap::new());
|
||||||
let mut neighbor_storage = vec![None; 256];
|
|
||||||
let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]);
|
|
||||||
let mut iface = EthernetInterfaceBuilder::new(&mut eth)
|
let mut iface = EthernetInterfaceBuilder::new(&mut eth)
|
||||||
.ethernet_addr(ethernet_addr)
|
.ethernet_addr(ethernet_addr)
|
||||||
.ip_addrs(&mut ip_addrs[..])
|
.ip_addrs(&mut ip_addrs[..])
|
||||||
|
@ -213,7 +164,7 @@ pub fn main_core0() {
|
||||||
.neighbor_cache(neighbor_cache)
|
.neighbor_cache(neighbor_cache)
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
// TODO: compare with ps7_init
|
ps7_init::report_differences();
|
||||||
|
|
||||||
Sockets::init(32);
|
Sockets::init(32);
|
||||||
/// `chargen`
|
/// `chargen`
|
||||||
|
@ -244,20 +195,20 @@ pub fn main_core0() {
|
||||||
None =>
|
None =>
|
||||||
stream.send("I had trouble reading your name.\n".bytes()).await?,
|
stream.send("I had trouble reading your name.\n".bytes()).await?,
|
||||||
}
|
}
|
||||||
stream.flush().await;
|
let _ = stream.flush().await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut counter = alloc::rc::Rc::new(core::cell::RefCell::new(0));
|
let counter = alloc::rc::Rc::new(core::cell::RefCell::new(0));
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
while let stream = TcpStream::accept(TCP_PORT, 2048, 2408).await.unwrap() {
|
while let Ok(stream) = TcpStream::accept(TCP_PORT, 2048, 2408).await {
|
||||||
let counter = counter.clone();
|
let counter = counter.clone();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
*counter.borrow_mut() += 1;
|
*counter.borrow_mut() += 1;
|
||||||
println!("Serving {} connections", *counter.borrow());
|
println!("Serving {} connections", *counter.borrow());
|
||||||
handle_connection(stream)
|
handle_connection(stream)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| println!("Connection: {:?}", e));
|
.unwrap_or_else(|e| println!("Connection: {:?}", e));
|
||||||
*counter.borrow_mut() -= 1;
|
*counter.borrow_mut() -= 1;
|
||||||
println!("Now serving {} connections", *counter.borrow());
|
println!("Now serving {} connections", *counter.borrow());
|
||||||
});
|
});
|
||||||
|
@ -272,7 +223,7 @@ pub fn main_core0() {
|
||||||
let timestamp = timer.get_us();
|
let timestamp = timer.get_us();
|
||||||
let seconds = timestamp / 1_000_000;
|
let seconds = timestamp / 1_000_000;
|
||||||
let micros = timestamp % 1_000_000;
|
let micros = timestamp % 1_000_000;
|
||||||
println!("time: {:6}.{:06}s", seconds, micros);
|
info!("time: {:6}.{:06}s", seconds, micros);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -293,7 +244,7 @@ pub fn main_core1() {
|
||||||
while req.is_none() {
|
while req.is_none() {
|
||||||
req = CORE1_REQ.lock().take();
|
req = CORE1_REQ.lock().take();
|
||||||
}
|
}
|
||||||
let mut req = req.unwrap();
|
let req = req.unwrap();
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
while res.is_none() {
|
while res.is_none() {
|
||||||
res = CORE1_RES.lock().take();
|
res = CORE1_RES.lock().take();
|
||||||
|
|
|
@ -15,6 +15,7 @@ bit_field = "0.10"
|
||||||
embedded-hal = "0.2"
|
embedded-hal = "0.2"
|
||||||
nb = "0.1"
|
nb = "0.1"
|
||||||
void = { version = "1", default-features = false }
|
void = { version = "1", default-features = false }
|
||||||
|
log = "0.4"
|
||||||
libregister = { path = "../libregister" }
|
libregister = { path = "../libregister" }
|
||||||
libcortex_a9 = { path = "../libcortex_a9" }
|
libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use log::debug;
|
||||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
|
|
||||||
|
@ -48,6 +49,8 @@ pub trait ClockSource {
|
||||||
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str;
|
||||||
|
|
||||||
/// Zynq-7000 AP SoC Technical Reference Manual:
|
/// Zynq-7000 AP SoC Technical Reference Manual:
|
||||||
/// 25.10.4 PLLs
|
/// 25.10.4 PLLs
|
||||||
fn setup(target_freq: u32) {
|
fn setup(target_freq: u32) {
|
||||||
|
@ -58,6 +61,7 @@ pub trait ClockSource {
|
||||||
.expect("PLL_FDIV_LOCK_PARAM")
|
.expect("PLL_FDIV_LOCK_PARAM")
|
||||||
.1.clone();
|
.1.clone();
|
||||||
|
|
||||||
|
debug!("Set {} to {} Hz", Self::name(), target_freq);
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
let (pll_ctrl, pll_cfg, pll_status) = Self::pll_regs(slcr);
|
let (pll_ctrl, pll_cfg, pll_status) = Self::pll_regs(slcr);
|
||||||
|
|
||||||
|
@ -108,6 +112,10 @@ impl ClockSource for ArmPll {
|
||||||
fn pll_locked(pll_status: &mut crate::slcr::PllStatus) -> bool {
|
fn pll_locked(pll_status: &mut crate::slcr::PllStatus) -> bool {
|
||||||
pll_status.read().arm_pll_lock()
|
pll_status.read().arm_pll_lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
&"ARM_PLL"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DDR PLL: Recommended clock for the DDR DRAM controller and AXI_HP interfaces
|
/// DDR PLL: Recommended clock for the DDR DRAM controller and AXI_HP interfaces
|
||||||
|
@ -130,6 +138,10 @@ impl ClockSource for DdrPll {
|
||||||
fn pll_locked(pll_status: &mut crate::slcr::PllStatus) -> bool {
|
fn pll_locked(pll_status: &mut crate::slcr::PllStatus) -> bool {
|
||||||
pll_status.read().ddr_pll_lock()
|
pll_status.read().ddr_pll_lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
&"DDR_PLL"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// I/O PLL: Recommended clock for I/O peripherals
|
/// I/O PLL: Recommended clock for I/O peripherals
|
||||||
|
@ -153,4 +165,8 @@ impl ClockSource for IoPll {
|
||||||
fn pll_locked(pll_status: &mut crate::slcr::PllStatus) -> bool {
|
fn pll_locked(pll_status: &mut crate::slcr::PllStatus) -> bool {
|
||||||
pll_status.read().io_pll_lock()
|
pll_status.read().io_pll_lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn name() -> &'static str {
|
||||||
|
&"IO_PLL"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||||
|
use log::{debug, info, error};
|
||||||
use crate::{print, println};
|
use crate::{print, println};
|
||||||
use super::slcr::{self, DdriobVrefSel};
|
use super::slcr::{self, DdriobVrefSel};
|
||||||
use super::clocks::{Clocks, source::{DdrPll, ClockSource}};
|
use super::clocks::{Clocks, source::{DdrPll, ClockSource}};
|
||||||
|
@ -38,11 +39,9 @@ impl DdrRam {
|
||||||
DdrPll::setup(2 * DDR_FREQ);
|
DdrPll::setup(2 * DDR_FREQ);
|
||||||
|
|
||||||
let clocks = Clocks::get();
|
let clocks = Clocks::get();
|
||||||
println!("Clocks: {:?}", clocks);
|
|
||||||
|
|
||||||
let ddr3x_clk_divisor = 2;
|
let ddr3x_clk_divisor = 2;
|
||||||
let ddr2x_clk_divisor = 3;
|
let ddr2x_clk_divisor = 3;
|
||||||
println!("DDR 3x/2x clocks: {}/{}", clocks.ddr / u32::from(ddr3x_clk_divisor), clocks.ddr / u32::from(ddr2x_clk_divisor));
|
debug!("DDR 3x/2x clocks: {}/{}", clocks.ddr / u32::from(ddr3x_clk_divisor), clocks.ddr / u32::from(ddr2x_clk_divisor));
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.ddr_clk_ctrl.write(
|
slcr.ddr_clk_ctrl.write(
|
||||||
|
@ -63,7 +62,7 @@ impl DdrRam {
|
||||||
.max(1).min(63) as u8;
|
.max(1).min(63) as u8;
|
||||||
let divisor1 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ / u32::from(divisor0))
|
let divisor1 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ / u32::from(divisor0))
|
||||||
.max(1).min(63) as u8;
|
.max(1).min(63) as u8;
|
||||||
println!("DDR DCI clock: {} Hz", clocks.ddr / u32::from(divisor0) / u32::from(divisor1));
|
debug!("DDR DCI clock: {} Hz", clocks.ddr / u32::from(divisor0) / u32::from(divisor1));
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
// Step 1.
|
// Step 1.
|
||||||
|
@ -226,7 +225,7 @@ impl DdrRam {
|
||||||
let patterns: &'static [u32] = &[0xffff_ffff, 0x5555_5555, 0xaaaa_aaaa, 0];
|
let patterns: &'static [u32] = &[0xffff_ffff, 0x5555_5555, 0xaaaa_aaaa, 0];
|
||||||
let mut expected = None;
|
let mut expected = None;
|
||||||
for (i, pattern) in patterns.iter().enumerate() {
|
for (i, pattern) in patterns.iter().enumerate() {
|
||||||
println!("memtest phase {} (status: {:?})", i, self.status());
|
info!("memtest phase {} (status: {:?})", i, self.status());
|
||||||
|
|
||||||
for megabyte in 0..=(slice.len() / (1024 * 1024)) {
|
for megabyte in 0..=(slice.len() / (1024 * 1024)) {
|
||||||
let start = megabyte * 1024 * 1024 / 4;
|
let start = megabyte * 1024 * 1024 / 4;
|
||||||
|
@ -235,7 +234,7 @@ impl DdrRam {
|
||||||
expected.map(|expected| {
|
expected.map(|expected| {
|
||||||
let read: u32 = *b;
|
let read: u32 = *b;
|
||||||
if read != expected {
|
if read != expected {
|
||||||
println!("{:08X}: expected {:08X}, read {:08X}", b as *mut _ as usize, expected, read);
|
error!("{:08X}: expected {:08X}, read {:08X}", b as *mut _ as usize, expected, read);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
*b = *pattern;
|
*b = *pattern;
|
||||||
|
|
|
@ -26,12 +26,18 @@ impl DevC {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_done(&self) -> bool {
|
||||||
|
// Note: contrary to what the TRM says, this appears to be simply
|
||||||
|
// the state of the DONE signal.
|
||||||
|
self.regs.int_sts.read().ixr_pcfg_done()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn program(&mut self) {
|
pub fn program(&mut self) {
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.init_preload_fpga();
|
slcr.init_preload_fpga();
|
||||||
});
|
});
|
||||||
|
|
||||||
while !self.regs.int_sts.read().ixr_pcfg_done() {}
|
while !self.is_done() {}
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.init_postload_fpga();
|
slcr.init_postload_fpga();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
use log::{error, info, warn};
|
||||||
use libregister::*;
|
use libregister::*;
|
||||||
use crate::println;
|
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
use super::clocks::Clocks;
|
use super::clocks::Clocks;
|
||||||
|
|
||||||
|
@ -389,7 +389,7 @@ impl<'r, 'rx, 'tx: 'a, 'a> smoltcp::phy::Device<'a> for &mut Eth<'r, rx::DescLis
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("eth recv error: {:?}", e);
|
error!("eth recv error: {:?}", e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -555,7 +555,7 @@ impl<'r> EthInner<'r> {
|
||||||
if self.link != link {
|
if self.link != link {
|
||||||
match &link {
|
match &link {
|
||||||
Some(link) => {
|
Some(link) => {
|
||||||
println!("eth: got {:?}", link);
|
info!("eth: got {:?}", link);
|
||||||
|
|
||||||
use phy::LinkSpeed::*;
|
use phy::LinkSpeed::*;
|
||||||
let txclock = match link.speed {
|
let txclock = match link.speed {
|
||||||
|
@ -573,7 +573,7 @@ impl<'r> EthInner<'r> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("eth: link lost");
|
warn!("eth: link lost");
|
||||||
phy.modify_control(self, |control|
|
phy.modify_control(self, |control|
|
||||||
control.set_autoneg_enable(true)
|
control.set_autoneg_enable(true)
|
||||||
.set_restart_autoneg(true)
|
.set_restart_autoneg(true)
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
//! Quad-SPI Flash Controller
|
//! Quad-SPI Flash Controller
|
||||||
|
|
||||||
use crate::{print, println};
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use log::{error, info, warn};
|
||||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||||
|
use crate::{print, println};
|
||||||
use super::slcr;
|
use super::slcr;
|
||||||
use super::clocks::source::{IoPll, ClockSource};
|
use super::clocks::source::{IoPll, ClockSource};
|
||||||
|
|
||||||
|
@ -422,17 +423,17 @@ impl Flash<Manual> {
|
||||||
let sr1 = self.wait_while_sr1_zeroed();
|
let sr1 = self.wait_while_sr1_zeroed();
|
||||||
|
|
||||||
if sr1.e_err() {
|
if sr1.e_err() {
|
||||||
println!("E_ERR");
|
error!("E_ERR");
|
||||||
} else if sr1.p_err() {
|
} else if sr1.p_err() {
|
||||||
println!("P_ERR");
|
error!("P_ERR");
|
||||||
} else if sr1.wip() {
|
} else if sr1.wip() {
|
||||||
print!("Erase in progress");
|
info!("Erase in progress");
|
||||||
while self.read_reg::<SR1>().wip() {
|
while self.read_reg::<SR1>().wip() {
|
||||||
print!(".");
|
print!(".");
|
||||||
}
|
}
|
||||||
println!("");
|
println!("");
|
||||||
} else {
|
} else {
|
||||||
println!("erased? sr1={:02X}", sr1.inner);
|
warn!("erased? sr1={:02X}", sr1.inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,17 +449,17 @@ impl Flash<Manual> {
|
||||||
let sr1 = self.read_reg::<SR1>();
|
let sr1 = self.read_reg::<SR1>();
|
||||||
|
|
||||||
if sr1.e_err() {
|
if sr1.e_err() {
|
||||||
println!("E_ERR");
|
error!("E_ERR");
|
||||||
} else if sr1.p_err() {
|
} else if sr1.p_err() {
|
||||||
println!("P_ERR");
|
error!("P_ERR");
|
||||||
} else if sr1.wip() {
|
} else if sr1.wip() {
|
||||||
println!("Program in progress");
|
info!("Program in progress");
|
||||||
while self.read_reg::<SR1>().wip() {
|
while self.read_reg::<SR1>().wip() {
|
||||||
print!(".");
|
print!(".");
|
||||||
}
|
}
|
||||||
println!("");
|
println!("");
|
||||||
} else {
|
} else {
|
||||||
println!("programmed? sr1={:02X}", sr1.inner);
|
warn!("programmed? sr1={:02X}", sr1.inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,3 +18,4 @@ pub mod dmac;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod sdio;
|
pub mod sdio;
|
||||||
|
pub mod logger;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! A logger for the `log` crate
|
//! A logger for the `log` crate
|
||||||
|
|
||||||
use libboard_zynq::{println, stdio, timer::GlobalTimer};
|
use crate::{println, stdio, timer::GlobalTimer};
|
||||||
|
|
||||||
pub static LOGGER: Logger = Logger;
|
pub static LOGGER: Logger = Logger;
|
||||||
|
|
||||||
|
@ -29,6 +29,6 @@ impl log::Log for Logger {
|
||||||
}
|
}
|
||||||
fn flush(&self) {
|
fn flush(&self) {
|
||||||
let uart = stdio::get_uart();
|
let uart = stdio::get_uart();
|
||||||
while !uart.tx_fifo_empty() {}
|
while !uart.tx_idle() {}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -63,6 +63,7 @@ macro_rules! println {
|
||||||
let mut uart = $crate::stdio::get_uart();
|
let mut uart = $crate::stdio::get_uart();
|
||||||
let _ = write!(uart, $($arg)*);
|
let _ = write!(uart, $($arg)*);
|
||||||
let _ = write!(uart, "\n");
|
let _ = write!(uart, "\n");
|
||||||
while !uart.tx_fifo_empty() {}
|
// flush after the newline
|
||||||
|
while !uart.tx_idle() {}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub struct GlobalTimer {
|
||||||
impl GlobalTimer {
|
impl GlobalTimer {
|
||||||
/// Get the potentially uninitialized timer
|
/// Get the potentially uninitialized timer
|
||||||
pub unsafe fn get() -> GlobalTimer {
|
pub unsafe fn get() -> GlobalTimer {
|
||||||
let mut regs = mpcore::RegisterBlock::new();
|
let regs = mpcore::RegisterBlock::new();
|
||||||
GlobalTimer { regs }
|
GlobalTimer { regs }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,15 +192,14 @@ impl Uart {
|
||||||
self.regs.channel_sts.read().txfull()
|
self.regs.channel_sts.read().txfull()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tx_fifo_empty(&self) -> bool {
|
pub fn tx_idle(&self) -> bool {
|
||||||
self.regs.channel_sts.read().txempty()
|
let status = self.regs.channel_sts.read();
|
||||||
|
status.txempty() && !status.tactive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Write for Uart {
|
impl fmt::Write for Uart {
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
||||||
while !self.tx_fifo_empty() {}
|
|
||||||
|
|
||||||
for b in s.bytes() {
|
for b in s.bytes() {
|
||||||
self.write_byte(b);
|
self.write_byte(b);
|
||||||
}
|
}
|
||||||
|
@ -222,7 +221,7 @@ impl embedded_hal::serial::Write<u8> for Uart {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) -> nb::Result<(), Void> {
|
fn flush(&mut self) -> nb::Result<(), Void> {
|
||||||
if self.tx_fifo_empty() {
|
if self.tx_idle() {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(nb::Error::WouldBlock)
|
Err(nb::Error::WouldBlock)
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
/// The classic no-op
|
/// The classic no-op
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn nop() {
|
pub fn nop() {
|
||||||
unsafe { asm!("nop" :::: "volatile") }
|
unsafe { llvm_asm!("nop" :::: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait For Event
|
/// Wait For Event
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wfe() {
|
pub fn wfe() {
|
||||||
unsafe { asm!("wfe" :::: "volatile") }
|
unsafe { llvm_asm!("wfe" :::: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send Event
|
/// Send Event
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sev() {
|
pub fn sev() {
|
||||||
unsafe { asm!("sev" :::: "volatile") }
|
unsafe { llvm_asm!("sev" :::: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data Memory Barrier
|
/// Data Memory Barrier
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dmb() {
|
pub fn dmb() {
|
||||||
unsafe { asm!("dmb" :::: "volatile") }
|
unsafe { llvm_asm!("dmb" :::: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data Synchronization Barrier
|
/// Data Synchronization Barrier
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dsb() {
|
pub fn dsb() {
|
||||||
unsafe { asm!("dsb" :::: "volatile") }
|
unsafe { llvm_asm!("dsb" :::: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instruction Synchronization Barrier
|
/// Instruction Synchronization Barrier
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn isb() {
|
pub fn isb() {
|
||||||
unsafe { asm!("isb" :::: "volatile") }
|
unsafe { llvm_asm!("isb" :::: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn tlbiall() {
|
pub fn tlbiall() {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mcr p15, 0, $0, c8, c7, 0" :: "r" (0) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c8, c7, 0" :: "r" (0) :: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ pub fn tlbiall() {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn iciallu() {
|
pub fn iciallu() {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mcr p15, 0, $0, c7, c5, 0" :: "r" (0) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c5, 0" :: "r" (0) :: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ pub fn iciallu() {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bpiall() {
|
pub fn bpiall() {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mcr p15, 0, $0, c7, c5, 6" :: "r" (0) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c5, 6" :: "r" (0) :: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ pub fn bpiall() {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dccsw(setway: u32) {
|
pub fn dccsw(setway: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mcr p15, 0, $0, c7, c10, 2" :: "r" (setway) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c10, 2" :: "r" (setway) :: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ pub fn dcisw(setway: u32) {
|
||||||
// also see example code (for DCCISW, but DCISW will be
|
// also see example code (for DCCISW, but DCISW will be
|
||||||
// analogous) "Example code for cache maintenance operations"
|
// analogous) "Example code for cache maintenance operations"
|
||||||
// on pages B2-1286 and B2-1287.
|
// on pages B2-1286 and B2-1287.
|
||||||
asm!("mcr p15, 0, $0, c7, c6, 2" :: "r" (setway) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c6, 2" :: "r" (setway) :: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ pub fn dciall() {
|
||||||
|
|
||||||
// select L1 data cache
|
// select L1 data cache
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mcr p15, 2, $0, c0, c0, 0" :: "r" (0) :: "volatile");
|
llvm_asm!("mcr p15, 2, $0, c0, c0, 0" :: "r" (0) :: "volatile");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalidate entire D-Cache by iterating every set and every way
|
// Invalidate entire D-Cache by iterating every set and every way
|
||||||
|
@ -101,7 +101,7 @@ fn slice_cache_line_addrs<T>(slice: &[T]) -> impl Iterator<Item = usize> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dccimvac(addr: usize) {
|
pub fn dccimvac(addr: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mcr p15, 0, $0, c7, c14, 1" :: "r" (addr) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c14, 1" :: "r" (addr) :: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ pub fn dcci_slice<T>(slice: &mut [T]) {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dccmvac(addr: usize) {
|
pub fn dccmvac(addr: usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!("mcr p15, 0, $0, c7, c10, 1" :: "r" (addr) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c10, 1" :: "r" (addr) :: "volatile");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ pub fn dcc_slice<T>(slice: &[T]) {
|
||||||
/// affecting more data than intended.
|
/// affecting more data than intended.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn dcimvac(addr: usize) {
|
pub unsafe fn dcimvac(addr: usize) {
|
||||||
asm!("mcr p15, 0, $0, c7, c6, 1" :: "r" (addr) :: "volatile");
|
llvm_asm!("mcr p15, 0, $0, c7, c6, 1" :: "r" (addr) :: "volatile");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean and invalidate for an object.
|
/// Data cache clean and invalidate for an object.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(asm, global_asm)]
|
#![feature(llvm_asm, global_asm)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
|
@ -94,16 +94,11 @@ impl L1Entry {
|
||||||
}
|
}
|
||||||
|
|
||||||
const L1_TABLE_SIZE: usize = 4096;
|
const L1_TABLE_SIZE: usize = 4096;
|
||||||
#[doc(hidden)]
|
static mut L1_TABLE: L1Table = L1Table {
|
||||||
#[link_section = ".bss.l1_table"]
|
|
||||||
#[no_mangle]
|
|
||||||
pub static mut l1_table: L1Table = L1Table {
|
|
||||||
table: [L1Entry(0); L1_TABLE_SIZE]
|
table: [L1Entry(0); L1_TABLE_SIZE]
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The `#[repr(align(16384))]` is unfortunately ineffective. Hence we
|
#[repr(C, align(16384))]
|
||||||
/// require explicit linking to a region defined in the linker script.
|
|
||||||
#[repr(align(16384))]
|
|
||||||
pub struct L1Table {
|
pub struct L1Table {
|
||||||
table: [L1Entry; L1_TABLE_SIZE]
|
table: [L1Entry; L1_TABLE_SIZE]
|
||||||
}
|
}
|
||||||
|
@ -111,7 +106,7 @@ pub struct L1Table {
|
||||||
impl L1Table {
|
impl L1Table {
|
||||||
pub fn get() -> &'static mut Self {
|
pub fn get() -> &'static mut Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut l1_table
|
&mut L1_TABLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ macro_rules! def_reg_r {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read(&self) -> Self::R {
|
fn read(&self) -> Self::R {
|
||||||
let mut value: u32;
|
let mut value: u32;
|
||||||
unsafe { asm!($asm_instr : "=r" (value) ::: "volatile") }
|
unsafe { llvm_asm!($asm_instr : "=r" (value) ::: "volatile") }
|
||||||
value.into()
|
value.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ macro_rules! def_reg_w {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write(&mut self, value: Self::W) {
|
fn write(&mut self, value: Self::W) {
|
||||||
let value: u32 = value.into();
|
let value: u32 = value.into();
|
||||||
unsafe { asm!($asm_instr :: "r" (value) :: "volatile") }
|
unsafe { llvm_asm!($asm_instr :: "r" (value) :: "volatile") }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -12,7 +12,6 @@ target_cora_z7_10 = ["libboard_zynq/target_cora_z7_10"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
r0 = "1"
|
r0 = "1"
|
||||||
compiler_builtins = "0.1"
|
compiler_builtins = "0.1"
|
||||||
log = "0.4"
|
|
||||||
linked_list_allocator = { version = "0.8", default-features = false }
|
linked_list_allocator = { version = "0.8", default-features = false }
|
||||||
libregister = { path = "../libregister" }
|
libregister = { path = "../libregister" }
|
||||||
libcortex_a9 = { path = "../libcortex_a9" }
|
libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
|
|
|
@ -9,13 +9,13 @@ use libboard_zynq::{slcr, mpcore};
|
||||||
extern "C" {
|
extern "C" {
|
||||||
static mut __bss_start: u32;
|
static mut __bss_start: u32;
|
||||||
static mut __bss_end: u32;
|
static mut __bss_end: u32;
|
||||||
static mut __stack_start: u32;
|
static mut __stack0_start: u32;
|
||||||
|
static mut __stack1_start: u32;
|
||||||
fn main_core0();
|
fn main_core0();
|
||||||
fn main_core1();
|
fn main_core1();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `0` means: wait for initialization by core0
|
static mut CORE1_ENABLED: VolatileCell<bool> = VolatileCell::new(false);
|
||||||
static mut CORE1_STACK: VolatileCell<u32> = VolatileCell::new(0);
|
|
||||||
|
|
||||||
#[link_section = ".text.boot"]
|
#[link_section = ".text.boot"]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -25,15 +25,14 @@ pub unsafe extern "C" fn _boot_cores() -> ! {
|
||||||
|
|
||||||
match MPIDR.read() & CORE_MASK {
|
match MPIDR.read() & CORE_MASK {
|
||||||
0 => {
|
0 => {
|
||||||
SP.write(&mut __stack_start as *mut _ as u32);
|
SP.write(&mut __stack0_start as *mut _ as u32);
|
||||||
boot_core0();
|
boot_core0();
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
while CORE1_STACK.get() == 0 {
|
while !CORE1_ENABLED.get() {
|
||||||
asm::wfe();
|
asm::wfe();
|
||||||
}
|
}
|
||||||
|
SP.write(&mut __stack1_start as *mut _ as u32);
|
||||||
SP.write(CORE1_STACK.get());
|
|
||||||
boot_core1();
|
boot_core1();
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -104,18 +103,12 @@ fn l1_cache_init() {
|
||||||
dciall();
|
dciall();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Core1<S: AsMut<[u32]>> {
|
pub struct Core1 {
|
||||||
pub stack: S,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: AsMut<[u32]>> Core1<S> {
|
impl Core1 {
|
||||||
/// Reset and start core1
|
/// Reset and start core1
|
||||||
///
|
pub fn start() -> Self {
|
||||||
/// 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)
|
// reset and stop (safe to repeat)
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(true));
|
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(true));
|
||||||
|
@ -123,15 +116,13 @@ impl<S: AsMut<[u32]>> Core1<S> {
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_rst1(false));
|
||||||
});
|
});
|
||||||
|
|
||||||
let stack = core.stack.as_mut();
|
|
||||||
let stack_start = &mut stack[stack.len() - 1];
|
|
||||||
unsafe {
|
unsafe {
|
||||||
CORE1_STACK.set(stack_start as *mut _ as u32);
|
CORE1_ENABLED.set(true);
|
||||||
}
|
}
|
||||||
// Ensure stack pointer has been written to cache
|
// Ensure stack pointer has been written to cache
|
||||||
asm::dmb();
|
asm::dmb();
|
||||||
// Flush cache-line
|
// Flush cache-line
|
||||||
cache::dccmvac(unsafe { &CORE1_STACK } as *const _ as usize);
|
cache::dccmvac(unsafe { &CORE1_ENABLED } as *const _ as usize);
|
||||||
|
|
||||||
// wake up core1
|
// wake up core1
|
||||||
slcr::RegisterBlock::unlocked(|slcr| {
|
slcr::RegisterBlock::unlocked(|slcr| {
|
||||||
|
@ -139,12 +130,12 @@ impl<S: AsMut<[u32]>> Core1<S> {
|
||||||
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(false));
|
slcr.a9_cpu_rst_ctrl.modify(|_, w| w.a9_clkstop1(false));
|
||||||
});
|
});
|
||||||
|
|
||||||
core
|
Core1 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disable(&self) {
|
pub fn disable(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
CORE1_STACK.set(0);
|
CORE1_ENABLED.set(false);
|
||||||
}
|
}
|
||||||
self.restart();
|
self.restart();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,5 +10,4 @@ pub extern crate compiler_builtins;
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
mod abort;
|
mod abort;
|
||||||
mod panic;
|
mod panic;
|
||||||
pub mod logger;
|
|
||||||
pub mod ram;
|
pub mod ram;
|
||||||
|
|
64
link.x
64
link.x
|
@ -1,64 +0,0 @@
|
||||||
ENTRY(_boot_cores);
|
|
||||||
|
|
||||||
STACK_SIZE = 0x8000;
|
|
||||||
|
|
||||||
/* Provide some defaults */
|
|
||||||
PROVIDE(Reset = _boot_cores);
|
|
||||||
PROVIDE(UndefinedInstruction = Reset);
|
|
||||||
PROVIDE(SoftwareInterrupt = Reset);
|
|
||||||
PROVIDE(PrefetchAbort = Reset);
|
|
||||||
PROVIDE(DataAbort = Reset);
|
|
||||||
PROVIDE(ReservedException = Reset);
|
|
||||||
PROVIDE(IRQ = Reset);
|
|
||||||
PROVIDE(FIQ = Reset);
|
|
||||||
|
|
||||||
MEMORY
|
|
||||||
{
|
|
||||||
/* 256 kB On-Chip Memory */
|
|
||||||
OCM : ORIGIN = 0, LENGTH = 0x30000
|
|
||||||
OCM3 : ORIGIN = 0xFFFF0000, LENGTH = 0x10000
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
KEEP(*(.text.exceptions));
|
|
||||||
*(.text.boot);
|
|
||||||
*(.text .text.*);
|
|
||||||
} > OCM
|
|
||||||
|
|
||||||
.rodata : ALIGN(4)
|
|
||||||
{
|
|
||||||
*(.rodata .rodata.*);
|
|
||||||
} > OCM
|
|
||||||
|
|
||||||
.data : ALIGN(4)
|
|
||||||
{
|
|
||||||
*(.data .data.*);
|
|
||||||
} > OCM
|
|
||||||
|
|
||||||
.bss (NOLOAD) : ALIGN(0x4000)
|
|
||||||
{
|
|
||||||
/* Aligned to 16 kB */
|
|
||||||
KEEP(*(.bss.l1_table));
|
|
||||||
*(.bss .bss.*);
|
|
||||||
. = ALIGN(4);
|
|
||||||
} > OCM
|
|
||||||
__bss_start = ADDR(.bss);
|
|
||||||
__bss_end = ADDR(.bss) + SIZEOF(.bss);
|
|
||||||
|
|
||||||
.stack (NOLOAD) : ALIGN(0x1000) {
|
|
||||||
. += STACK_SIZE;
|
|
||||||
} > OCM
|
|
||||||
__stack_end = ADDR(.stack);
|
|
||||||
__stack_start = ADDR(.stack) + SIZEOF(.stack);
|
|
||||||
|
|
||||||
/DISCARD/ :
|
|
||||||
{
|
|
||||||
/* Unused exception related info that only wastes space */
|
|
||||||
*(.ARM.exidx);
|
|
||||||
*(.ARM.exidx.*);
|
|
||||||
*(.ARM.extab.*);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue