Compare commits

...

15 Commits

Author SHA1 Message Date
bb09d25378 libboard_zynq/ethernet: ethernet fix and config 2020-08-21 13:34:02 +08:00
a1f859637a experiments: enabled L2 cache
...and removed some trailing spaces
2020-08-20 13:02:28 +08:00
7cb2669c3b Updated cargo dependencies 2020-08-20 13:01:49 +08:00
511c906d4d libcortex_a9/uncached: fixed mmu setting 2020-08-20 13:01:49 +08:00
1ba0aa450f libsupport_zynq/boot: fix cache mainteinance opertaions 2020-08-20 13:01:49 +08:00
283bc9b810 libcortex_a9: added L2 cache 2020-08-20 13:01:17 +08:00
b268fe015a stdio::drop_uart(): add delay 2020-08-17 19:38:41 +02:00
64db9b0142 Merge pull request 'libboard_zynq: dead code, peripheral & regblock ctor names consistency' (#63) from harry/zynq-rs:cleanup into master 2020-08-17 23:38:22 +08:00
4b258c19f5 libasync: improve scheduling fairness between block_on and spawned tasks
in the libasync::smoltcp::Sockets::run() case the block_on iface.poll
loop would progress just one task before. now all tasks get to run in
each iteration.
2020-08-17 00:58:12 +02:00
1a96a7550a libboard_zynq: make RegisterBlock constructors more consistent 2020-08-13 14:49:26 +08:00
36947104e3 libboard_zynq: make constructor names more consistent 2020-08-13 13:31:53 +08:00
11089d8a64 i2c: delete dead code 2020-08-12 16:51:25 +08:00
c69cd9951e Update README and build.sh (#59)
update build.sh to use rpi-4 directly; fix README

README: update build instruction

build.sh: fix missing package argument

Co-authored-by: Harry Ho <hh@m-labs.hk>
2020-08-11 11:24:21 +08:00
76a4cac873 i2c: disable its usage on Cora Z7-10 2020-08-10 14:24:13 +08:00
4614ed1371 i2c: simplify ctor_common() 2020-08-08 10:06:11 +08:00
34 changed files with 579 additions and 205 deletions

7
Cargo.lock generated
View File

@ -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"

View File

@ -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
```

View File

@ -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

View File

@ -49,7 +49,7 @@ let
name = "${crate}";
src = ./.;
crateSubdir = crate;
cargoSha256 = "1c1qpg9by8bg93yhgllb5xs155g27qmh99pbrb681wazm8k7nwim";
cargoSha256 = "1gdxrsn58mabqf8yc3xqkrl1qlmlyvpnzcfj4xafpdr1gdhwhdjg";
cargoFeatures = features;
doCheck = false;
dontFixup = true;

View File

@ -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 };

View File

@ -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);
}
}

View File

@ -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 =>

View File

@ -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
}

View File

@ -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();

View File

@ -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,

View File

@ -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()

View File

@ -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);

View File

@ -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();
}

View File

@ -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();

View File

@ -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,

View File

@ -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 }
}

View File

@ -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,

View File

@ -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| {

View File

@ -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(),

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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(),

View File

@ -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
}

View File

@ -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();

View File

@ -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
}

View File

@ -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 }
}

View File

@ -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();

View File

@ -12,4 +12,5 @@ default = ["target_zc706"]
[dependencies]
bit_field = "0.10"
volatile-register = "0.2"
libregister = { path = "../libregister" }

View File

@ -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
View 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);

View File

@ -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;

View File

@ -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;
});
}

View File

@ -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