forked from M-Labs/zynq-rs
Compare commits
15 Commits
fa07bdb681
...
bb09d25378
Author | SHA1 | Date | |
---|---|---|---|
bb09d25378 | |||
a1f859637a | |||
7cb2669c3b | |||
511c906d4d | |||
1ba0aa450f | |||
283bc9b810 | |||
b268fe015a | |||
64db9b0142 | |||
4b258c19f5 | |||
1a96a7550a | |||
36947104e3 | |||
11089d8a64 | |||
c69cd9951e | |||
76a4cac873 | |||
4614ed1371 |
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -22,7 +22,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.27"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@ -79,6 +79,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libregister 0.0.0",
|
||||
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -94,7 +95,7 @@ dependencies = [
|
||||
name = "libsupport_zynq"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"compiler_builtins 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"compiler_builtins 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libboard_zynq 0.0.0",
|
||||
"libcortex_a9 0.0.0",
|
||||
"libregister 0.0.0",
|
||||
@ -168,7 +169,7 @@ dependencies = [
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
"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.32 (registry+https://github.com/rust-lang/crates.io-index)" = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c"
|
||||
"checksum embedded-hal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4908a155094da7723c2d60d617b820061e3b4efcc3d9e293d206a5a76c170b"
|
||||
"checksum linked_list_allocator 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e70e46c13c0e8374c26cec5752e3347ca1087d9711de8f45aa513a7700efd73d"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
|
17
README.md
17
README.md
@ -1,7 +1,7 @@
|
||||
# Build
|
||||
|
||||
```shell
|
||||
nix-shell --command "cargo xbuild --release"
|
||||
nix-shell --command "cargo xbuild --release -p experiments"
|
||||
```
|
||||
|
||||
Currently the ELF output is placed at `target/armv7-none-eabihf/release/experiments`
|
||||
@ -41,7 +41,7 @@ Proceed using gdb with `load`, `c`
|
||||
### Running on the ZC706
|
||||
|
||||
```shell
|
||||
nix-shell --command "cargo xbuild --release"
|
||||
nix-shell --command "cargo xbuild --release -p experiments"
|
||||
cd openocd
|
||||
openocd -f zc706.cfg
|
||||
```
|
||||
@ -57,23 +57,26 @@ openocd -f cora-z7-10.cfg
|
||||
### Loading a bitstream into volatile memory
|
||||
|
||||
```shell
|
||||
openocd -f zc706.cfg -c "pld load 0 blinker_migen.bit; exit"
|
||||
openocd -f zc706.cfg -c "pld load 0 blinker_migen.bit; exit"
|
||||
```
|
||||
|
||||
### Development Process
|
||||
|
||||
Clone this repo onto your development/build machine and the raspberry pi that controls the Xilinx 7000 board
|
||||
|
||||
On the dev machine, the below script builds zc706 and secure copies it to the target pi (in your pi $HOME directory)
|
||||
On the dev machine, the below script builds zc706 and secure copies it to the target pi (in your pi $HOME directory):
|
||||
```shell
|
||||
cd ~/zc706
|
||||
./build.sh $your_user/ssh_id
|
||||
cd ~/zynq-rs
|
||||
./build.sh $your_user_or_ssh_id
|
||||
```
|
||||
|
||||
On the pi, we need an information rich environment that includes a relatively reliable `gdb` experience (that includes `ctrl-p` and `ctrl-n` command history that persists across `cgdb` executions), run:
|
||||
```shell
|
||||
ssh pi4
|
||||
cd zc706
|
||||
cd zynq-rs
|
||||
# For ZC706, run:
|
||||
./tmux.sh 0
|
||||
# For Cora Z7, run:
|
||||
./tmux.sh
|
||||
```
|
||||
|
||||
|
2
build.sh
2
build.sh
@ -1 +1 @@
|
||||
nix-shell --command "cargo xbuild --release -p experiments" && scp -P 2204 -C target/armv7-none-eabihf/release/zc706-experiments $1@nixbld.m-labs.hk:/home/$1/zc706/zc706.elf
|
||||
nix-shell --command "cargo xbuild --release -p experiments" && scp -C target/armv7-none-eabihf/release/experiments $1@rpi-4.m-labs.hk:/home/$1/zc706/zc706.elf
|
||||
|
@ -49,7 +49,7 @@ let
|
||||
name = "${crate}";
|
||||
src = ./.;
|
||||
crateSubdir = crate;
|
||||
cargoSha256 = "1c1qpg9by8bg93yhgllb5xs155g27qmh99pbrb681wazm8k7nwim";
|
||||
cargoSha256 = "1gdxrsn58mabqf8yc3xqkrl1qlmlyvpnzcfj4xafpdr1gdhwhdjg";
|
||||
cargoFeatures = features;
|
||||
doCheck = false;
|
||||
dontFixup = true;
|
||||
|
@ -27,6 +27,7 @@ use libboard_zynq::{
|
||||
};
|
||||
use libcortex_a9::{
|
||||
mutex::Mutex,
|
||||
l2c::enable_l2_cache,
|
||||
sync_channel::{Sender, Receiver},
|
||||
sync_channel,
|
||||
regs::{MPIDR, SP},
|
||||
@ -56,8 +57,8 @@ static CORE1_RESTART: AtomicBool = AtomicBool::new(false);
|
||||
#[naked]
|
||||
pub unsafe extern "C" fn IRQ() {
|
||||
if MPIDR.read().cpu_id() == 1{
|
||||
let mpcore = mpcore::RegisterBlock::new();
|
||||
let mut gic = gic::InterruptController::new(mpcore);
|
||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||
let mut gic = gic::InterruptController::gic(mpcore);
|
||||
let id = gic.get_interrupt_id();
|
||||
if id.0 == 0 {
|
||||
gic.end_interrupt(id);
|
||||
@ -75,7 +76,7 @@ pub unsafe extern "C" fn IRQ() {
|
||||
}
|
||||
|
||||
pub fn restart_core1() {
|
||||
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
|
||||
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
||||
CORE1_RESTART.store(true, Ordering::Relaxed);
|
||||
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core1.into());
|
||||
while CORE1_RESTART.load(Ordering::Relaxed) {
|
||||
@ -86,8 +87,9 @@ pub fn restart_core1() {
|
||||
#[no_mangle]
|
||||
pub fn main_core0() {
|
||||
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
|
||||
enable_l2_cache();
|
||||
println!("\nzc706 main");
|
||||
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
|
||||
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
||||
interrupt_controller.enable_interrupts();
|
||||
// ps7_init::apply();
|
||||
libboard_zynq::stdio::drop_uart();
|
||||
@ -97,7 +99,7 @@ pub fn main_core0() {
|
||||
|
||||
info!(
|
||||
"Boot mode: {:?}",
|
||||
zynq::slcr::RegisterBlock::new()
|
||||
zynq::slcr::RegisterBlock::slcr()
|
||||
.boot_mode
|
||||
.read()
|
||||
.boot_mode_pins()
|
||||
@ -131,7 +133,7 @@ pub fn main_core0() {
|
||||
clocks.cpu_1x()
|
||||
);
|
||||
|
||||
let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode();
|
||||
let mut flash = zynq::flash::Flash::flash(200_000_000).linear_addressing_mode();
|
||||
let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) };
|
||||
for i in 0..=1 {
|
||||
print!("Flash {}:", i);
|
||||
@ -144,7 +146,7 @@ pub fn main_core0() {
|
||||
|
||||
let timer = libboard_zynq::timer::GlobalTimer::start();
|
||||
|
||||
let mut ddr = zynq::ddr::DdrRam::new();
|
||||
let mut ddr = zynq::ddr::DdrRam::ddrram();
|
||||
#[cfg(not(feature = "target_zc706"))]
|
||||
ddr.memtest();
|
||||
ram::init_alloc_ddr(&mut ddr);
|
||||
@ -203,38 +205,41 @@ pub fn main_core0() {
|
||||
unsafe {
|
||||
core1_req.drop_elements();
|
||||
}
|
||||
|
||||
// Test I2C
|
||||
let mut i2c = zynq::i2c::I2C::i2c();
|
||||
i2c.init();
|
||||
println!("I2C bit-banging enabled");
|
||||
let mut eeprom = zynq::i2c::eeprom::EEPROM::new(&mut i2c, 16);
|
||||
// Write to 0x00 and 0x08
|
||||
let eeprom_buffer: [u8; 22] = [
|
||||
0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
|
||||
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
|
||||
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
|
||||
];
|
||||
eeprom.write(0x00, &eeprom_buffer[0..6]);
|
||||
eeprom.write(0x08, &eeprom_buffer[6..22]);
|
||||
println!("Data written to EEPROM");
|
||||
let mut eeprom_buffer = [0u8; 24];
|
||||
// Read from 0x00
|
||||
eeprom.read(0x00, &mut eeprom_buffer);
|
||||
print!("Data read from EEPROM @ 0x00: (hex) ");
|
||||
for i in 0..6 {
|
||||
print!("{:02x} ", eeprom_buffer[i]);
|
||||
}
|
||||
println!("");
|
||||
// Read from 0x08
|
||||
eeprom.read(0x08, &mut eeprom_buffer);
|
||||
print!("Data read from EEPROM @ 0x08: (hex) ");
|
||||
for i in 0..16 {
|
||||
print!("{:02x} ", eeprom_buffer[i]);
|
||||
}
|
||||
println!("");
|
||||
|
||||
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
||||
// Test I2C
|
||||
#[cfg(feature = "target_zc706")]
|
||||
{
|
||||
let mut i2c = zynq::i2c::I2c::i2c0();
|
||||
i2c.init();
|
||||
println!("I2C bit-banging enabled");
|
||||
let mut eeprom = zynq::i2c::eeprom::EEPROM::new(&mut i2c, 16);
|
||||
// Write to 0x00 and 0x08
|
||||
let eeprom_buffer: [u8; 22] = [
|
||||
0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
|
||||
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
|
||||
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
|
||||
];
|
||||
eeprom.write(0x00, &eeprom_buffer[0..6]);
|
||||
eeprom.write(0x08, &eeprom_buffer[6..22]);
|
||||
println!("Data written to EEPROM");
|
||||
let mut eeprom_buffer = [0u8; 24];
|
||||
// Read from 0x00
|
||||
eeprom.read(0x00, &mut eeprom_buffer);
|
||||
print!("Data read from EEPROM @ 0x00: (hex) ");
|
||||
for i in 0..6 {
|
||||
print!("{:02x} ", eeprom_buffer[i]);
|
||||
}
|
||||
println!("");
|
||||
// Read from 0x08
|
||||
eeprom.read(0x08, &mut eeprom_buffer);
|
||||
print!("Data read from EEPROM @ 0x08: (hex) ");
|
||||
for i in 0..16 {
|
||||
print!("{:02x} ", eeprom_buffer[i]);
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
|
||||
let eth = zynq::eth::Eth::eth0(HWADDR.clone());
|
||||
println!("Eth on");
|
||||
|
||||
const RX_LEN: usize = 4096;
|
||||
@ -328,7 +333,7 @@ static DONE: Mutex<bool> = Mutex::new(false);
|
||||
#[no_mangle]
|
||||
pub fn main_core1() {
|
||||
println!("Hello from core1!");
|
||||
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
|
||||
let mut interrupt_controller = gic::InterruptController::gic(mpcore::RegisterBlock::mpcore());
|
||||
interrupt_controller.enable_interrupts();
|
||||
let req = unsafe { &mut CORE1_REQ.1 };
|
||||
let res = unsafe { &mut CORE1_RES.0 };
|
||||
|
@ -6,7 +6,7 @@ use core::{
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
};
|
||||
use alloc::{boxed::Box, collections::VecDeque as Deque};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
//use futures::future::FutureExt;
|
||||
use pin_utils::pin_mut;
|
||||
|
||||
@ -31,7 +31,7 @@ static VTABLE: RawWakerVTable = {
|
||||
/// ready should not move as long as this waker references it. That is
|
||||
/// the reason for keeping Tasks in a pinned box.
|
||||
fn wrap_waker(ready: &AtomicBool) -> Waker {
|
||||
unsafe { Waker::from_raw(RawWaker::new(ready as *const _ as *const _, &VTABLE)) }
|
||||
unsafe { Waker::from_raw(RawWaker::new(ready as *const _ as *const (), &VTABLE)) }
|
||||
}
|
||||
|
||||
/// A single-threaded executor
|
||||
@ -44,7 +44,7 @@ pub struct Executor {
|
||||
/// Tasks reside on the heap, so that we just queue pointers. They
|
||||
/// must also be pinned in memory because our RawWaker is a pointer
|
||||
/// to their `ready` field.
|
||||
tasks: RefCell<Deque<Pin<Box<Task>>>>,
|
||||
tasks: RefCell<Vec<Pin<Box<Task>>>>,
|
||||
}
|
||||
|
||||
impl Executor {
|
||||
@ -52,7 +52,7 @@ impl Executor {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
in_block_on: RefCell::new(false),
|
||||
tasks: RefCell::new(Deque::new()),
|
||||
tasks: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,10 +85,9 @@ impl Executor {
|
||||
// println!("ran block_on");
|
||||
}
|
||||
|
||||
// println!("tasks: {}", self.tasks.borrow().len());
|
||||
// advance other tasks
|
||||
let next_task = self.tasks.borrow_mut().pop_front();
|
||||
if let Some(mut task) = next_task {
|
||||
// advance all tasks
|
||||
let next_tasks = self.tasks.replace_with(|tasks| Vec::with_capacity(tasks.len()));
|
||||
for mut task in next_tasks.into_iter() {
|
||||
// NOTE we don't need a CAS operation here because `wake` invocations that come from
|
||||
// interrupt handlers (the only source of 'race conditions' (!= data races)) are
|
||||
// "oneshot": they'll issue a `wake` and then disable themselves to not run again
|
||||
@ -106,7 +105,7 @@ impl Executor {
|
||||
}
|
||||
}
|
||||
// Requeue
|
||||
self.tasks.borrow_mut().push_back(task);
|
||||
self.tasks.borrow_mut().push(task);
|
||||
}
|
||||
|
||||
// // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an
|
||||
@ -119,7 +118,7 @@ impl Executor {
|
||||
|
||||
pub fn spawn(&self, f: impl Future + 'static) {
|
||||
let task = Box::pin(Task::new(f));
|
||||
self.tasks.borrow_mut().push_back(task);
|
||||
self.tasks.borrow_mut().push(task);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ enum CpuClockMode {
|
||||
|
||||
impl CpuClockMode {
|
||||
pub fn get() -> Self {
|
||||
let regs = slcr::RegisterBlock::new();
|
||||
let regs = slcr::RegisterBlock::slcr();
|
||||
if regs.clk_621_true.read().clk_621_true() {
|
||||
CpuClockMode::C621
|
||||
} else {
|
||||
@ -59,7 +59,7 @@ impl Clocks {
|
||||
}
|
||||
|
||||
pub fn cpu_6x4x(&self) -> u32 {
|
||||
let slcr = slcr::RegisterBlock::new();
|
||||
let slcr = slcr::RegisterBlock::slcr();
|
||||
let arm_clk_ctrl = slcr.arm_clk_ctrl.read();
|
||||
let pll = match arm_clk_ctrl.srcsel() {
|
||||
ArmPllSource::ArmPll => self.arm,
|
||||
@ -92,7 +92,7 @@ impl Clocks {
|
||||
}
|
||||
|
||||
pub fn uart_ref_clk(&self) -> u32 {
|
||||
let regs = slcr::RegisterBlock::new();
|
||||
let regs = slcr::RegisterBlock::slcr();
|
||||
let uart_clk_ctrl = regs.uart_clk_ctrl.read();
|
||||
let pll = match uart_clk_ctrl.srcsel() {
|
||||
slcr::PllSource::ArmPll =>
|
||||
@ -106,7 +106,7 @@ impl Clocks {
|
||||
}
|
||||
|
||||
pub fn sdio_ref_clk(&self) -> u32 {
|
||||
let regs = slcr::RegisterBlock::new();
|
||||
let regs = slcr::RegisterBlock::slcr();
|
||||
let sdio_clk_ctrl = regs.sdio_clk_ctrl.read();
|
||||
let pll = match sdio_clk_ctrl.srcsel() {
|
||||
slcr::PllSource::ArmPll =>
|
||||
|
@ -44,7 +44,7 @@ pub trait ClockSource {
|
||||
|
||||
/// get configured frequency
|
||||
fn freq() -> u32 {
|
||||
let mut slcr = slcr::RegisterBlock::new();
|
||||
let mut slcr = slcr::RegisterBlock::slcr();
|
||||
let (pll_ctrl, _, _) = Self::pll_regs(&mut slcr);
|
||||
u32::from(pll_ctrl.read().pll_fdiv()) * PS_CLK
|
||||
}
|
||||
|
@ -22,12 +22,12 @@ pub struct DdrRam {
|
||||
}
|
||||
|
||||
impl DdrRam {
|
||||
pub fn new() -> Self {
|
||||
pub fn ddrram() -> Self {
|
||||
let clocks = Self::clock_setup();
|
||||
Self::calibrate_iob_impedance(&clocks);
|
||||
Self::configure_iob();
|
||||
|
||||
let regs = unsafe { regs::RegisterBlock::new() };
|
||||
let regs = unsafe { regs::RegisterBlock::ddrc() };
|
||||
let mut ddr = DdrRam { regs };
|
||||
ddr.configure();
|
||||
ddr.reset_ddrc();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use volatile_register::{RO, RW};
|
||||
|
||||
use libregister::{register, register_bit, register_bits, register_bits_typed};
|
||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Clone, Copy)]
|
||||
@ -158,11 +158,7 @@ pub struct RegisterBlock {
|
||||
pub lpddr_ctrl3: RW<u32>,
|
||||
}
|
||||
|
||||
impl RegisterBlock {
|
||||
pub unsafe fn new() -> &'static mut Self {
|
||||
&mut *(0xF8006000 as *mut _)
|
||||
}
|
||||
}
|
||||
register_at!(RegisterBlock, 0xF8006000, ddrc);
|
||||
|
||||
register!(ddrc_ctrl, DdrcCtrl, RW, u32);
|
||||
register_bit!(ddrc_ctrl,
|
||||
|
@ -27,7 +27,7 @@ const TX_1000: u32 = 125_000_000;
|
||||
pub struct Buffer(pub [u8; MTU]);
|
||||
|
||||
impl Buffer {
|
||||
pub fn new() -> Self {
|
||||
pub const fn new() -> Self {
|
||||
Buffer([0; MTU])
|
||||
}
|
||||
}
|
||||
@ -148,7 +148,7 @@ pub struct Eth<GEM: Gem, RX, TX> {
|
||||
}
|
||||
|
||||
impl Eth<Gem0, (), ()> {
|
||||
pub fn default(macaddr: [u8; 6]) -> Self {
|
||||
pub fn eth0(macaddr: [u8; 6]) -> Self {
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
// Manual example: 0x0000_1280
|
||||
// MDIO
|
||||
@ -224,48 +224,48 @@ impl Eth<Gem0, (), ()> {
|
||||
// RX_CLK
|
||||
slcr.mio_pin_22.write(
|
||||
slcr::MioPin22::zeroed()
|
||||
.tri_enable(true)
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
);
|
||||
// RX_CTRL
|
||||
slcr.mio_pin_27.write(
|
||||
slcr::MioPin27::zeroed()
|
||||
.tri_enable(true)
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
);
|
||||
// RXD3
|
||||
slcr.mio_pin_26.write(
|
||||
slcr::MioPin26::zeroed()
|
||||
.tri_enable(true)
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
);
|
||||
// RXD2
|
||||
slcr.mio_pin_25.write(
|
||||
slcr::MioPin25::zeroed()
|
||||
.tri_enable(true)
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
);
|
||||
// RXD1
|
||||
slcr.mio_pin_24.write(
|
||||
slcr::MioPin24::zeroed()
|
||||
.tri_enable(true)
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
);
|
||||
// RXD0
|
||||
slcr.mio_pin_23.write(
|
||||
slcr::MioPin23::zeroed()
|
||||
.tri_enable(true)
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
);
|
||||
@ -280,19 +280,22 @@ impl Eth<Gem0, (), ()> {
|
||||
}
|
||||
|
||||
pub fn gem0(macaddr: [u8; 6]) -> Self {
|
||||
Self::new(macaddr)
|
||||
Self::gem_common(macaddr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Eth<Gem1, (), ()> {
|
||||
// TODO: Add a `eth1()`
|
||||
|
||||
pub fn gem1(macaddr: [u8; 6]) -> Self {
|
||||
Self::new(macaddr)
|
||||
Self::gem_common(macaddr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<GEM: Gem> Eth<GEM, (), ()> {
|
||||
fn new(macaddr: [u8; 6]) -> Self {
|
||||
fn gem_common(macaddr: [u8; 6]) -> Self {
|
||||
GEM::setup_clock(TX_1000);
|
||||
|
||||
let mut inner = EthInner {
|
||||
@ -530,7 +533,10 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
|
||||
fn configure(&mut self, macaddr: [u8; 6]) {
|
||||
let clocks = Clocks::get();
|
||||
let mdc_clk_div = (clocks.cpu_1x() / MAX_MDC) + 1;
|
||||
let mut mdc_clk_div = clocks.cpu_1x() / MAX_MDC;
|
||||
if clocks.cpu_1x() % MAX_MDC > 0 {
|
||||
mdc_clk_div += 1;
|
||||
}
|
||||
|
||||
GEM::regs().net_cfg.write(
|
||||
regs::NetCfg::zeroed()
|
||||
@ -539,10 +545,10 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
.speed(true)
|
||||
.no_broadcast(false)
|
||||
.multi_hash_en(true)
|
||||
// Promiscuous mode (TODO?)
|
||||
.copy_all(true)
|
||||
.rx_1536_byte_frames(true)
|
||||
// Remove 4-byte Frame CheckSum
|
||||
.fcs_remove(true)
|
||||
.dis_cp_pause_frame(true)
|
||||
// RX checksum offload
|
||||
.rx_chksum_offld_en(true)
|
||||
// One of the slower speeds
|
||||
@ -550,22 +556,23 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
);
|
||||
|
||||
let macaddr_msbs =
|
||||
(u16::from(macaddr[0]) << 8) |
|
||||
u16::from(macaddr[1]);
|
||||
(u16::from(macaddr[5]) << 8) |
|
||||
u16::from(macaddr[4]);
|
||||
let macaddr_lsbs =
|
||||
(u32::from(macaddr[2]) << 24) |
|
||||
(u32::from(macaddr[3]) << 16) |
|
||||
(u32::from(macaddr[4]) << 8) |
|
||||
u32::from(macaddr[5]);
|
||||
GEM::regs().spec_addr1_top.write(
|
||||
regs::SpecAddrTop::zeroed()
|
||||
.addr_msbs(macaddr_msbs)
|
||||
);
|
||||
(u32::from(macaddr[3]) << 24) |
|
||||
(u32::from(macaddr[2]) << 16) |
|
||||
(u32::from(macaddr[1]) << 8) |
|
||||
u32::from(macaddr[0]);
|
||||
// writing to bot would disable the specific address
|
||||
GEM::regs().spec_addr1_bot.write(
|
||||
regs::SpecAddrBot::zeroed()
|
||||
.addr_lsbs(macaddr_lsbs)
|
||||
);
|
||||
|
||||
// writing to top would enable it again
|
||||
GEM::regs().spec_addr1_top.write(
|
||||
regs::SpecAddrTop::zeroed()
|
||||
.addr_msbs(macaddr_msbs)
|
||||
);
|
||||
|
||||
GEM::regs().dma_cfg.write(
|
||||
regs::DmaCfg::zeroed()
|
||||
|
@ -1,6 +1,6 @@
|
||||
use volatile_register::{RO, WO, RW};
|
||||
|
||||
use libregister::{register, register_bit, register_bits, register_bits_typed};
|
||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
@ -110,18 +110,8 @@ pub struct RegisterBlock {
|
||||
pub design_cfg5: RO<u32>,
|
||||
}
|
||||
|
||||
impl RegisterBlock {
|
||||
const GEM0: *mut Self = 0xE000B000 as *mut _;
|
||||
const GEM1: *mut Self = 0xE000C000 as *mut _;
|
||||
|
||||
pub fn gem0() -> &'static mut Self {
|
||||
unsafe { &mut *Self::GEM0 }
|
||||
}
|
||||
|
||||
pub fn gem1() -> &'static mut Self {
|
||||
unsafe { &mut *Self::GEM1 }
|
||||
}
|
||||
}
|
||||
register_at!(RegisterBlock, 0xE000B000, gem0);
|
||||
register_at!(RegisterBlock, 0xE000C000, gem1);
|
||||
|
||||
register!(net_ctrl, NetCtrl, RW, u32);
|
||||
register_bit!(net_ctrl, loopback_local, 1);
|
||||
|
@ -108,6 +108,20 @@ impl DescList {
|
||||
if entry.word0.read().used() {
|
||||
let word1 = entry.word1.read();
|
||||
let len = word1.frame_length_lsbs().into();
|
||||
let padding = {
|
||||
let diff = len % 0x20;
|
||||
if diff == 0 {
|
||||
0
|
||||
} else {
|
||||
0x20 - diff
|
||||
}
|
||||
};
|
||||
unsafe {
|
||||
// invalidate the buffer
|
||||
// we cannot do it in the drop function, as L2 cache data prefetch would prefetch
|
||||
// the data, and there is no way for us to prevent that unless changing MMU table.
|
||||
dci_slice(&mut self.buffers[self.next][0..len + padding]);
|
||||
}
|
||||
let buffer = &mut self.buffers[self.next][0..len];
|
||||
|
||||
self.next += 1;
|
||||
@ -135,10 +149,6 @@ pub struct PktRef<'a> {
|
||||
|
||||
impl<'a> Drop for PktRef<'a> {
|
||||
fn drop(&mut self) {
|
||||
// Flush buffer from cache, to be filled by the peripheral
|
||||
// before next read
|
||||
dcci_slice(self.buffer);
|
||||
|
||||
self.entry.word0.modify(|_, w| w.used(false));
|
||||
dmb();
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ impl<MODE> Flash<MODE> {
|
||||
}
|
||||
|
||||
impl Flash<()> {
|
||||
pub fn new(clock: u32) -> Self {
|
||||
pub fn flash(clock: u32) -> Self {
|
||||
Self::enable_clocks(clock);
|
||||
Self::setup_signals();
|
||||
Self::reset();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use volatile_register::{RO, WO, RW};
|
||||
|
||||
use libregister::{register, register_bit, register_bits};
|
||||
use libregister::{register, register_at, register_bit, register_bits};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
@ -30,13 +30,9 @@ pub struct RegisterBlock {
|
||||
pub mod_id: RW<u32>,
|
||||
}
|
||||
|
||||
impl RegisterBlock {
|
||||
const BASE_ADDRESS: *mut Self = 0xE000D000 as *mut _;
|
||||
const BASE_ADDRESS: u32 = 0xE000D000;
|
||||
|
||||
pub fn qspi() -> &'static mut Self {
|
||||
unsafe { &mut *Self::BASE_ADDRESS }
|
||||
}
|
||||
}
|
||||
register_at!(RegisterBlock, 0xE000D000, qspi);
|
||||
|
||||
register!(config, Config, RW, u32);
|
||||
register_bit!(config,
|
||||
|
@ -62,7 +62,7 @@ pub struct InterruptController {
|
||||
}
|
||||
|
||||
impl InterruptController {
|
||||
pub fn new(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
|
||||
pub fn gic(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
|
||||
InterruptController { mpcore }
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
use super::I2C;
|
||||
use super::I2c;
|
||||
use crate::time::Milliseconds;
|
||||
use embedded_hal::timer::CountDown;
|
||||
|
||||
pub struct EEPROM<'a> {
|
||||
i2c: &'a mut I2C,
|
||||
i2c: &'a mut I2c,
|
||||
port: u8,
|
||||
address: u8,
|
||||
page_size: u8,
|
||||
@ -12,7 +12,7 @@ pub struct EEPROM<'a> {
|
||||
|
||||
impl<'a> EEPROM<'a> {
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub fn new(i2c: &'a mut I2C, page_size: u8) -> Self {
|
||||
pub fn new(i2c: &'a mut I2c, page_size: u8) -> Self {
|
||||
EEPROM {
|
||||
i2c: i2c,
|
||||
port: 2,
|
||||
|
@ -2,25 +2,19 @@
|
||||
|
||||
mod regs;
|
||||
pub mod eeprom;
|
||||
use super::clocks::Clocks;
|
||||
use super::slcr;
|
||||
use super::time::Microseconds;
|
||||
use embedded_hal::timer::CountDown;
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||
|
||||
const INVALID_BUS: &'static str = "Invalid I2C bus";
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
const GPIO_OUTPUT_MASK: u16 = 0xFFFF - 0x000C;
|
||||
|
||||
pub struct I2C {
|
||||
regs: regs::RegisterWrapper,
|
||||
pub struct I2c {
|
||||
regs: regs::RegisterBlock,
|
||||
count_down: super::timer::global::CountDown<Microseconds>
|
||||
}
|
||||
|
||||
impl I2C {
|
||||
impl I2c {
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub fn i2c() -> Self {
|
||||
pub fn i2c0() -> Self {
|
||||
// Route I2C 0 SCL / SDA Signals to MIO Pins 50 / 51
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
// SCL
|
||||
@ -43,20 +37,19 @@ impl I2C {
|
||||
slcr.gpio_rst_ctrl.reset_gpio();
|
||||
});
|
||||
|
||||
Self::ctor_common()
|
||||
Self::i2c_common(0xFFFF - 0x000C)
|
||||
}
|
||||
|
||||
fn ctor_common() -> Self {
|
||||
fn i2c_common(gpio_output_mask: u16) -> Self {
|
||||
// Setup register block
|
||||
let clocks = Clocks::get();
|
||||
let self_ = Self {
|
||||
regs: regs::RegisterWrapper::new(),
|
||||
regs: regs::RegisterBlock::i2c(),
|
||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown()
|
||||
};
|
||||
|
||||
// Setup GPIO output mask
|
||||
self_.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.mask(GPIO_OUTPUT_MASK)
|
||||
w.mask(gpio_output_mask)
|
||||
});
|
||||
// Setup GPIO driver direction
|
||||
self_.regs.gpio_direction.modify(|_, w| {
|
||||
|
@ -1,5 +1,3 @@
|
||||
use volatile_register::{RO, WO, RW};
|
||||
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits
|
||||
@ -23,15 +21,15 @@ use libregister::{
|
||||
// Current compatibility:
|
||||
// zc706: GPIO 50, 51 == SCL, SDA
|
||||
|
||||
pub struct RegisterWrapper {
|
||||
pub struct RegisterBlock {
|
||||
pub gpio_output_mask: &'static mut GPIOOutputMask,
|
||||
pub gpio_input: &'static mut GPIOInput,
|
||||
pub gpio_direction: &'static mut GPIODirection,
|
||||
pub gpio_output_enable: &'static mut GPIOOutputEnable,
|
||||
}
|
||||
|
||||
impl RegisterWrapper {
|
||||
pub fn new() -> Self {
|
||||
impl RegisterBlock {
|
||||
pub fn i2c() -> Self {
|
||||
Self {
|
||||
gpio_output_mask: GPIOOutputMask::new(),
|
||||
gpio_input: GPIOInput::new(),
|
||||
|
@ -20,6 +20,7 @@ pub mod flash;
|
||||
pub mod time;
|
||||
pub mod timer;
|
||||
pub mod sdio;
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub mod i2c;
|
||||
pub mod logger;
|
||||
pub mod ps7_init;
|
||||
|
@ -138,7 +138,7 @@ pub struct RegisterBlock {
|
||||
pub icdsgir: ICDSGIR,
|
||||
}
|
||||
|
||||
register_at!(RegisterBlock, 0xF8F00000, new);
|
||||
register_at!(RegisterBlock, 0xF8F00000, mpcore);
|
||||
|
||||
register!(value_register, ValueRegister, RW, u32);
|
||||
register_bits!(value_register, value, u32, 0, 31);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/// ADMA library
|
||||
use core::mem::MaybeUninit;
|
||||
use super::SDIO;
|
||||
use super::Sdio;
|
||||
use libcortex_a9::cache;
|
||||
use libregister::{
|
||||
register, register_bit,
|
||||
@ -32,7 +32,7 @@ impl Adma2DescTable {
|
||||
}
|
||||
|
||||
/// Initialize the table and setup `adma_system_address`
|
||||
pub fn setup(&mut self, sdio: &mut SDIO, blk_cnt: u32, buffer: &[u8]) {
|
||||
pub fn setup(&mut self, sdio: &mut Sdio, blk_cnt: u32, buffer: &[u8]) {
|
||||
let descr_table = &mut self.0;
|
||||
let blk_size = sdio
|
||||
.regs
|
||||
|
@ -12,7 +12,7 @@ use log::{trace, debug};
|
||||
use nb;
|
||||
|
||||
/// Basic SDIO Struct with common low-level functions.
|
||||
pub struct SDIO {
|
||||
pub struct Sdio {
|
||||
regs: &'static mut regs::RegisterBlock,
|
||||
count_down: super::timer::global::CountDown<Milliseconds>,
|
||||
input_clk_hz: u32,
|
||||
@ -48,7 +48,7 @@ pub enum CardType {
|
||||
CardMmc,
|
||||
}
|
||||
|
||||
impl SDIO {
|
||||
impl Sdio {
|
||||
/// Initialize SDIO0
|
||||
/// card_detect means if we would use the card detect pin,
|
||||
/// false to disable card detection (assume there is card inserted)
|
||||
@ -121,7 +121,7 @@ impl SDIO {
|
||||
slcr.sdio_clk_ctrl.enable_sdio0();
|
||||
});
|
||||
let clocks = Clocks::get();
|
||||
let mut self_ = SDIO {
|
||||
let mut self_ = Sdio {
|
||||
regs: regs::RegisterBlock::sdio0(),
|
||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
||||
input_clk_hz: clocks.sdio_ref_clk(),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::{adma::Adma2DescTable, cmd, CardType, CmdTransferError, SDIO};
|
||||
use super::{adma::Adma2DescTable, cmd, CardType, CmdTransferError, Sdio};
|
||||
use libcortex_a9::cache;
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||
use log::{trace, debug};
|
||||
@ -37,7 +37,7 @@ enum CardVersion {
|
||||
}
|
||||
|
||||
pub struct SdCard {
|
||||
sdio: SDIO,
|
||||
sdio: Sdio,
|
||||
adma2_desc_table: Adma2DescTable,
|
||||
card_version: CardVersion,
|
||||
hcs: bool,
|
||||
@ -171,8 +171,8 @@ impl SdCard {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Convert SDIO into SdCard struct, error if no card inserted or it is not an SD card.
|
||||
pub fn from_sdio(mut sdio: SDIO) -> Result<Self, CardInitializationError> {
|
||||
/// Convert Sdio into SdCard struct, error if no card inserted or it is not an SD card.
|
||||
pub fn from_sdio(mut sdio: Sdio) -> Result<Self, CardInitializationError> {
|
||||
match sdio.identify_card()? {
|
||||
CardType::CardSd => (),
|
||||
_ => return Err(CardInitializationError::NoCardInserted),
|
||||
@ -192,8 +192,8 @@ impl SdCard {
|
||||
Ok(_self)
|
||||
}
|
||||
|
||||
/// Convert SdCard struct back to SDIO struct.
|
||||
pub fn to_sdio(self) -> SDIO {
|
||||
/// Convert SdCard struct back to Sdio struct.
|
||||
pub fn to_sdio(self) -> Sdio {
|
||||
self.sdio
|
||||
}
|
||||
|
||||
|
@ -253,12 +253,12 @@ pub struct RegisterBlock {
|
||||
pub ddriob_dci_ctrl: DdriobDciCtrl,
|
||||
pub ddriob_dci_status: DdriobDciStatus,
|
||||
}
|
||||
register_at!(RegisterBlock, 0xF8000000, new);
|
||||
register_at!(RegisterBlock, 0xF8000000, slcr);
|
||||
|
||||
impl RegisterBlock {
|
||||
/// Required to modify any sclr register
|
||||
pub fn unlocked<F: FnMut(&mut Self) -> R, R>(mut f: F) -> R {
|
||||
let mut self_ = Self::new();
|
||||
let mut self_ = Self::slcr();
|
||||
self_.slcr_unlock.unlock();
|
||||
let r = f(&mut self_);
|
||||
self_.slcr_lock.lock();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
||||
use libcortex_a9::{asm, mutex::{Mutex, MutexGuard}};
|
||||
use crate::uart::Uart;
|
||||
|
||||
const UART_RATE: u32 = 115_200;
|
||||
@ -10,7 +10,15 @@ pub fn get_uart<'a>() -> MutexGuard<'a, LazyUart> {
|
||||
unsafe { UART.lock() }
|
||||
}
|
||||
|
||||
/// Deinitialize so that the Uart will be reinitialized on next
|
||||
/// output.
|
||||
///
|
||||
/// Delays so that an outstanding transmission can finish.
|
||||
pub fn drop_uart() {
|
||||
for _ in 0..1_000_000 {
|
||||
asm::nop();
|
||||
}
|
||||
|
||||
unsafe { UART = Mutex::new(LazyUart::Uninitialized); }
|
||||
}
|
||||
|
||||
@ -37,7 +45,10 @@ impl DerefMut for LazyUart {
|
||||
fn deref_mut(&mut self) -> &mut Uart {
|
||||
match self {
|
||||
LazyUart::Uninitialized => {
|
||||
let uart = Uart::serial(UART_RATE);
|
||||
#[cfg(feature = "target_cora_z7_10")]
|
||||
let uart = Uart::uart0(UART_RATE);
|
||||
#[cfg(feature = "target_zc706")]
|
||||
let uart = Uart::uart1(UART_RATE);
|
||||
*self = LazyUart::Initialized(uart);
|
||||
self
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ pub struct GlobalTimer {
|
||||
impl GlobalTimer {
|
||||
/// Get the potentially uninitialized timer
|
||||
pub unsafe fn get() -> GlobalTimer {
|
||||
let regs = mpcore::RegisterBlock::new();
|
||||
let regs = mpcore::RegisterBlock::mpcore();
|
||||
GlobalTimer { regs }
|
||||
}
|
||||
|
||||
/// Get the timer with a reset
|
||||
pub fn start() -> GlobalTimer {
|
||||
let mut regs = mpcore::RegisterBlock::new();
|
||||
let mut regs = mpcore::RegisterBlock::mpcore();
|
||||
Self::reset(&mut regs);
|
||||
GlobalTimer { regs }
|
||||
}
|
||||
|
@ -13,31 +13,8 @@ pub struct Uart {
|
||||
}
|
||||
|
||||
impl Uart {
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub fn serial(baudrate: u32) -> Self {
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
// Route UART 1 RxD/TxD Signals to MIO Pins
|
||||
// TX pin
|
||||
slcr.mio_pin_48.write(
|
||||
slcr::MioPin48::zeroed()
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
);
|
||||
// RX pin
|
||||
slcr.mio_pin_49.write(
|
||||
slcr::MioPin49::zeroed()
|
||||
.tri_enable(true)
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
);
|
||||
});
|
||||
Self::uart1(baudrate)
|
||||
}
|
||||
|
||||
#[cfg(feature = "target_cora_z7_10")]
|
||||
pub fn serial(baudrate: u32) -> Self {
|
||||
pub fn uart0(baudrate: u32) -> Self {
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
// Route UART 0 RxD/TxD Signals to MIO Pins
|
||||
// TX pin
|
||||
@ -56,10 +33,7 @@ impl Uart {
|
||||
.pullup(true)
|
||||
);
|
||||
});
|
||||
Self::uart0(baudrate)
|
||||
}
|
||||
|
||||
pub fn uart0(baudrate: u32) -> Self {
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.uart_rst_ctrl.reset_uart0();
|
||||
slcr.aper_clk_ctrl.enable_uart0();
|
||||
@ -72,7 +46,27 @@ impl Uart {
|
||||
self_
|
||||
}
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
pub fn uart1(baudrate: u32) -> Self {
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
// Route UART 1 RxD/TxD Signals to MIO Pins
|
||||
// TX pin
|
||||
slcr.mio_pin_48.write(
|
||||
slcr::MioPin48::zeroed()
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
);
|
||||
// RX pin
|
||||
slcr.mio_pin_49.write(
|
||||
slcr::MioPin49::zeroed()
|
||||
.tri_enable(true)
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
);
|
||||
});
|
||||
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.uart_rst_ctrl.reset_uart1();
|
||||
slcr.aper_clk_ctrl.enable_uart1();
|
||||
|
@ -12,4 +12,5 @@ default = ["target_zc706"]
|
||||
|
||||
[dependencies]
|
||||
bit_field = "0.10"
|
||||
volatile-register = "0.2"
|
||||
libregister = { path = "../libregister" }
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::asm::{dmb, dsb};
|
||||
use super::l2c::*;
|
||||
|
||||
/// Invalidate TLBs
|
||||
#[inline(always)]
|
||||
@ -52,10 +53,9 @@ pub fn dccisw(setway: u32) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
||||
#[inline(always)]
|
||||
pub fn dciall() {
|
||||
pub fn dciall_l1() {
|
||||
// the cache associativity could be read from a register, but will
|
||||
// always be 4 in L1 data cache of a cortex a9
|
||||
let ways = 4;
|
||||
@ -80,9 +80,17 @@ pub fn dciall() {
|
||||
}
|
||||
}
|
||||
|
||||
/// A made-up "instruction": invalidate all of the L1 L2 D-Cache
|
||||
#[inline(always)]
|
||||
pub fn dciall() {
|
||||
dmb();
|
||||
l2_cache_invalidate_all();
|
||||
dciall_l1();
|
||||
}
|
||||
|
||||
/// A made-up "instruction": flush and invalidate all of the L1 D-Cache
|
||||
#[inline(always)]
|
||||
pub fn dcciall() {
|
||||
pub fn dcciall_l1() {
|
||||
// the cache associativity could be read from a register, but will
|
||||
// always be 4 in L1 data cache of a cortex a9
|
||||
let ways = 4;
|
||||
@ -107,6 +115,15 @@ pub fn dcciall() {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn dcciall() {
|
||||
dmb();
|
||||
dcciall_l1();
|
||||
dsb();
|
||||
l2_cache_clean_invalidate_all();
|
||||
dcciall_l1();
|
||||
dsb();
|
||||
}
|
||||
|
||||
const CACHE_LINE: usize = 0x20;
|
||||
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
||||
@ -145,7 +162,16 @@ pub fn dccimvac(addr: usize) {
|
||||
|
||||
/// Data cache clean and invalidate for an object.
|
||||
pub fn dcci<T>(object: &T) {
|
||||
// ref: L2C310 TRM 3.3.10
|
||||
dmb();
|
||||
for addr in object_cache_line_addrs(object) {
|
||||
dccmvac(addr);
|
||||
}
|
||||
dsb();
|
||||
for addr in object_cache_line_addrs(object) {
|
||||
l2_cache_clean_invalidate(addr);
|
||||
}
|
||||
l2_cache_sync();
|
||||
for addr in object_cache_line_addrs(object) {
|
||||
dccimvac(addr);
|
||||
}
|
||||
@ -154,6 +180,14 @@ pub fn dcci<T>(object: &T) {
|
||||
|
||||
pub fn dcci_slice<T>(slice: &[T]) {
|
||||
dmb();
|
||||
for addr in slice_cache_line_addrs(slice) {
|
||||
dccmvac(addr);
|
||||
}
|
||||
dsb();
|
||||
for addr in slice_cache_line_addrs(slice) {
|
||||
l2_cache_clean_invalidate(addr);
|
||||
}
|
||||
l2_cache_sync();
|
||||
for addr in slice_cache_line_addrs(slice) {
|
||||
dccimvac(addr);
|
||||
}
|
||||
@ -175,17 +209,28 @@ pub fn dcc<T>(object: &T) {
|
||||
dccmvac(addr);
|
||||
}
|
||||
dsb();
|
||||
for addr in object_cache_line_addrs(object) {
|
||||
l2_cache_clean(addr);
|
||||
}
|
||||
l2_cache_sync();
|
||||
}
|
||||
|
||||
/// Data cache clean for an object. Panics if not properly
|
||||
/// aligned and properly sized to be contained in an exact number of
|
||||
/// cache lines.
|
||||
pub fn dcc_slice<T>(slice: &[T]) {
|
||||
if slice.len() == 0 {
|
||||
return;
|
||||
}
|
||||
dmb();
|
||||
for addr in slice_cache_line_addrs(slice) {
|
||||
dccmvac(addr);
|
||||
}
|
||||
dsb();
|
||||
for addr in slice_cache_line_addrs(slice) {
|
||||
l2_cache_clean(addr);
|
||||
}
|
||||
l2_cache_sync();
|
||||
}
|
||||
|
||||
/// Data cache invalidate by memory virtual address. This and
|
||||
@ -205,6 +250,10 @@ pub unsafe fn dci<T>(object: &mut T) {
|
||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci object beyond_addr must be aligned");
|
||||
|
||||
dmb();
|
||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||
l2_cache_invalidate(addr);
|
||||
}
|
||||
l2_cache_sync();
|
||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||
dcimvac(addr);
|
||||
}
|
||||
@ -219,6 +268,10 @@ pub unsafe fn dci_slice<T>(slice: &mut [T]) {
|
||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci slice beyond_addr must be aligned");
|
||||
|
||||
dmb();
|
||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||
l2_cache_invalidate(addr);
|
||||
}
|
||||
l2_cache_sync();
|
||||
for addr in (first_addr..beyond_addr).step_by(CACHE_LINE) {
|
||||
dcimvac(addr);
|
||||
}
|
||||
|
313
libcortex_a9/src/l2c.rs
Normal file
313
libcortex_a9/src/l2c.rs
Normal file
@ -0,0 +1,313 @@
|
||||
use libregister::{register, register_at, register_bit, register_bits, RegisterRW, RegisterR, RegisterW};
|
||||
use super::asm::dmb;
|
||||
use volatile_register::RW;
|
||||
|
||||
pub fn enable_l2_cache() {
|
||||
dmb();
|
||||
let regs = RegisterBlock::new();
|
||||
// disable L2 cache
|
||||
regs.reg1_control.modify(|_, w| w.l2_enable(false));
|
||||
|
||||
regs.reg1_aux_control.modify(|_, w| {
|
||||
w.early_bresp_en(true)
|
||||
.instr_prefetch_en(true)
|
||||
.data_prefetch_en(true)
|
||||
.cache_replace_policy(true)
|
||||
.way_size(3)
|
||||
});
|
||||
regs.reg1_tag_ram_control.modify(|_, w| w.ram_wr_access_lat(1).ram_rd_access_lat(1).ram_setup_lat(1));
|
||||
regs.reg1_data_ram_control.modify(|_, w| w.ram_wr_access_lat(1).ram_rd_access_lat(2).ram_setup_lat(1));
|
||||
// invalidate L2 ways
|
||||
unsafe {
|
||||
regs.reg7_inv_way.write(0xFFFF);
|
||||
}
|
||||
// poll for completion
|
||||
while regs.reg7_cache_sync.read().c() {}
|
||||
// write to a magic memory location with a magic sequence
|
||||
// required in UG585 Section 3.4.10 Initialization Sequence
|
||||
unsafe {
|
||||
core::ptr::write_volatile(0xF8000008usize as *mut u32, 0xDF0D);
|
||||
core::ptr::write_volatile(0xF8000A1Cusize as *mut u32, 0x020202);
|
||||
core::ptr::write_volatile(0xF8000004usize as *mut u32, 0x767B);
|
||||
}
|
||||
regs.reg1_control.modify(|_, w| w.l2_enable(true));
|
||||
dmb();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_invalidate_all() {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_inv_way.write(0xFFFF);
|
||||
}
|
||||
// poll for completion
|
||||
while regs.reg7_cache_sync.read().c() {}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_clean_all() {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_clean_way.write(0xFFFF);
|
||||
}
|
||||
// poll for completion
|
||||
while regs.reg7_cache_sync.read().c() {}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_clean_invalidate_all() {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_clean_inv_way.write(0xFFFF);
|
||||
}
|
||||
// poll for completion
|
||||
while regs.reg7_cache_sync.read().c() {}
|
||||
}
|
||||
|
||||
/// L2 cache sync, similar to dsb for L1 cache
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_sync() {
|
||||
let regs = RegisterBlock::new();
|
||||
regs.reg7_cache_sync.write(Reg7CacheSync::zeroed().c(false));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_clean(addr: usize) {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_clean_pa.write(addr as u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_invalidate(addr: usize) {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_inv_pa.write(addr as u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_clean_invalidate(addr: usize) {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_clean_inv_pa.write(addr as u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct RegisterBlock {
|
||||
/// cache ID register, Returns the 32-bit device ID code it reads off the CACHEID input bus.
|
||||
/// The value is specified by the system integrator. Reset value: 0x410000c8
|
||||
pub reg0_cache_id: Reg0CacheId,
|
||||
/// cache type register, Returns the 32-bit cache type. Reset value: 0x1c100100
|
||||
pub reg0_cache_type: Reg0CacheType,
|
||||
unused0: [u32; 62],
|
||||
/// control register, reset value: 0x0
|
||||
pub reg1_control: Reg1Control,
|
||||
/// auxilary control register, reset value: 0x02020000
|
||||
pub reg1_aux_control: Reg1AuxControl,
|
||||
/// Configures Tag RAM latencies
|
||||
pub reg1_tag_ram_control: Reg1TagRamControl,
|
||||
/// configures data RAM latencies
|
||||
pub reg1_data_ram_control: Reg1DataRamControl,
|
||||
unused1: [u32; 60],
|
||||
/// Permits the event counters to be enabled and reset.
|
||||
pub reg2_ev_counter_ctrl: Reg2EvCounterCtrl,
|
||||
/// Enables event counter 1 to be driven by a specific event. Counter 1 increments when the
|
||||
/// event occurs.
|
||||
pub reg2_ev_counter1_cfg: Reg2EvCounter1Cfg,
|
||||
/// Enables event counter 0 to be driven by a specific event. Counter 0 increments when the
|
||||
/// event occurs.
|
||||
pub reg2_ev_counter0_cfg: Reg2EvCounter0Cfg,
|
||||
/// Enable the programmer to read off the counter value. The counter counts an event as
|
||||
/// specified by the Counter Configuration Registers. The counter can be preloaded if counting
|
||||
/// is disabled and reset by the Event Counter Control Register.
|
||||
pub reg2_ev_counter1: RW<u32>,
|
||||
/// Enable the programmer to read off the counter value. The counter counts an event as
|
||||
/// specified by the Counter Configuration Registers. The counter can be preloaded if counting
|
||||
/// is disabled and reset by the Event Counter Control Register.
|
||||
pub reg2_ev_counter0: RW<u32>,
|
||||
/// This register enables or masks interrupts from being triggered on the external pins of the
|
||||
/// cache controller. Figure 3-8 on page 3-17 shows the register bit assignments. The bit
|
||||
/// assignments enables the masking of the interrupts on both their individual outputs and the
|
||||
/// combined L2CCINTR line. Clearing a bit by writing a 0, disables the interrupt triggering on
|
||||
/// that pin. All bits are cleared by a reset. You must write to the register bits with a 1 to
|
||||
/// enable the generation of interrupts. 1 = Enabled. 0 = Masked. This is the default.
|
||||
pub reg2_int_mask: Reg2IntMask,
|
||||
/// This register is a read-only.It returns the masked interrupt status. This register can be
|
||||
/// accessed by secure and non-secure operations. The register gives an AND function of the raw
|
||||
/// interrupt status with the values of the interrupt mask register. All the bits are cleared
|
||||
/// by a reset. A write to this register is ignored. Bits read can be HIGH or LOW: HIGH If the
|
||||
/// bits read HIGH, they reflect the status of the input lines triggering an interrupt. LOW If
|
||||
/// the bits read LOW, either no interrupt has been generated, or the interrupt is masked.
|
||||
pub reg2_int_mask_status: Reg2IntMaskStatus,
|
||||
/// The Raw Interrupt Status Register enables the interrupt status that excludes the masking
|
||||
/// logic. Bits read can be HIGH or LOW: HIGH If the bits read HIGH, they reflect the status of
|
||||
/// the input lines triggering an interrupt. LOW If the bits read LOW, no interrupt has been
|
||||
/// generated.
|
||||
pub reg2_int_raw_status: Reg2IntRawStatus,
|
||||
/// Clears the Raw Interrupt Status Register bits. When a bit is written as 1, it clears the
|
||||
/// corresponding bit in the Raw Interrupt Status Register. When a bit is written as 0, it has
|
||||
/// no effect
|
||||
pub reg2_int_clear: Reg2IntClear,
|
||||
unused2: [u32; 323],
|
||||
/// Drain the STB. Operation complete when all buffers, LRB, LFB, STB, and EB, are empty
|
||||
pub reg7_cache_sync: Reg7CacheSync,
|
||||
unused3: [u32; 15],
|
||||
/// Invalidate Line by PA: Specific L2 cache line is marked as not valid
|
||||
pub reg7_inv_pa: RW<u32>,
|
||||
unused4: [u32; 2],
|
||||
/// Invalidate by Way Invalidate all data in specified ways, including dirty data. An
|
||||
/// Invalidate by way while selecting all cache ways is equivalent to invalidating all cache
|
||||
/// entries. Completes as a background task with the way, or ways, locked, preventing
|
||||
/// allocation.
|
||||
pub reg7_inv_way: RW<u32>,
|
||||
unused5: [u32; 12],
|
||||
/// Clean Line by PA Write the specific L2 cache line to L3 main memory if the line is marked
|
||||
/// as valid and dirty. The line is marked as not dirty. The valid bit is unchanged
|
||||
pub reg7_clean_pa: RW<u32>,
|
||||
unused6: [u32; 1],
|
||||
/// Clean Line by Set/Way Write the specific L2 cache line within the specified way to L3 main
|
||||
/// memory if the line is marked as valid and dirty. The line is marked as not dirty. The valid
|
||||
/// bit is unchanged
|
||||
pub reg7_clean_index: Reg7CleanIndex,
|
||||
/// Clean by Way Writes each line of the specified L2 cache ways to L3 main memory if the line
|
||||
/// is marked as valid and dirty. The lines are marked as not dirty. The valid bits are
|
||||
/// unchanged. Completes as a background task with the way, or ways, locked, preventing
|
||||
/// allocation.
|
||||
pub reg7_clean_way: RW<u32>,
|
||||
unused7: [u32; 12],
|
||||
/// Clean and Invalidate Line by PA Write the specific L2 cache line to L3 main memory if the
|
||||
/// line is marked as valid and dirty. The line is marked as not valid
|
||||
pub reg7_clean_inv_pa: RW<u32>,
|
||||
unused8: [u32; 1],
|
||||
/// Clean and Invalidate Line by Set/Way Write the specific L2 cache line within the specified
|
||||
/// way to L3 main memory if the line is marked as valid and dirty. The line is marked as not
|
||||
/// valid
|
||||
pub reg7_clean_inv_index: Reg7CleanInvIndex,
|
||||
/// Clean and Invalidate by Way Writes each line of the specified L2 cache ways to L3 main
|
||||
/// memory if the line is marked as valid and dirty. The lines are marked as not valid.
|
||||
/// Completes as a background task with the way, or ways, locked, preventing allocation.
|
||||
pub reg7_clean_inv_way: RW<u32>,
|
||||
}
|
||||
|
||||
register_at!(RegisterBlock, 0xF8F02000, new);
|
||||
|
||||
register!(reg0_cache_id, Reg0CacheId, RW, u32);
|
||||
register_bits!(reg0_cache_id, implementer, u8, 24, 31);
|
||||
register_bits!(reg0_cache_id, cache_id, u8, 10, 15);
|
||||
register_bits!(reg0_cache_id, part_num, u8, 6, 9);
|
||||
register_bits!(reg0_cache_id, rtl_release, u8, 0, 5);
|
||||
|
||||
register!(reg0_cache_type, Reg0CacheType, RW, u32);
|
||||
register_bit!(reg0_cache_type, data_banking, 31);
|
||||
register_bits!(reg0_cache_type, ctype, u8, 25, 28);
|
||||
register_bit!(reg0_cache_type, h, 24);
|
||||
register_bits!(reg0_cache_type, dsize_middsize_19, u8, 20, 22);
|
||||
register_bit!(reg0_cache_type, l2_assoc_d, 18);
|
||||
register_bits!(reg0_cache_type, l2cache_line_len_disize_11, u8, 12, 13);
|
||||
register_bits!(reg0_cache_type, isize_midisize_7, u8, 8, 10);
|
||||
register_bit!(reg0_cache_type, l2_assoc_i, 6);
|
||||
register_bits!(reg0_cache_type, l2cache_line_len_i, u8, 0, 1);
|
||||
|
||||
register!(reg1_control, Reg1Control, RW, u32);
|
||||
register_bit!(reg1_control, l2_enable, 0);
|
||||
|
||||
register!(reg1_aux_control, Reg1AuxControl, RW, u32);
|
||||
register_bit!(reg1_aux_control, early_bresp_en, 30);
|
||||
register_bit!(reg1_aux_control, instr_prefetch_en, 29);
|
||||
register_bit!(reg1_aux_control, data_prefetch_en, 28);
|
||||
register_bit!(reg1_aux_control, nonsec_inte_access_ctrl, 27);
|
||||
register_bit!(reg1_aux_control, nonsec_lockdown_en, 26);
|
||||
register_bit!(reg1_aux_control, cache_replace_policy, 25);
|
||||
register_bits!(reg1_aux_control, force_write_alloc, u8, 23, 24);
|
||||
register_bit!(reg1_aux_control, shared_attr_override_en, 22);
|
||||
register_bit!(reg1_aux_control, parity_en, 21);
|
||||
register_bit!(reg1_aux_control, event_mon_bus_en, 20);
|
||||
register_bits!(reg1_aux_control, way_size, u8, 17, 19);
|
||||
register_bit!(reg1_aux_control, associativity, 16);
|
||||
register_bit!(reg1_aux_control, shared_attr_inva_en, 13);
|
||||
register_bit!(reg1_aux_control, ex_cache_config, 12);
|
||||
register_bit!(reg1_aux_control, store_buff_dev_lim_en, 11);
|
||||
register_bit!(reg1_aux_control, high_pr_so_dev_rd_en, 10);
|
||||
register_bit!(reg1_aux_control, full_line_zero_enable, 0);
|
||||
|
||||
register!(reg1_tag_ram_control, Reg1TagRamControl, RW, u32);
|
||||
register_bits!(reg1_tag_ram_control, ram_wr_access_lat, u8, 8, 10);
|
||||
register_bits!(reg1_tag_ram_control, ram_rd_access_lat, u8, 4, 6);
|
||||
register_bits!(reg1_tag_ram_control, ram_setup_lat, u8, 0, 2);
|
||||
|
||||
register!(reg1_data_ram_control, Reg1DataRamControl, RW, u32);
|
||||
register_bits!(reg1_data_ram_control, ram_wr_access_lat, u8, 8, 10);
|
||||
register_bits!(reg1_data_ram_control, ram_rd_access_lat, u8, 4, 6);
|
||||
register_bits!(reg1_data_ram_control, ram_setup_lat, u8, 0, 2);
|
||||
|
||||
register!(reg2_ev_counter_ctrl, Reg2EvCounterCtrl, RW, u32);
|
||||
register_bit!(reg2_ev_counter_ctrl, ev_ctr_en, 0);
|
||||
|
||||
register!(reg2_ev_counter1_cfg, Reg2EvCounter1Cfg, RW, u32);
|
||||
register_bits!(reg2_ev_counter1_cfg, ctr_ev_src, u8, 2, 5);
|
||||
register_bits!(reg2_ev_counter1_cfg, ev_ctr_intr_gen, u8, 0, 1);
|
||||
|
||||
register!(reg2_ev_counter0_cfg, Reg2EvCounter0Cfg, RW, u32);
|
||||
register_bits!(reg2_ev_counter0_cfg, ctr_ev_src, u8, 2, 5);
|
||||
register_bits!(reg2_ev_counter0_cfg, ev_ctr_intr_gen, u8, 0, 1);
|
||||
|
||||
register!(reg2_int_mask, Reg2IntMask, RW, u32);
|
||||
register_bit!(reg2_int_mask, decerr, 8);
|
||||
register_bit!(reg2_int_mask, slverr, 7);
|
||||
register_bit!(reg2_int_mask, errrd, 6);
|
||||
register_bit!(reg2_int_mask, errrt, 5);
|
||||
register_bit!(reg2_int_mask, errwd, 4);
|
||||
register_bit!(reg2_int_mask, errwt, 3);
|
||||
register_bit!(reg2_int_mask, parrd, 2);
|
||||
register_bit!(reg2_int_mask, parrt, 1);
|
||||
register_bit!(reg2_int_mask, ecntr, 0);
|
||||
|
||||
register!(reg2_int_mask_status, Reg2IntMaskStatus, RW, u32);
|
||||
register_bit!(reg2_int_mask_status, decerr, 8);
|
||||
register_bit!(reg2_int_mask_status, slverr, 7);
|
||||
register_bit!(reg2_int_mask_status, errrd, 6);
|
||||
register_bit!(reg2_int_mask_status, errrt, 5);
|
||||
register_bit!(reg2_int_mask_status, errwd, 4);
|
||||
register_bit!(reg2_int_mask_status, errwt, 3);
|
||||
register_bit!(reg2_int_mask_status, parrd, 2);
|
||||
register_bit!(reg2_int_mask_status, parrt, 1);
|
||||
register_bit!(reg2_int_mask_status, ecntr, 0);
|
||||
|
||||
register!(reg2_int_raw_status, Reg2IntRawStatus, RW, u32);
|
||||
register_bit!(reg2_int_raw_status, decerr, 8);
|
||||
register_bit!(reg2_int_raw_status, slverr, 7);
|
||||
register_bit!(reg2_int_raw_status, errrd, 6);
|
||||
register_bit!(reg2_int_raw_status, errrt, 5);
|
||||
register_bit!(reg2_int_raw_status, errwd, 4);
|
||||
register_bit!(reg2_int_raw_status, errwt, 3);
|
||||
register_bit!(reg2_int_raw_status, parrd, 2);
|
||||
register_bit!(reg2_int_raw_status, parrt, 1);
|
||||
register_bit!(reg2_int_raw_status, ecntr, 0);
|
||||
|
||||
register!(reg2_int_clear, Reg2IntClear, RW, u32, 0);
|
||||
register_bit!(reg2_int_clear, decerr, 8, WTC);
|
||||
register_bit!(reg2_int_clear, slverr, 7, WTC);
|
||||
register_bit!(reg2_int_clear, errrd, 6, WTC);
|
||||
register_bit!(reg2_int_clear, errrt, 5, WTC);
|
||||
register_bit!(reg2_int_clear, errwd, 4, WTC);
|
||||
register_bit!(reg2_int_clear, errwt, 3, WTC);
|
||||
register_bit!(reg2_int_clear, parrd, 2, WTC);
|
||||
register_bit!(reg2_int_clear, parrt, 1, WTC);
|
||||
register_bit!(reg2_int_clear, ecntr, 0, WTC);
|
||||
|
||||
register!(reg7_cache_sync, Reg7CacheSync, RW, u32);
|
||||
register_bit!(reg7_cache_sync, c, 0);
|
||||
|
||||
register!(reg7_clean_index, Reg7CleanIndex, RW, u32);
|
||||
register_bits!(reg7_clean_index, way, u8, 28, 30);
|
||||
register_bits!(reg7_clean_index, index, u8, 5, 11);
|
||||
register_bit!(reg7_clean_index, c, 0);
|
||||
|
||||
register!(reg7_clean_inv_index, Reg7CleanInvIndex, RW, u32);
|
||||
register_bits!(reg7_clean_inv_index, way, u8, 28, 30);
|
||||
register_bits!(reg7_clean_inv_index, index, u8, 5, 11);
|
||||
register_bit!(reg7_clean_inv_index, c, 0);
|
||||
|
@ -12,6 +12,7 @@ pub mod mmu;
|
||||
pub mod mutex;
|
||||
pub mod sync_channel;
|
||||
pub mod semaphore;
|
||||
pub mod l2c;
|
||||
mod uncached;
|
||||
mod fpu;
|
||||
pub use uncached::UncachedSlice;
|
||||
|
@ -23,10 +23,11 @@ impl<T> UncachedSlice<T> {
|
||||
assert_eq!(start & (L1_PAGE_SIZE - 1), 0);
|
||||
|
||||
for page_start in (start..(start + size)).step_by(L1_PAGE_SIZE) {
|
||||
// non-shareable device
|
||||
L1Table::get()
|
||||
.update(page_start as *const (), |l1_section| {
|
||||
l1_section.tex = 0b100;
|
||||
l1_section.cacheable = false;
|
||||
l1_section.tex = 0b10;
|
||||
l1_section.cacheable = true;
|
||||
l1_section.bufferable = false;
|
||||
});
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use libregister::{
|
||||
VolatileCell,
|
||||
RegisterR, RegisterW, RegisterRW,
|
||||
};
|
||||
use libcortex_a9::{asm, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock};
|
||||
use libcortex_a9::{asm, l2c, regs::*, cache, mmu, spin_lock_yield, notify_spin_lock};
|
||||
use libboard_zynq::{slcr, mpcore};
|
||||
|
||||
extern "C" {
|
||||
@ -43,7 +43,7 @@ pub unsafe extern "C" fn Reset() -> ! {
|
||||
unsafe fn boot_core0() -> ! {
|
||||
l1_cache_init();
|
||||
|
||||
let mpcore = mpcore::RegisterBlock::new();
|
||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||
mpcore.scu_invalidate.invalidate_all_cores();
|
||||
|
||||
zero_bss(&mut __bss_start, &mut __bss_end);
|
||||
@ -68,7 +68,7 @@ unsafe fn boot_core0() -> ! {
|
||||
unsafe fn boot_core1() -> ! {
|
||||
l1_cache_init();
|
||||
|
||||
let mpcore = mpcore::RegisterBlock::new();
|
||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||
mpcore.scu_invalidate.invalidate_core1();
|
||||
|
||||
let mmu_table = mmu::L1Table::get();
|
||||
@ -101,7 +101,7 @@ fn l1_cache_init() {
|
||||
// for all of the L1 data cache rather than a (previously
|
||||
// unspecified) combination of one cache set and one cache
|
||||
// way.
|
||||
dciall();
|
||||
dciall_l1();
|
||||
}
|
||||
|
||||
pub struct Core1 {
|
||||
@ -131,12 +131,13 @@ impl Core1 {
|
||||
unsafe {
|
||||
CORE1_ENABLED.set(true);
|
||||
}
|
||||
// Ensure values have been written to cache
|
||||
asm::dmb();
|
||||
// Flush cache-line
|
||||
cache::dccmvac(unsafe { &CORE1_ENABLED } as *const _ as usize);
|
||||
cache::dcc(unsafe { &CORE1_ENABLED });
|
||||
if sdram {
|
||||
cache::dccmvac(0);
|
||||
asm::dsb();
|
||||
l2c::l2_cache_clean(0);
|
||||
l2c::l2_cache_sync();
|
||||
}
|
||||
|
||||
// wake up core1
|
||||
|
Loading…
Reference in New Issue
Block a user