forked from M-Labs/zynq-rs
cargo fmt
This commit is contained in:
@@ -1,7 +1,4 @@
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs::File, io::Write, path::PathBuf};
|
||||
|
||||
fn main() {
|
||||
// Put the linker script somewhere the linker can find it
|
||||
|
||||
@@ -6,43 +6,33 @@
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::collections::BTreeMap;
|
||||
use core::arch::naked_asm;
|
||||
use libasync::{
|
||||
delay,
|
||||
smoltcp::{Sockets, TcpStream},
|
||||
task,
|
||||
};
|
||||
use libboard_zynq::{
|
||||
self as zynq,
|
||||
clocks::source::{ArmPll, ClockSource, IoPll},
|
||||
clocks::Clocks,
|
||||
println, stdio,
|
||||
mpcore,
|
||||
gic,
|
||||
smoltcp::{
|
||||
iface::{EthernetInterfaceBuilder, NeighborCache, Routes},
|
||||
time::{Duration, Instant},
|
||||
wire::{EthernetAddress, IpAddress, IpCidr},
|
||||
},
|
||||
time::Milliseconds,
|
||||
};
|
||||
use core::{arch::naked_asm,
|
||||
sync::atomic::{AtomicBool, Ordering}};
|
||||
|
||||
use libasync::{delay,
|
||||
smoltcp::{Sockets, TcpStream},
|
||||
task};
|
||||
#[cfg(feature = "target_zc706")]
|
||||
use libboard_zynq::print;
|
||||
use libcortex_a9::{
|
||||
mutex::Mutex,
|
||||
l2c::enable_l2_cache,
|
||||
sync_channel::{Sender, Receiver},
|
||||
sync_channel,
|
||||
regs::{MPIDR, SP},
|
||||
spin_lock_yield, notify_spin_lock,
|
||||
asm, interrupt_handler
|
||||
};
|
||||
use libboard_zynq::{self as zynq,
|
||||
clocks::{Clocks,
|
||||
source::{ArmPll, ClockSource, IoPll}},
|
||||
gic, mpcore, println,
|
||||
smoltcp::{iface::{EthernetInterfaceBuilder, NeighborCache, Routes},
|
||||
time::{Duration, Instant},
|
||||
wire::{EthernetAddress, IpAddress, IpCidr}},
|
||||
stdio,
|
||||
time::Milliseconds};
|
||||
use libcortex_a9::{asm, interrupt_handler,
|
||||
l2c::enable_l2_cache,
|
||||
mutex::Mutex,
|
||||
notify_spin_lock,
|
||||
regs::{MPIDR, SP},
|
||||
spin_lock_yield, sync_channel,
|
||||
sync_channel::{Receiver, Sender}};
|
||||
use libregister::{RegisterR, RegisterW};
|
||||
use libsupport_zynq::{
|
||||
boot, exception_vectors, ram,
|
||||
};
|
||||
use libsupport_zynq::{boot, exception_vectors, ram};
|
||||
use log::{info, warn};
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
|
||||
|
||||
@@ -59,14 +49,14 @@ interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||
let mpcore = mpcore::RegisterBlock::mpcore();
|
||||
let mut gic = gic::InterruptController::gic(mpcore);
|
||||
let id = gic.get_interrupt_id();
|
||||
match MPIDR.read().cpu_id(){
|
||||
match MPIDR.read().cpu_id() {
|
||||
0 => {
|
||||
if id.0 == 0 {
|
||||
println!("Interrupting core0...");
|
||||
gic.end_interrupt(id);
|
||||
return;
|
||||
}
|
||||
},
|
||||
}
|
||||
1 => {
|
||||
if id.0 == 0 {
|
||||
gic.end_interrupt(id);
|
||||
@@ -77,7 +67,7 @@ interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
|
||||
notify_spin_lock();
|
||||
main_core1();
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
stdio::drop_uart();
|
||||
@@ -108,10 +98,7 @@ pub fn main_core0() {
|
||||
|
||||
info!(
|
||||
"Boot mode: {:?}",
|
||||
zynq::slcr::RegisterBlock::slcr()
|
||||
.boot_mode
|
||||
.read()
|
||||
.boot_mode_pins()
|
||||
zynq::slcr::RegisterBlock::slcr().boot_mode.read().boot_mode_pins()
|
||||
);
|
||||
|
||||
#[cfg(any(
|
||||
@@ -175,9 +162,8 @@ pub fn main_core0() {
|
||||
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,
|
||||
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]).unwrap();
|
||||
eeprom.write(0x08, &eeprom_buffer[6..22]).unwrap();
|
||||
@@ -204,7 +190,7 @@ pub fn main_core0() {
|
||||
let mut err_cdwn = timer.countdown();
|
||||
let mut err_state = true;
|
||||
let mut led = zynq::error_led::ErrorLED::error_led();
|
||||
task::spawn( async move {
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
led.toggle(err_state);
|
||||
err_state = !err_state;
|
||||
@@ -254,7 +240,7 @@ pub fn main_core0() {
|
||||
Ok(_len) => stats_tx.borrow_mut().1 += tx_data.len(), //CHUNK_SIZE,
|
||||
Err(e) => {
|
||||
warn!("tx: {:?}", e);
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -263,7 +249,7 @@ pub fn main_core0() {
|
||||
});
|
||||
let stats_rx = stats.clone();
|
||||
task::spawn(async move {
|
||||
while let Ok(stream) = TcpStream::accept(TCP_PORT+1, 0x10_0000, 0x10_0000).await {
|
||||
while let Ok(stream) = TcpStream::accept(TCP_PORT + 1, 0x10_0000, 0x10_0000).await {
|
||||
let stats_rx = stats_rx.clone();
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
@@ -271,7 +257,7 @@ pub fn main_core0() {
|
||||
Ok(len) => stats_rx.borrow_mut().0 += len,
|
||||
Err(e) => {
|
||||
warn!("rx: {:?}", e);
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,7 +279,13 @@ pub fn main_core0() {
|
||||
*stats = (0, 0);
|
||||
result
|
||||
};
|
||||
info!("time: {:6}.{:06}s, rx: {}k/s, tx: {}k/s", seconds, micros, rx / 1024, tx / 1024);
|
||||
info!(
|
||||
"time: {:6}.{:06}s, rx: {}k/s, tx: {}k/s",
|
||||
seconds,
|
||||
micros,
|
||||
rx / 1024,
|
||||
tx / 1024
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use embedded_hal::timer::CountDown;
|
||||
|
||||
use crate::block_async;
|
||||
|
||||
pub async fn delay<T: CountDown<Time=C>, C>(timer: &mut T, count: C) {
|
||||
pub async fn delay<T: CountDown<Time = C>, C>(timer: &mut T, count: C) {
|
||||
timer.start(count);
|
||||
let _ = block_async!(timer.wait()).await;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use core::{
|
||||
cell::{RefCell, Cell},
|
||||
future::Future,
|
||||
mem::MaybeUninit,
|
||||
pin::{pin, Pin},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
|
||||
};
|
||||
use core::{cell::{Cell, RefCell},
|
||||
future::Future,
|
||||
mem::MaybeUninit,
|
||||
pin::{Pin, pin},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
task::{Context, Poll, RawWaker, RawWakerVTable, Waker}};
|
||||
|
||||
// NOTE `*const ()` is &AtomicBool
|
||||
static VTABLE: RawWakerVTable = {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod task;
|
||||
pub mod executor;
|
||||
mod delay;
|
||||
pub mod executor;
|
||||
pub mod task;
|
||||
pub use delay::delay;
|
||||
|
||||
pub mod smoltcp;
|
||||
@@ -24,13 +24,12 @@ macro_rules! block_async {
|
||||
match $e {
|
||||
Err($crate::nb::Error::Other(e)) => {
|
||||
#[allow(unreachable_code)]
|
||||
break Err(e)
|
||||
},
|
||||
Err($crate::nb::Error::WouldBlock) =>
|
||||
$crate::task::r#yield().await,
|
||||
break Err(e);
|
||||
}
|
||||
Err($crate::nb::Error::WouldBlock) => $crate::task::r#yield().await,
|
||||
Ok(x) => break Ok(x),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
use core::{
|
||||
cell::RefCell,
|
||||
task::Waker,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use smoltcp::{
|
||||
iface::EthernetInterface,
|
||||
phy::Device,
|
||||
socket::SocketSet,
|
||||
time::Instant,
|
||||
};
|
||||
use core::{cell::RefCell, task::Waker};
|
||||
|
||||
use smoltcp::{iface::EthernetInterface, phy::Device, socket::SocketSet, time::Instant};
|
||||
|
||||
mod tcp_stream;
|
||||
pub use tcp_stream::TcpStream;
|
||||
@@ -30,11 +23,10 @@ impl Sockets {
|
||||
|
||||
let wakers = RefCell::new(Vec::new());
|
||||
|
||||
let instance = Sockets {
|
||||
sockets,
|
||||
wakers,
|
||||
};
|
||||
unsafe { SOCKETS = Some(instance); }
|
||||
let instance = Sockets { sockets, wakers };
|
||||
unsafe {
|
||||
SOCKETS = Some(instance);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
@@ -42,11 +34,7 @@ impl Sockets {
|
||||
unsafe { SOCKETS.as_ref().expect("Sockets") }
|
||||
}
|
||||
|
||||
pub fn poll<'b, D: for<'d> Device<'d>>(
|
||||
&self,
|
||||
iface: &mut EthernetInterface<'b, D>,
|
||||
instant: Instant
|
||||
) {
|
||||
pub fn poll<'b, D: for<'d> Device<'d>>(&self, iface: &mut EthernetInterface<'b, D>, instant: Instant) {
|
||||
let processed = {
|
||||
let mut sockets = self.sockets.borrow_mut();
|
||||
match iface.poll(&mut sockets, instant) {
|
||||
|
||||
@@ -2,22 +2,17 @@
|
||||
//!
|
||||
//! TODO: implement futures AsyncRead/AsyncWrite/Stream/Sink interfaces
|
||||
|
||||
use core::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use smoltcp::{
|
||||
Error, Result,
|
||||
socket::{
|
||||
SocketHandle, SocketRef,
|
||||
TcpSocketBuffer, TcpSocket, TcpState,
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
use crate::task;
|
||||
use core::{future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll}};
|
||||
|
||||
use smoltcp::{Error, Result,
|
||||
socket::{SocketHandle, SocketRef, TcpSocket, TcpSocketBuffer, TcpState},
|
||||
time::Duration};
|
||||
|
||||
use super::Sockets;
|
||||
use crate::task;
|
||||
|
||||
/// References a smoltcp TcpSocket
|
||||
pub struct TcpStream {
|
||||
@@ -26,25 +21,27 @@ pub struct TcpStream {
|
||||
|
||||
/// Wait while letting `$f()` poll a stream's socket
|
||||
macro_rules! poll_stream {
|
||||
($stream: expr, $output: ty, $f: expr) => (async {
|
||||
struct Adhoc<'a> {
|
||||
stream: &'a TcpStream,
|
||||
}
|
||||
|
||||
impl<'a> Future for Adhoc<'a> {
|
||||
type Output = $output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let result = self.stream.with_socket($f);
|
||||
if !result.is_ready() {
|
||||
Sockets::register_waker(cx.waker().clone());
|
||||
}
|
||||
result
|
||||
($stream:expr, $output:ty, $f:expr) => {
|
||||
async {
|
||||
struct Adhoc<'a> {
|
||||
stream: &'a TcpStream,
|
||||
}
|
||||
}
|
||||
|
||||
Adhoc { stream: $stream }.await
|
||||
})
|
||||
impl<'a> Future for Adhoc<'a> {
|
||||
type Output = $output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let result = self.stream.with_socket($f);
|
||||
if !result.is_ready() {
|
||||
Sockets::register_waker(cx.waker().clone());
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
Adhoc { stream: $stream }.await
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl TcpStream {
|
||||
@@ -64,16 +61,13 @@ impl TcpStream {
|
||||
let rx_buffer = TcpSocketBuffer::new(uninit_vec(rx_bufsize));
|
||||
let tx_buffer = TcpSocketBuffer::new(uninit_vec(tx_bufsize));
|
||||
let socket = TcpSocket::new(rx_buffer, tx_buffer);
|
||||
let handle = Sockets::instance().sockets.borrow_mut()
|
||||
.add(socket);
|
||||
let handle = Sockets::instance().sockets.borrow_mut().add(socket);
|
||||
TcpStream { handle }
|
||||
}
|
||||
|
||||
/// Operate on the referenced TCP socket
|
||||
fn with_socket<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(SocketRef<TcpSocket>) -> R,
|
||||
{
|
||||
where F: FnOnce(SocketRef<TcpSocket>) -> R {
|
||||
let mut sockets = Sockets::instance().sockets.borrow_mut();
|
||||
let socket_ref = sockets.get::<TcpSocket>(self.handle);
|
||||
f(socket_ref)
|
||||
@@ -96,7 +90,8 @@ impl TcpStream {
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}).await;
|
||||
})
|
||||
.await;
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
@@ -107,9 +102,7 @@ impl TcpStream {
|
||||
/// and it must consume at least one byte. It returns a tuple with the
|
||||
/// number of bytes it consumed, and a user-defined return value of type R.
|
||||
pub async fn recv<F, R>(&self, f: F) -> Result<R>
|
||||
where
|
||||
F: Fn(&[u8]) -> (usize, R),
|
||||
{
|
||||
where F: Fn(&[u8]) -> (usize, R) {
|
||||
struct Recv<'a, F: FnOnce(&[u8]) -> (usize, R), R> {
|
||||
stream: &'a TcpStream,
|
||||
f: F,
|
||||
@@ -139,19 +132,13 @@ impl TcpStream {
|
||||
Sockets::register_waker(cx.waker().clone());
|
||||
Poll::Pending
|
||||
}
|
||||
Ok(result) => {
|
||||
result
|
||||
}
|
||||
Err(e) =>
|
||||
Poll::Ready(Err(e)),
|
||||
Ok(result) => result,
|
||||
Err(e) => Poll::Ready(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Recv {
|
||||
stream: self,
|
||||
f,
|
||||
}.await
|
||||
Recv { stream: self, f }.await
|
||||
}
|
||||
|
||||
/// Wait until there is any space in the socket's send queue
|
||||
@@ -161,12 +148,13 @@ impl TcpStream {
|
||||
Poll::Pending
|
||||
} else if socket.can_send() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else if ! socket.may_send() {
|
||||
} else if !socket.may_send() {
|
||||
Poll::Ready(Err(Error::Truncated))
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
}).await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Yields to wait for more buffer space
|
||||
@@ -183,7 +171,7 @@ impl TcpStream {
|
||||
buf[i] = byte;
|
||||
} else {
|
||||
done = true;
|
||||
return (i, ())
|
||||
return (i, ());
|
||||
}
|
||||
}
|
||||
(buf.len(), ())
|
||||
@@ -228,7 +216,8 @@ impl TcpStream {
|
||||
} else {
|
||||
Poll::Ready(Err(Error::Truncated))
|
||||
}
|
||||
}).await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Close the transmit half of the connection
|
||||
@@ -276,16 +265,13 @@ impl Drop for TcpStream {
|
||||
/// Free item in the socket set, which leads to deallocation of
|
||||
/// the rx/tx buffers associated with this socket.
|
||||
fn drop(&mut self) {
|
||||
Sockets::instance().sockets.borrow_mut()
|
||||
.remove(self.handle);
|
||||
Sockets::instance().sockets.borrow_mut().remove(self.handle);
|
||||
}
|
||||
}
|
||||
|
||||
fn socket_is_handhshaking(socket: &SocketRef<TcpSocket>) -> bool {
|
||||
match socket.state() {
|
||||
TcpState::SynSent | TcpState::SynReceived =>
|
||||
true,
|
||||
_ =>
|
||||
false,
|
||||
TcpState::SynSent | TcpState::SynReceived => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
//! Asynchronous tasks
|
||||
|
||||
use core::{
|
||||
future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use core::{future::Future,
|
||||
pin::Pin,
|
||||
task::{Context, Poll}};
|
||||
|
||||
use super::executor;
|
||||
|
||||
/// Drives the future `f` to completion
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
//! AXI_HP Interface (AFI)
|
||||
|
||||
use volatile_register::RW;
|
||||
|
||||
use libregister::{register, register_bit, register_bits};
|
||||
use volatile_register::RW;
|
||||
|
||||
pub unsafe fn axi_hp0() -> &'static RegisterBlock {
|
||||
&*(0xF8008000 as *const _)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use core::unimplemented;
|
||||
|
||||
use libregister::{RegisterR, RegisterRW};
|
||||
use super::slcr;
|
||||
pub use slcr::ArmPllSource;
|
||||
|
||||
use super::slcr;
|
||||
|
||||
pub mod source;
|
||||
use source::*;
|
||||
|
||||
@@ -53,10 +54,8 @@ impl Clocks {
|
||||
}
|
||||
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.arm_clk_ctrl.modify(|_, w| w
|
||||
.srcsel(ArmPllSource::ArmPll)
|
||||
.divisor(div)
|
||||
);
|
||||
slcr.arm_clk_ctrl
|
||||
.modify(|_, w| w.srcsel(ArmPllSource::ArmPll).divisor(div));
|
||||
})
|
||||
}
|
||||
|
||||
@@ -77,19 +76,15 @@ impl Clocks {
|
||||
|
||||
pub fn cpu_2x(&self) -> u32 {
|
||||
match CpuClockMode::get() {
|
||||
CpuClockMode::C421 =>
|
||||
self.cpu_6x4x() / 2,
|
||||
CpuClockMode::C621 =>
|
||||
self.cpu_6x4x() / 3,
|
||||
CpuClockMode::C421 => self.cpu_6x4x() / 2,
|
||||
CpuClockMode::C621 => self.cpu_6x4x() / 3,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpu_1x(&self) -> u32 {
|
||||
match CpuClockMode::get() {
|
||||
CpuClockMode::C421 =>
|
||||
self.cpu_6x4x() / 4,
|
||||
CpuClockMode::C621 =>
|
||||
self.cpu_6x4x() / 6,
|
||||
CpuClockMode::C421 => self.cpu_6x4x() / 4,
|
||||
CpuClockMode::C621 => self.cpu_6x4x() / 6,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,14 +92,10 @@ impl Clocks {
|
||||
let regs = slcr::RegisterBlock::slcr();
|
||||
let uart_clk_ctrl = regs.uart_clk_ctrl.read();
|
||||
let pll = match uart_clk_ctrl.srcsel() {
|
||||
slcr::PllSource::ArmPll =>
|
||||
self.arm,
|
||||
slcr::PllSource::DdrPll =>
|
||||
self.ddr,
|
||||
slcr::PllSource::IoPll =>
|
||||
self.io,
|
||||
slcr::PllSource::Emio =>
|
||||
unimplemented!(),
|
||||
slcr::PllSource::ArmPll => self.arm,
|
||||
slcr::PllSource::DdrPll => self.ddr,
|
||||
slcr::PllSource::IoPll => self.io,
|
||||
slcr::PllSource::Emio => unimplemented!(),
|
||||
};
|
||||
pll / u32::from(uart_clk_ctrl.divisor())
|
||||
}
|
||||
@@ -113,14 +104,10 @@ impl Clocks {
|
||||
let regs = slcr::RegisterBlock::slcr();
|
||||
let sdio_clk_ctrl = regs.sdio_clk_ctrl.read();
|
||||
let pll = match sdio_clk_ctrl.srcsel() {
|
||||
slcr::PllSource::ArmPll =>
|
||||
self.arm,
|
||||
slcr::PllSource::DdrPll =>
|
||||
self.ddr,
|
||||
slcr::PllSource::IoPll =>
|
||||
self.io,
|
||||
slcr::PllSource::Emio =>
|
||||
unimplemented!(),
|
||||
slcr::PllSource::ArmPll => self.arm,
|
||||
slcr::PllSource::DdrPll => self.ddr,
|
||||
slcr::PllSource::IoPll => self.io,
|
||||
slcr::PllSource::Emio => unimplemented!(),
|
||||
};
|
||||
pll / u32::from(sdio_clk_ctrl.divisor())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||
use log::debug;
|
||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||
|
||||
use super::slcr;
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
@@ -39,11 +40,13 @@ const PLL_FDIV_LOCK_PARAM: &[(u16, (u8, u8, u16))] = &[
|
||||
|
||||
pub trait ClockSource {
|
||||
/// picks this ClockSource's registers from the SLCR block
|
||||
fn pll_regs(slcr: &mut crate::slcr::RegisterBlock)
|
||||
-> (&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus
|
||||
);
|
||||
fn pll_regs(
|
||||
slcr: &mut crate::slcr::RegisterBlock,
|
||||
) -> (
|
||||
&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus,
|
||||
);
|
||||
|
||||
/// query PLL lock status
|
||||
fn pll_locked(pll_status: &mut crate::slcr::PllStatus) -> bool;
|
||||
@@ -61,39 +64,34 @@ pub trait ClockSource {
|
||||
/// 25.10.4 PLLs
|
||||
fn setup(target_freq: u32) {
|
||||
let fdiv = (target_freq / PS_CLK).min(66) as u16;
|
||||
let (pll_cp, pll_res, lock_cnt) = PLL_FDIV_LOCK_PARAM.iter()
|
||||
let (pll_cp, pll_res, lock_cnt) = PLL_FDIV_LOCK_PARAM
|
||||
.iter()
|
||||
.filter(|(fdiv_max, _)| fdiv <= *fdiv_max)
|
||||
.nth(0)
|
||||
.expect("PLL_FDIV_LOCK_PARAM")
|
||||
.1.clone();
|
||||
.1
|
||||
.clone();
|
||||
|
||||
debug!("Set {} to {} Hz", Self::name(), target_freq);
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
let (pll_ctrl, pll_cfg, pll_status) = Self::pll_regs(slcr);
|
||||
|
||||
// Bypass
|
||||
pll_ctrl.modify(|_, w| w
|
||||
.pll_pwrdwn(false)
|
||||
.pll_bypass_force(true)
|
||||
.pll_fdiv(fdiv)
|
||||
);
|
||||
pll_ctrl.modify(|_, w| w.pll_pwrdwn(false).pll_bypass_force(true).pll_fdiv(fdiv));
|
||||
// Configure
|
||||
pll_cfg.write(
|
||||
slcr::PllCfg::zeroed()
|
||||
.pll_res(pll_res)
|
||||
.pll_cp(pll_cp)
|
||||
.lock_cnt(lock_cnt)
|
||||
.lock_cnt(lock_cnt),
|
||||
);
|
||||
// Reset
|
||||
pll_ctrl.modify(|_, w| w.pll_reset(true));
|
||||
pll_ctrl.modify(|_, w| w.pll_reset(false));
|
||||
// Wait for PLL lock
|
||||
while ! Self::pll_locked(pll_status) {}
|
||||
while !Self::pll_locked(pll_status) {}
|
||||
// Remove bypass
|
||||
pll_ctrl.modify(|_, w| w
|
||||
.pll_bypass_force(false)
|
||||
.pll_bypass_qual(false)
|
||||
);
|
||||
pll_ctrl.modify(|_, w| w.pll_bypass_force(false).pll_bypass_qual(false));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -103,15 +101,14 @@ pub struct ArmPll;
|
||||
|
||||
impl ClockSource for ArmPll {
|
||||
#[inline]
|
||||
fn pll_regs(slcr: &mut crate::slcr::RegisterBlock)
|
||||
-> (&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus
|
||||
fn pll_regs(
|
||||
slcr: &mut crate::slcr::RegisterBlock,
|
||||
) -> (
|
||||
&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus,
|
||||
) {
|
||||
(&mut slcr.arm_pll_ctrl,
|
||||
&mut slcr.arm_pll_cfg,
|
||||
&mut slcr.pll_status
|
||||
)
|
||||
(&mut slcr.arm_pll_ctrl, &mut slcr.arm_pll_cfg, &mut slcr.pll_status)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -129,15 +126,14 @@ pub struct DdrPll;
|
||||
|
||||
impl ClockSource for DdrPll {
|
||||
#[inline]
|
||||
fn pll_regs(slcr: &mut crate::slcr::RegisterBlock)
|
||||
-> (&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus
|
||||
fn pll_regs(
|
||||
slcr: &mut crate::slcr::RegisterBlock,
|
||||
) -> (
|
||||
&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus,
|
||||
) {
|
||||
(&mut slcr.ddr_pll_ctrl,
|
||||
&mut slcr.ddr_pll_cfg,
|
||||
&mut slcr.pll_status
|
||||
)
|
||||
(&mut slcr.ddr_pll_ctrl, &mut slcr.ddr_pll_cfg, &mut slcr.pll_status)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -153,18 +149,16 @@ impl ClockSource for DdrPll {
|
||||
/// I/O PLL: Recommended clock for I/O peripherals
|
||||
pub struct IoPll;
|
||||
|
||||
|
||||
impl ClockSource for IoPll {
|
||||
#[inline]
|
||||
fn pll_regs(slcr: &mut crate::slcr::RegisterBlock)
|
||||
-> (&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus
|
||||
fn pll_regs(
|
||||
slcr: &mut crate::slcr::RegisterBlock,
|
||||
) -> (
|
||||
&mut crate::slcr::PllCtrl,
|
||||
&mut crate::slcr::PllCfg,
|
||||
&mut crate::slcr::PllStatus,
|
||||
) {
|
||||
(&mut slcr.io_pll_ctrl,
|
||||
&mut slcr.io_pll_cfg,
|
||||
&mut slcr.pll_status
|
||||
)
|
||||
(&mut slcr.io_pll_ctrl, &mut slcr.io_pll_cfg, &mut slcr.pll_status)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use libregister::{RegisterR, RegisterW, RegisterRW};
|
||||
use log::{debug, info, error};
|
||||
use crate::{print, println};
|
||||
use super::slcr;
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||
use log::{debug, error, info};
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
use super::slcr::DdriobVrefSel;
|
||||
use super::clocks::{Clocks, source::{DdrPll, ClockSource}};
|
||||
use super::{clocks::{Clocks,
|
||||
source::{ClockSource, DdrPll}},
|
||||
slcr};
|
||||
use crate::{print, println};
|
||||
|
||||
mod regs;
|
||||
|
||||
@@ -53,7 +55,11 @@ impl DdrRam {
|
||||
let clocks = Clocks::get();
|
||||
let ddr3x_clk_divisor = 2;
|
||||
let ddr2x_clk_divisor = 3;
|
||||
debug!("DDR 3x/2x clocks: {}/{}", clocks.ddr / u32::from(ddr3x_clk_divisor), clocks.ddr / u32::from(ddr2x_clk_divisor));
|
||||
debug!(
|
||||
"DDR 3x/2x clocks: {}/{}",
|
||||
clocks.ddr / u32::from(ddr3x_clk_divisor),
|
||||
clocks.ddr / u32::from(ddr2x_clk_divisor)
|
||||
);
|
||||
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
slcr.ddr_clk_ctrl.write(
|
||||
@@ -61,7 +67,7 @@ impl DdrRam {
|
||||
.ddr_2xclkact(true)
|
||||
.ddr_3xclkact(true)
|
||||
.ddr_2xclk_divisor(ddr2x_clk_divisor)
|
||||
.ddr_3xclk_divisor(ddr3x_clk_divisor)
|
||||
.ddr_3xclk_divisor(ddr3x_clk_divisor),
|
||||
);
|
||||
});
|
||||
clocks
|
||||
@@ -93,9 +99,12 @@ impl DdrRam {
|
||||
/// 10.6.2 DDR IOB Impedance Calibration
|
||||
fn calibrate_iob_impedance(clocks: &Clocks) {
|
||||
let (divisor0, divisor1) = Self::calculate_dci_divisors(clocks);
|
||||
debug!("DDR DCI clock: {} Hz (divisors={}*{})",
|
||||
clocks.ddr / u32::from(divisor0) / u32::from(divisor1),
|
||||
divisor0, divisor1);
|
||||
debug!(
|
||||
"DDR DCI clock: {} Hz (divisors={}*{})",
|
||||
clocks.ddr / u32::from(divisor0) / u32::from(divisor1),
|
||||
divisor0,
|
||||
divisor1
|
||||
);
|
||||
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
// Step 1.
|
||||
@@ -103,34 +112,21 @@ impl DdrRam {
|
||||
slcr::DciClkCtrl::zeroed()
|
||||
.clkact(true)
|
||||
.divisor0(divisor0)
|
||||
.divisor1(divisor1)
|
||||
.divisor1(divisor1),
|
||||
);
|
||||
|
||||
// Step 2.a.
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w|
|
||||
w.reset(false)
|
||||
);
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w|
|
||||
w.reset(true)
|
||||
);
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w| w.reset(false));
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w| w.reset(true));
|
||||
// Step 3.b. for DDR3/DDR3L
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w|
|
||||
w.nref_opt1(0)
|
||||
.nref_opt2(0)
|
||||
.nref_opt4(1)
|
||||
.pref_opt1(0)
|
||||
.pref_opt2(0)
|
||||
);
|
||||
slcr.ddriob_dci_ctrl
|
||||
.modify(|_, w| w.nref_opt1(0).nref_opt2(0).nref_opt4(1).pref_opt1(0).pref_opt2(0));
|
||||
// Step 2.c.
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w|
|
||||
w.update_control(false)
|
||||
);
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w| w.update_control(false));
|
||||
// Step 2.d.
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w|
|
||||
w.enable(true)
|
||||
);
|
||||
slcr.ddriob_dci_ctrl.modify(|_, w| w.enable(true));
|
||||
// Step 2.e.
|
||||
while ! slcr.ddriob_dci_status.read().done() {}
|
||||
while !slcr.ddriob_dci_status.read().done() {}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,8 +134,7 @@ impl DdrRam {
|
||||
/// 10.6.3 DDR IOB Configuration
|
||||
fn configure_iob() {
|
||||
slcr::RegisterBlock::unlocked(|slcr| {
|
||||
let addr_config = slcr::DdriobConfig::zeroed()
|
||||
.output_en(slcr::DdriobOutputEn::Obuf);
|
||||
let addr_config = slcr::DdriobConfig::zeroed().output_en(slcr::DdriobOutputEn::Obuf);
|
||||
slcr.ddriob_addr0.write(addr_config.clone());
|
||||
slcr.ddriob_addr1.write(addr_config);
|
||||
|
||||
@@ -168,8 +163,7 @@ impl DdrRam {
|
||||
feature = "target_redpitaya",
|
||||
feature = "target_kasli_soc",
|
||||
))]
|
||||
let data1_config = slcr::DdriobConfig::zeroed()
|
||||
.pullup_en(true);
|
||||
let data1_config = slcr::DdriobConfig::zeroed().pullup_en(true);
|
||||
slcr.ddriob_data0.write(data0_config);
|
||||
slcr.ddriob_data1.write(data1_config);
|
||||
|
||||
@@ -198,15 +192,12 @@ impl DdrRam {
|
||||
feature = "target_redpitaya",
|
||||
feature = "target_kasli_soc",
|
||||
))]
|
||||
let diff1_config = slcr::DdriobConfig::zeroed()
|
||||
.pullup_en(true);
|
||||
let diff1_config = slcr::DdriobConfig::zeroed().pullup_en(true);
|
||||
slcr.ddriob_diff0.write(diff0_config);
|
||||
slcr.ddriob_diff1.write(diff1_config);
|
||||
|
||||
slcr.ddriob_clock.write(
|
||||
slcr::DdriobConfig::zeroed()
|
||||
.output_en(slcr::DdriobOutputEn::Obuf)
|
||||
);
|
||||
slcr.ddriob_clock
|
||||
.write(slcr::DdriobConfig::zeroed().output_en(slcr::DdriobOutputEn::Obuf));
|
||||
|
||||
unsafe {
|
||||
// Not documented in Technical Reference Manual
|
||||
@@ -222,19 +213,19 @@ impl DdrRam {
|
||||
feature = "target_redpitaya",
|
||||
feature = "target_kasli_soc",
|
||||
))]
|
||||
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
||||
.vref_int_en(false)
|
||||
slcr.ddriob_ddr_ctrl.modify(|_, w| {
|
||||
w.vref_int_en(false)
|
||||
.vref_ext_en_lower(true)
|
||||
.vref_ext_en_upper(false)
|
||||
.refio_en(true)
|
||||
);
|
||||
});
|
||||
#[cfg(feature = "target_zc706")]
|
||||
slcr.ddriob_ddr_ctrl.modify(|_, w| w
|
||||
.vref_int_en(true)
|
||||
slcr.ddriob_ddr_ctrl.modify(|_, w| {
|
||||
w.vref_int_en(true)
|
||||
.vref_sel(DdriobVrefSel::Vref0_75V)
|
||||
.vref_ext_en_lower(false)
|
||||
.vref_ext_en_upper(false)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -244,45 +235,40 @@ impl DdrRam {
|
||||
regs::DramParam0::zeroed()
|
||||
.t_rc(0x1a)
|
||||
.t_rfc_min(0x9e)
|
||||
.post_selfref_gap_x32(0x10)
|
||||
.post_selfref_gap_x32(0x10),
|
||||
);
|
||||
#[cfg(feature = "target_ebaz4205")]
|
||||
self.regs.dram_param0.write(
|
||||
regs::DramParam0::zeroed()
|
||||
.t_rc(0x1a)
|
||||
.t_rfc_min(0x56)
|
||||
.post_selfref_gap_x32(0x10)
|
||||
.post_selfref_gap_x32(0x10),
|
||||
);
|
||||
#[cfg(feature = "target_redpitaya")]
|
||||
self.regs.dram_param0.write(
|
||||
regs::DramParam0::zeroed()
|
||||
.t_rc(0x1b)
|
||||
.t_rfc_min(0xa0)
|
||||
.post_selfref_gap_x32(0x10)
|
||||
.post_selfref_gap_x32(0x10),
|
||||
);
|
||||
#[cfg(feature = "target_zc706")]
|
||||
self.regs.dram_param0.write(
|
||||
regs::DramParam0::zeroed()
|
||||
.t_rc(0x1b)
|
||||
.t_rfc_min(0x56)
|
||||
.post_selfref_gap_x32(0x10)
|
||||
.post_selfref_gap_x32(0x10),
|
||||
);
|
||||
#[cfg(feature = "target_ebaz4205")]
|
||||
self.regs.dram_param1.modify(
|
||||
|_, w| w
|
||||
.t_faw(0x16)
|
||||
.t_ras_min(0x13)
|
||||
);
|
||||
self.regs.dram_param1.modify(|_, w| w.t_faw(0x16).t_ras_min(0x13));
|
||||
#[cfg(feature = "target_redpitaya")]
|
||||
self.regs.dram_param1.modify(
|
||||
|_, w| w
|
||||
.wr2pre(0x12)
|
||||
self.regs.dram_param1.modify(|_, w| {
|
||||
w.wr2pre(0x12)
|
||||
.powerdown_to_x32(6)
|
||||
.t_faw(0x16)
|
||||
.t_ras_max(0x24)
|
||||
.t_ras_min(0x13)
|
||||
.t_cke(4)
|
||||
);
|
||||
});
|
||||
|
||||
self.regs.dram_param2.write(
|
||||
regs::DramParam2::zeroed()
|
||||
@@ -292,17 +278,13 @@ impl DdrRam {
|
||||
.t_xp(0x4)
|
||||
.pad_pd(0x0)
|
||||
.rd2pre(0x4)
|
||||
.t_rcd(0x7)
|
||||
.t_rcd(0x7),
|
||||
);
|
||||
#[cfg(feature = "target_ebaz4205")]
|
||||
self.regs.dram_param3.modify(
|
||||
|_, w| w
|
||||
.t_rp(7)
|
||||
);
|
||||
self.regs.dram_param3.modify(|_, w| w.t_rp(7));
|
||||
#[cfg(feature = "target_redpitaya")]
|
||||
self.regs.dram_param3.modify(
|
||||
|_, w| w
|
||||
.t_ccd(4)
|
||||
self.regs.dram_param3.modify(|_, w| {
|
||||
w.t_ccd(4)
|
||||
.t_rrd(6)
|
||||
.refresh_margin(2)
|
||||
.t_rp(7)
|
||||
@@ -312,13 +294,11 @@ impl DdrRam {
|
||||
.read_latency(7)
|
||||
.mode_ddr1_ddr2(true)
|
||||
.dis_pad_pd(false)
|
||||
);
|
||||
});
|
||||
|
||||
self.regs.dram_emr_mr.write(
|
||||
regs::DramEmrMr::zeroed()
|
||||
.mr(0x930)
|
||||
.emr(0x4)
|
||||
);
|
||||
self.regs
|
||||
.dram_emr_mr
|
||||
.write(regs::DramEmrMr::zeroed().mr(0x930).emr(0x4));
|
||||
|
||||
#[cfg(any(
|
||||
feature = "target_coraz7",
|
||||
@@ -326,22 +306,17 @@ impl DdrRam {
|
||||
feature = "target_redpitaya",
|
||||
feature = "target_kasli_soc",
|
||||
))]
|
||||
self.regs.phy_configs[2].modify(
|
||||
|_, w| w.data_slice_in_use(false)
|
||||
);
|
||||
self.regs.phy_configs[2].modify(|_, w| w.data_slice_in_use(false));
|
||||
#[cfg(any(
|
||||
feature = "target_coraz7",
|
||||
feature = "target_ebaz4205",
|
||||
feature = "target_redpitaya",
|
||||
feature = "target_kasli_soc",
|
||||
))]
|
||||
self.regs.phy_configs[3].modify(
|
||||
|_, w| w.data_slice_in_use(false)
|
||||
);
|
||||
self.regs.phy_configs[3].modify(|_, w| w.data_slice_in_use(false));
|
||||
|
||||
self.regs.phy_cmd_timeout_rddata_cpt.modify(
|
||||
|_, w| w
|
||||
.rd_cmd_to_data(0x0)
|
||||
self.regs.phy_cmd_timeout_rddata_cpt.modify(|_, w| {
|
||||
w.rd_cmd_to_data(0x0)
|
||||
.wr_cmd_to_data(0x0)
|
||||
.we_to_re_delay(0x8)
|
||||
.rdc_fifo_rst_disable(false)
|
||||
@@ -351,7 +326,7 @@ impl DdrRam {
|
||||
.clk_stall_level(false)
|
||||
.gatelvl_num_of_dq0(0x7)
|
||||
.wrlvl_num_of_dq0(0x7)
|
||||
);
|
||||
});
|
||||
|
||||
self.regs.reg_2c.write(
|
||||
regs::Reg2C::zeroed()
|
||||
@@ -361,37 +336,30 @@ impl DdrRam {
|
||||
.trdlvl_max_error(false)
|
||||
.dfi_wr_level_en(true)
|
||||
.dfi_rd_dqs_gate_level(true)
|
||||
.dfi_rd_data_eye_train(true)
|
||||
.dfi_rd_data_eye_train(true),
|
||||
);
|
||||
|
||||
self.regs.dfi_timing.write(
|
||||
regs::DfiTiming::zeroed()
|
||||
.rddata_en(0x6)
|
||||
.ctrlup_min(0x3)
|
||||
.ctrlup_max(0x40)
|
||||
.ctrlup_max(0x40),
|
||||
);
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
self.regs.phy_init_ratios[3].write(
|
||||
regs::PhyInitRatio::zeroed()
|
||||
.wrlvl_init_ratio(0x21)
|
||||
.gatelvl_init_ratio(0xee)
|
||||
.gatelvl_init_ratio(0xee),
|
||||
);
|
||||
|
||||
#[cfg(any(
|
||||
feature = "target_coraz7",
|
||||
feature = "target_ebaz4205",
|
||||
feature = "target_kasli_soc"),
|
||||
)]
|
||||
self.regs.reg_64.modify(
|
||||
|_, w| w
|
||||
.phy_ctrl_slave_ratio(0x100)
|
||||
.phy_invert_clkout(true)
|
||||
);
|
||||
#[cfg(any(feature = "target_coraz7", feature = "target_ebaz4205", feature = "target_kasli_soc"))]
|
||||
self.regs
|
||||
.reg_64
|
||||
.modify(|_, w| w.phy_ctrl_slave_ratio(0x100).phy_invert_clkout(true));
|
||||
#[cfg(feature = "target_redpitaya")]
|
||||
self.regs.reg_64.modify(
|
||||
|_, w| w
|
||||
.phy_bl2(false)
|
||||
self.regs.reg_64.modify(|_, w| {
|
||||
w.phy_bl2(false)
|
||||
.phy_invert_clkout(true)
|
||||
.phy_sel_logic(false)
|
||||
.phy_ctrl_slave_ratio(0x100)
|
||||
@@ -399,7 +367,7 @@ impl DdrRam {
|
||||
.phy_ctrl_slave_delay(0)
|
||||
.phy_lpddr(false)
|
||||
.phy_cmd_latency(false)
|
||||
);
|
||||
});
|
||||
|
||||
self.regs.reg_65.write(
|
||||
regs::Reg65::zeroed()
|
||||
@@ -410,7 +378,7 @@ impl DdrRam {
|
||||
.use_rd_dqs_gate_level(true)
|
||||
.use_rd_data_eye_level(true)
|
||||
.dis_calib_rst(false)
|
||||
.ctrl_slave_delay(0x0)
|
||||
.ctrl_slave_delay(0x0),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -425,11 +393,9 @@ impl DdrRam {
|
||||
feature = "target_kasli_soc",
|
||||
))]
|
||||
let width = regs::DataBusWidth::Width16bit;
|
||||
self.regs.ddrc_ctrl.modify(|_, w| w
|
||||
.soft_rstb(false)
|
||||
.powerdown_en(false)
|
||||
.data_bus_width(width)
|
||||
);
|
||||
self.regs
|
||||
.ddrc_ctrl
|
||||
.modify(|_, w| w.soft_rstb(false).powerdown_en(false).data_bus_width(width));
|
||||
f(self);
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
@@ -452,11 +418,9 @@ impl DdrRam {
|
||||
self.regs.dram_addr_map_row.write(0x0F555555);
|
||||
}
|
||||
|
||||
self.regs.ddrc_ctrl.modify(|_, w| w
|
||||
.soft_rstb(true)
|
||||
.powerdown_en(false)
|
||||
.data_bus_width(width)
|
||||
);
|
||||
self.regs
|
||||
.ddrc_ctrl
|
||||
.modify(|_, w| w.soft_rstb(true).powerdown_en(false).data_bus_width(width));
|
||||
|
||||
while self.status() == regs::ControllerStatus::Init {}
|
||||
}
|
||||
@@ -489,9 +453,7 @@ impl DdrRam {
|
||||
}
|
||||
|
||||
pub fn memtest(&mut self) {
|
||||
let slice = unsafe {
|
||||
core::slice::from_raw_parts_mut(self.ptr(), self.size())
|
||||
};
|
||||
let slice = unsafe { core::slice::from_raw_parts_mut(self.ptr(), self.size()) };
|
||||
let patterns: &'static [u32] = &[0xffff_ffff, 0x5555_5555, 0xaaaa_aaaa, 0];
|
||||
let mut expected = None;
|
||||
for (i, pattern) in patterns.iter().enumerate() {
|
||||
@@ -504,7 +466,10 @@ impl DdrRam {
|
||||
expected.map(|expected| {
|
||||
let read: u32 = *b;
|
||||
if read != expected {
|
||||
error!("{:08X}: expected {:08X}, read {:08X}", b as *mut _ as usize, expected, read);
|
||||
error!(
|
||||
"{:08X}: expected {:08X}, read {:08X}",
|
||||
b as *mut _ as usize, expected, read
|
||||
);
|
||||
}
|
||||
});
|
||||
*b = *pattern;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use volatile_register::{RO, RW};
|
||||
|
||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
use volatile_register::{RO, RW};
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -23,8 +22,6 @@ pub enum ControllerStatus {
|
||||
Powerdown4 = 7,
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub ddrc_ctrl: DdrcCtrl,
|
||||
@@ -266,8 +263,7 @@ register_bit!(reg_65, dis_calib_rst, 17);
|
||||
register_bits!(reg_65, ctrl_slave_delay, u8, 18, 19);
|
||||
|
||||
// Controller operation mode status
|
||||
register!(mode_sts_reg,
|
||||
ModeStsReg, RO, u32);
|
||||
register!(mode_sts_reg, ModeStsReg, RO, u32);
|
||||
register_bits_typed!(mode_sts_reg, operating_mode, u8, ControllerStatus, 0, 2);
|
||||
// (mode_sts_reg) ...
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use super::time::Milliseconds;
|
||||
use crate::slcr;
|
||||
use embedded_hal::timer::CountDown;
|
||||
use libcortex_a9::cache;
|
||||
use libregister::*;
|
||||
use log::{debug, trace};
|
||||
|
||||
use super::time::Milliseconds;
|
||||
use crate::slcr;
|
||||
|
||||
mod regs;
|
||||
|
||||
pub struct DevC {
|
||||
@@ -54,10 +55,7 @@ impl core::fmt::Display for DevcError {
|
||||
ResetTimeout => write!(f, "DevC driver reset timeout."),
|
||||
DmaBusy => write!(f, "DevC driver DMA busy."),
|
||||
DmaTimeout => write!(f, "DevC driver DMA timeout."),
|
||||
DoneTimeout => write!(
|
||||
f,
|
||||
"FPGA DONE signal timeout. Check if the bitstream is correct."
|
||||
),
|
||||
DoneTimeout => write!(f, "FPGA DONE signal timeout. Check if the bitstream is correct."),
|
||||
Unknown(reg) => write!(f, "Unknown error, interrupt status register = 0x{:0X}", reg),
|
||||
}
|
||||
}
|
||||
@@ -88,9 +86,7 @@ impl DevC {
|
||||
// unlock register with magic pattern
|
||||
self.regs.unlock.write(UNLOCK_PATTERN);
|
||||
}
|
||||
self.regs
|
||||
.control
|
||||
.modify(|_, w| w.pcap_mode(true).pcap_pr(true));
|
||||
self.regs.control.modify(|_, w| w.pcap_mode(true).pcap_pr(true));
|
||||
self.regs
|
||||
.int_mask
|
||||
.write(self::regs::int_mask::Write { inner: 0xFFFFFFFF });
|
||||
@@ -102,9 +98,7 @@ impl DevC {
|
||||
/// `enable` has to be called before further `program` or
|
||||
/// `start_dma_transaction`.
|
||||
pub fn disable(&mut self) {
|
||||
self.regs
|
||||
.control
|
||||
.modify(|_, w| w.pcap_mode(false).pcap_pr(false));
|
||||
self.regs.control.modify(|_, w| w.pcap_mode(false).pcap_pr(false));
|
||||
self.enabled = false;
|
||||
}
|
||||
|
||||
@@ -116,11 +110,7 @@ impl DevC {
|
||||
}
|
||||
|
||||
/// Wait on a certain condition with hardcoded timeout.
|
||||
fn wait_condition<F: Fn(&mut Self) -> bool>(
|
||||
&mut self,
|
||||
fun: F,
|
||||
err: DevcError,
|
||||
) -> Result<(), DevcError> {
|
||||
fn wait_condition<F: Fn(&mut Self) -> bool>(&mut self, fun: F, err: DevcError) -> Result<(), DevcError> {
|
||||
self.count_down.start(self.timeout_ms);
|
||||
while let Err(nb::Error::WouldBlock) = self.count_down.wait() {
|
||||
if fun(self) {
|
||||
@@ -154,17 +144,11 @@ impl DevC {
|
||||
self.regs.control.modify(|_, w| w.pcfg_prog_b(false));
|
||||
|
||||
// wait until init is false
|
||||
self.wait_condition(
|
||||
|s| !s.regs.status.read().pcfg_init(),
|
||||
DevcError::ResetTimeout,
|
||||
)?;
|
||||
self.wait_condition(|s| !s.regs.status.read().pcfg_init(), DevcError::ResetTimeout)?;
|
||||
|
||||
self.regs.control.modify(|_, w| w.pcfg_prog_b(true));
|
||||
// wait until init is true
|
||||
self.wait_condition(
|
||||
|s| s.regs.status.read().pcfg_init(),
|
||||
DevcError::ResetTimeout,
|
||||
)?;
|
||||
self.wait_condition(|s| s.regs.status.read().pcfg_init(), DevcError::ResetTimeout)?;
|
||||
|
||||
self.regs.int_sts.write(
|
||||
self::regs::IntSts::zeroed()
|
||||
@@ -217,9 +201,7 @@ impl DevC {
|
||||
};
|
||||
|
||||
self.regs.dma_src_addr.modify(|_, w| w.src_addr(src_addr));
|
||||
self.regs
|
||||
.dma_dest_addr
|
||||
.modify(|_, w| w.dest_addr(dest_addr));
|
||||
self.regs.dma_dest_addr.modify(|_, w| w.dest_addr(dest_addr));
|
||||
self.regs.dma_src_len.modify(|_, w| w.dma_len(src_len));
|
||||
self.regs.dma_dest_len.modify(|_, w| w.dma_len(dest_len));
|
||||
}
|
||||
@@ -247,9 +229,7 @@ impl DevC {
|
||||
return Err(DevcError::DmaBusy);
|
||||
}
|
||||
|
||||
if transfer_type != TransferType::ConcurrentReadWrite
|
||||
&& !self.regs.status.read().pcfg_init()
|
||||
{
|
||||
if transfer_type != TransferType::ConcurrentReadWrite && !self.regs.status.read().pcfg_init() {
|
||||
return Err(DevcError::NotInitialized);
|
||||
}
|
||||
match &transfer_type {
|
||||
@@ -279,13 +259,8 @@ impl DevC {
|
||||
|
||||
fn wait_dma_transfer_complete(&mut self) -> Result<(), DevcError> {
|
||||
trace!("Wait for DMA done");
|
||||
self.wait_condition(
|
||||
|s| s.regs.int_sts.read().ixr_dma_done(),
|
||||
DevcError::DmaTimeout,
|
||||
)?;
|
||||
self.regs
|
||||
.int_sts
|
||||
.write(self::regs::IntSts::zeroed().ixr_dma_done(true));
|
||||
self.wait_condition(|s| s.regs.int_sts.read().ixr_dma_done(), DevcError::DmaTimeout)?;
|
||||
self.regs.int_sts.write(self::regs::IntSts::zeroed().ixr_dma_done(true));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits, register_bits_typed,
|
||||
};
|
||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
use volatile_register::WO;
|
||||
|
||||
#[repr(C)]
|
||||
@@ -33,22 +30,22 @@ pub struct RegisterBlock {
|
||||
}
|
||||
register_at!(RegisterBlock, 0xF8007000, devc);
|
||||
register!(control, Control, RW, u32);
|
||||
register_bit!(control, force_rst, 31);
|
||||
register_bit!(control, pcfg_prog_b, 30);
|
||||
register_bit!(control, pcfg_pro_cnt_4k, 29);
|
||||
register_bit!(control, pcap_pr, 27);
|
||||
register_bit!(control, pcap_mode, 26);
|
||||
register_bit!(control, pcap_rate_en, 25);
|
||||
register_bit!(control, multiboot_en, 24);
|
||||
register_bit!(control, jtag_chain_dis, 23);
|
||||
register_bit!(control, pcfg_aes_fuse, 12);
|
||||
register_bit!(control, force_rst, 31);
|
||||
register_bit!(control, pcfg_prog_b, 30);
|
||||
register_bit!(control, pcfg_pro_cnt_4k, 29);
|
||||
register_bit!(control, pcap_pr, 27);
|
||||
register_bit!(control, pcap_mode, 26);
|
||||
register_bit!(control, pcap_rate_en, 25);
|
||||
register_bit!(control, multiboot_en, 24);
|
||||
register_bit!(control, jtag_chain_dis, 23);
|
||||
register_bit!(control, pcfg_aes_fuse, 12);
|
||||
register_bits!(control, pcfg_aes_en, u8, 9, 11);
|
||||
register_bit!(control, seu_en, 8);
|
||||
register_bit!(control, sec_en, 7);
|
||||
register_bit!(control, spniden, 6);
|
||||
register_bit!(control, spiden, 5);
|
||||
register_bit!(control, niden, 4);
|
||||
register_bit!(control, dbgen, 3);
|
||||
register_bit!(control, seu_en, 8);
|
||||
register_bit!(control, sec_en, 7);
|
||||
register_bit!(control, spniden, 6);
|
||||
register_bit!(control, spiden, 5);
|
||||
register_bit!(control, niden, 4);
|
||||
register_bit!(control, dbgen, 3);
|
||||
register_bits!(control, dap_en, u8, 0, 2);
|
||||
|
||||
register!(lock, Lock, RW, u32);
|
||||
@@ -62,19 +59,19 @@ register!(cfg, Cfg, RW, u32);
|
||||
#[allow(unused)]
|
||||
#[repr(u8)]
|
||||
pub enum RFifoTh {
|
||||
OneFourthFull = 0b00, // One fourth full for read
|
||||
HalfFull = 0b01, // Half full for read
|
||||
ThreeFourthFull = 0b10, // Three fourth full for read
|
||||
Full = 0b11, // Full for read
|
||||
OneFourthFull = 0b00, // One fourth full for read
|
||||
HalfFull = 0b01, // Half full for read
|
||||
ThreeFourthFull = 0b10, // Three fourth full for read
|
||||
Full = 0b11, // Full for read
|
||||
}
|
||||
register_bits_typed!(cfg, rfifo_th, u8, RFifoTh, 10, 11);
|
||||
#[allow(unused)]
|
||||
#[repr(u8)]
|
||||
pub enum WFifoTh {
|
||||
OneFourthEmpty = 0b00, // One fourth empty for write
|
||||
HalfEmpty = 0b01, // Half empty for write
|
||||
OneFourthEmpty = 0b00, // One fourth empty for write
|
||||
HalfEmpty = 0b01, // Half empty for write
|
||||
ThreeFourthEmpty = 0b10, // Three fourth empty for write
|
||||
Empty = 0b11, // Empty for write
|
||||
Empty = 0b11, // Empty for write
|
||||
}
|
||||
register_bits_typed!(cfg, wfifo_th, u8, WFifoTh, 8, 9);
|
||||
register_bit!(cfg, rclk_edge, 7);
|
||||
@@ -145,7 +142,7 @@ register_bit!(status, pss_fst_cfg_b, 10);
|
||||
register_bit!(status, pss_gpwrdwn_b, 9);
|
||||
register_bit!(status, pss_gts_cfg_b, 8);
|
||||
register_bit!(status, secure_rst, 7);
|
||||
register_bit!(status, illegal_apb_access , 6);
|
||||
register_bit!(status, illegal_apb_access, 6);
|
||||
register_bit!(status, pss_cfg_reset_b, 5);
|
||||
register_bit!(status, pcfg_init, 4);
|
||||
register_bit!(status, efuse_sw_reserve, 3);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use libregister::{RegisterRW, RegisterW};
|
||||
use libregister::{register, register_at, register_bit, register_bits};
|
||||
use libregister::{RegisterRW, RegisterW, register, register_at, register_bit, register_bits};
|
||||
|
||||
use super::slcr;
|
||||
|
||||
pub struct ErrorLED {
|
||||
@@ -16,7 +16,7 @@ impl ErrorLED {
|
||||
.l3_sel(0b000)
|
||||
.io_type(slcr::IoBufferType::Lvcmos25)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -30,27 +30,19 @@ impl ErrorLED {
|
||||
};
|
||||
|
||||
// Setup GPIO output mask
|
||||
self_.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.mask(gpio_output_mask)
|
||||
});
|
||||
self_.regs.gpio_output_mask.modify(|_, w| w.mask(gpio_output_mask));
|
||||
|
||||
self_.regs.gpio_direction.modify(|_, w| {
|
||||
w.lederr(true)
|
||||
});
|
||||
self_.regs.gpio_direction.modify(|_, w| w.lederr(true));
|
||||
|
||||
self_
|
||||
}
|
||||
|
||||
fn led_oe(&mut self, oe: bool) {
|
||||
self.regs.gpio_output_enable.modify(|_, w| {
|
||||
w.lederr(oe)
|
||||
})
|
||||
self.regs.gpio_output_enable.modify(|_, w| w.lederr(oe))
|
||||
}
|
||||
|
||||
fn led_o(&mut self, o: bool) {
|
||||
self.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.lederr_o(o)
|
||||
})
|
||||
self.regs.gpio_output_mask.modify(|_, w| w.lederr_o(o))
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self, state: bool) {
|
||||
@@ -59,7 +51,6 @@ impl ErrorLED {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct RegisterBlock {
|
||||
pub gpio_output_mask: &'static mut GPIOOutputMask,
|
||||
pub gpio_direction: &'static mut GPIODirection,
|
||||
@@ -71,7 +62,7 @@ impl RegisterBlock {
|
||||
Self {
|
||||
gpio_output_mask: GPIOOutputMask::new(),
|
||||
gpio_direction: GPIODirection::new(),
|
||||
gpio_output_enable: GPIOOutputEnable::new()
|
||||
gpio_output_enable: GPIOOutputEnable::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,8 +78,7 @@ register_bit!(gpio_output_mask,
|
||||
/// Output for LED_ERR (MIO[37])
|
||||
lederr_o, 5);
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
register_bits!(gpio_output_mask,
|
||||
mask, u16, 16, 31);
|
||||
register_bits!(gpio_output_mask, mask, u16, 16, 31);
|
||||
|
||||
register!(gpio_direction,
|
||||
/// DIRM_1:
|
||||
@@ -111,4 +101,3 @@ register_at!(GPIOOutputEnable, 0xE000A248, new);
|
||||
register_bit!(gpio_output_enable,
|
||||
/// Output enable for LED_ERR
|
||||
lederr, 5);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use log::{debug, info, warn, error};
|
||||
use core::{marker::PhantomData,
|
||||
ops::{Deref, DerefMut}};
|
||||
|
||||
use libregister::*;
|
||||
use super::slcr;
|
||||
use super::clocks::Clocks;
|
||||
use log::{debug, error, info, warn};
|
||||
|
||||
use super::{clocks::Clocks, slcr};
|
||||
|
||||
pub mod phy;
|
||||
use phy::{Phy, PhyAccess};
|
||||
@@ -13,9 +12,10 @@ mod regs;
|
||||
pub mod rx;
|
||||
pub mod tx;
|
||||
|
||||
use super::time::Milliseconds;
|
||||
use embedded_hal::timer::CountDown;
|
||||
|
||||
use super::time::Milliseconds;
|
||||
|
||||
/// Size of all the buffers
|
||||
pub const MTU: usize = 1536;
|
||||
/// Maximum MDC clock
|
||||
@@ -77,19 +77,16 @@ impl Gem for Gem0 {
|
||||
.clkact(true)
|
||||
.srcsel(slcr::PllSource::Emio)
|
||||
.divisor(divisor0 as u8)
|
||||
.divisor1(divisor1 as u8)
|
||||
.divisor1(divisor1 as u8),
|
||||
);
|
||||
// Enable gem0 recv clock
|
||||
slcr.gem0_rclk_ctrl.write(
|
||||
// 0x0000_0801
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
slcr::RclkCtrl::zeroed()
|
||||
.clkact(true),
|
||||
slcr::RclkCtrl::zeroed().clkact(true),
|
||||
// ebaz4205 -- EMIO
|
||||
#[cfg(feature = "target_ebaz4205")]
|
||||
slcr::RclkCtrl::zeroed()
|
||||
.clkact(true)
|
||||
.srcsel(true)
|
||||
slcr::RclkCtrl::zeroed().clkact(true).srcsel(true),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -112,13 +109,12 @@ impl Gem for Gem1 {
|
||||
.clkact(true)
|
||||
.srcsel(slcr::PllSource::IoPll)
|
||||
.divisor(divisor0 as u8)
|
||||
.divisor1(divisor1 as u8)
|
||||
.divisor1(divisor1 as u8),
|
||||
);
|
||||
// Enable gem1 recv clock
|
||||
slcr.gem1_rclk_ctrl.write(
|
||||
// 0x0000_0801
|
||||
slcr::RclkCtrl::zeroed()
|
||||
.clkact(true)
|
||||
slcr::RclkCtrl::zeroed().clkact(true),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -149,10 +145,13 @@ fn calculate_tx_divisors(tx_clock: u32) -> (u8, u8) {
|
||||
}
|
||||
}
|
||||
let result = best.unwrap();
|
||||
debug!("Eth TX clock for {}: {} / {} / {} = {}",
|
||||
tx_clock, io_pll,
|
||||
result.0, result.1,
|
||||
io_pll / result.0 as u32 / result.1 as u32
|
||||
debug!(
|
||||
"Eth TX clock for {}: {} / {} / {} = {}",
|
||||
tx_clock,
|
||||
io_pll,
|
||||
result.0,
|
||||
result.1,
|
||||
io_pll / result.0 as u32 / result.1 as u32
|
||||
);
|
||||
result
|
||||
}
|
||||
@@ -176,14 +175,14 @@ impl Eth<Gem0, (), ()> {
|
||||
slcr::MioPin53::zeroed()
|
||||
.l3_sel(0b100)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// MDC
|
||||
slcr.mio_pin_52.write(
|
||||
slcr::MioPin52::zeroed()
|
||||
.l3_sel(0b100)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// Manual example: 0x0000_3902
|
||||
// TX_CLK
|
||||
@@ -193,7 +192,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// TX_CTRL
|
||||
slcr.mio_pin_21.write(
|
||||
@@ -202,7 +201,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// TXD3
|
||||
slcr.mio_pin_20.write(
|
||||
@@ -211,7 +210,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// TXD2
|
||||
slcr.mio_pin_19.write(
|
||||
@@ -220,7 +219,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// TXD1
|
||||
slcr.mio_pin_18.write(
|
||||
@@ -229,7 +228,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// TXD0
|
||||
slcr.mio_pin_17.write(
|
||||
@@ -238,7 +237,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// Manual example: 0x0000_1903
|
||||
// RX_CLK
|
||||
@@ -247,7 +246,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RX_CTRL
|
||||
slcr.mio_pin_27.write(
|
||||
@@ -255,7 +254,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RXD3
|
||||
slcr.mio_pin_26.write(
|
||||
@@ -263,7 +262,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RXD2
|
||||
slcr.mio_pin_25.write(
|
||||
@@ -271,7 +270,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RXD1
|
||||
slcr.mio_pin_24.write(
|
||||
@@ -279,7 +278,7 @@ impl Eth<Gem0, (), ()> {
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RXD0
|
||||
slcr.mio_pin_23.write(
|
||||
@@ -287,13 +286,10 @@ impl Eth<Gem0, (), ()> {
|
||||
.l0_sel(true)
|
||||
.speed(true)
|
||||
.io_type(slcr::IoBufferType::Hstl)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// VREF internal generator
|
||||
slcr.gpiob_ctrl.write(
|
||||
slcr::GpiobCtrl::zeroed()
|
||||
.vref_en(true)
|
||||
);
|
||||
slcr.gpiob_ctrl.write(slcr::GpiobCtrl::zeroed().vref_en(true));
|
||||
});
|
||||
|
||||
Self::gem0(macaddr)
|
||||
@@ -304,7 +300,6 @@ impl Eth<Gem0, (), ()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Eth<Gem1, (), ()> {
|
||||
// TODO: Add a `eth1()`
|
||||
|
||||
@@ -313,12 +308,11 @@ impl Eth<Gem1, (), ()> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<GEM: Gem> Eth<GEM, (), ()> {
|
||||
fn gem_common(macaddr: [u8; 6]) -> Self {
|
||||
GEM::setup_clock(TX_1000);
|
||||
|
||||
#[cfg(feature="target_kasli_soc")]
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
{
|
||||
let mut eth_reset_pin = PhyRst::rst_pin();
|
||||
eth_reset_pin.reset();
|
||||
@@ -335,7 +329,7 @@ impl<GEM: Gem> Eth<GEM, (), ()> {
|
||||
let phy = Phy::find(&mut inner).expect("phy");
|
||||
phy.reset(&mut inner);
|
||||
phy.restart_autoneg(&mut inner);
|
||||
#[cfg(feature="target_kasli_soc")]
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
phy.set_leds(&mut inner);
|
||||
|
||||
Eth {
|
||||
@@ -359,13 +353,10 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
|
||||
};
|
||||
let list_addr = new_self.rx.list_addr();
|
||||
assert!(list_addr & 0b11 == 0);
|
||||
GEM::regs().rx_qbar.write(
|
||||
regs::RxQbar::zeroed()
|
||||
.rx_q_baseaddr(list_addr >> 2)
|
||||
);
|
||||
GEM::regs().net_ctrl.modify(|_, w|
|
||||
w.rx_en(true)
|
||||
);
|
||||
GEM::regs()
|
||||
.rx_qbar
|
||||
.write(regs::RxQbar::zeroed().rx_q_baseaddr(list_addr >> 2));
|
||||
GEM::regs().net_ctrl.modify(|_, w| w.rx_en(true));
|
||||
new_self
|
||||
}
|
||||
|
||||
@@ -379,13 +370,10 @@ impl<GEM: Gem, RX, TX> Eth<GEM, RX, TX> {
|
||||
};
|
||||
let list_addr = &new_self.tx.list_addr();
|
||||
assert!(list_addr & 0b11 == 0);
|
||||
GEM::regs().tx_qbar.write(
|
||||
regs::TxQbar::zeroed()
|
||||
.tx_q_baseaddr(list_addr >> 2)
|
||||
);
|
||||
GEM::regs().net_ctrl.modify(|_, w|
|
||||
w.tx_en(true)
|
||||
);
|
||||
GEM::regs()
|
||||
.tx_qbar
|
||||
.write(regs::TxQbar::zeroed().tx_q_baseaddr(list_addr >> 2));
|
||||
GEM::regs().net_ctrl.modify(|_, w| w.tx_en(true));
|
||||
new_self
|
||||
}
|
||||
}
|
||||
@@ -395,26 +383,19 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
||||
let status = GEM::regs().rx_status.read();
|
||||
if status.hresp_not_ok() {
|
||||
// Clear
|
||||
GEM::regs().rx_status.write(
|
||||
regs::RxStatus::zeroed()
|
||||
.hresp_not_ok(true)
|
||||
);
|
||||
GEM::regs().rx_status.write(regs::RxStatus::zeroed().hresp_not_ok(true));
|
||||
return Err(rx::Error::HrespNotOk);
|
||||
}
|
||||
if status.rx_overrun() {
|
||||
// Clear
|
||||
GEM::regs().rx_status.write(
|
||||
regs::RxStatus::zeroed()
|
||||
.rx_overrun(true)
|
||||
);
|
||||
GEM::regs().rx_status.write(regs::RxStatus::zeroed().rx_overrun(true));
|
||||
return Err(rx::Error::RxOverrun);
|
||||
}
|
||||
if status.buffer_not_avail() {
|
||||
// Clear
|
||||
GEM::regs().rx_status.write(
|
||||
regs::RxStatus::zeroed()
|
||||
.buffer_not_avail(true)
|
||||
);
|
||||
GEM::regs()
|
||||
.rx_status
|
||||
.write(regs::RxStatus::zeroed().buffer_not_avail(true));
|
||||
return Err(rx::Error::BufferNotAvail);
|
||||
}
|
||||
|
||||
@@ -423,14 +404,10 @@ impl<GEM: Gem, TX> Eth<GEM, rx::DescList, TX> {
|
||||
match result {
|
||||
Ok(None) => {
|
||||
// No packet, clear status bit
|
||||
GEM::regs().rx_status.write(
|
||||
regs::RxStatus::zeroed()
|
||||
.frame_recd(true)
|
||||
);
|
||||
GEM::regs().rx_status.write(regs::RxStatus::zeroed().frame_recd(true));
|
||||
self.idle = true;
|
||||
}
|
||||
_ =>
|
||||
self.idle = false,
|
||||
_ => self.idle = false,
|
||||
}
|
||||
result
|
||||
} else {
|
||||
@@ -459,7 +436,7 @@ impl<'a, GEM: Gem> smoltcp::phy::Device<'a> for &mut Eth<GEM, rx::DescList, tx::
|
||||
type TxToken = tx::Token<'a>;
|
||||
|
||||
fn capabilities(&self) -> smoltcp::phy::DeviceCapabilities {
|
||||
use smoltcp::phy::{DeviceCapabilities, ChecksumCapabilities, Checksum};
|
||||
use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities};
|
||||
|
||||
let mut checksum_caps = ChecksumCapabilities::default();
|
||||
checksum_caps.ipv4 = Checksum::Both;
|
||||
@@ -517,12 +494,12 @@ impl PhyRst {
|
||||
.l3_sel(0b000)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
});
|
||||
Self::eth_reset_common(0xFFFF - 0x8000)
|
||||
}
|
||||
|
||||
|
||||
fn delay_ms(&mut self, ms: u64) {
|
||||
self.count_down.start(Milliseconds(ms));
|
||||
nb::block!(self.count_down.wait()).unwrap();
|
||||
@@ -535,38 +512,29 @@ impl PhyRst {
|
||||
};
|
||||
|
||||
// Setup GPIO output mask
|
||||
self_.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.mask(gpio_output_mask)
|
||||
});
|
||||
self_.regs.gpio_output_mask.modify(|_, w| w.mask(gpio_output_mask));
|
||||
|
||||
self_.regs.gpio_direction.modify(|_, w| w.phy_rst(true));
|
||||
|
||||
self_.regs.gpio_direction.modify(|_, w| {
|
||||
w.phy_rst(true)
|
||||
});
|
||||
|
||||
self_
|
||||
}
|
||||
|
||||
fn oe(&mut self, oe: bool) {
|
||||
self.regs.gpio_output_enable.modify(|_, w| {
|
||||
w.phy_rst(oe)
|
||||
})
|
||||
self.regs.gpio_output_enable.modify(|_, w| w.phy_rst(oe))
|
||||
}
|
||||
|
||||
fn toggle(&mut self, o: bool) {
|
||||
self.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.phy_rst(o)
|
||||
})
|
||||
self.regs.gpio_output_mask.modify(|_, w| w.phy_rst(o))
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.toggle(false); // drive phy_rst (active LOW) pin low
|
||||
self.oe(true); // enable pin's output
|
||||
self.oe(true); // enable pin's output
|
||||
self.delay_ms(10);
|
||||
self.toggle(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct EthInner<GEM: Gem> {
|
||||
gem: PhantomData<GEM>,
|
||||
link: Option<phy::Link>,
|
||||
@@ -576,14 +544,16 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
fn init(&mut self) {
|
||||
// Clear the Network Control register.
|
||||
GEM::regs().net_ctrl.write(regs::NetCtrl::zeroed());
|
||||
GEM::regs().net_ctrl.write(regs::NetCtrl::zeroed().clear_stat_regs(true));
|
||||
GEM::regs()
|
||||
.net_ctrl
|
||||
.write(regs::NetCtrl::zeroed().clear_stat_regs(true));
|
||||
// Clear the Status registers.
|
||||
GEM::regs().rx_status.write(
|
||||
regs::RxStatus::zeroed()
|
||||
.buffer_not_avail(true)
|
||||
.frame_recd(true)
|
||||
.rx_overrun(true)
|
||||
.hresp_not_ok(true)
|
||||
.hresp_not_ok(true),
|
||||
);
|
||||
GEM::regs().tx_status.write(
|
||||
regs::TxStatus::zeroed()
|
||||
@@ -596,7 +566,7 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
.tx_under_run(true)
|
||||
.late_collision(true)
|
||||
// not in the manual:
|
||||
.hresp_not_ok(true)
|
||||
.hresp_not_ok(true),
|
||||
);
|
||||
// Disable all interrupts.
|
||||
GEM::regs().intr_dis.write(
|
||||
@@ -626,15 +596,11 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
.pdelay_resp_rx(true)
|
||||
.pdelay_req_tx(true)
|
||||
.pdelay_resp_tx(true)
|
||||
.tsu_sec_incr(true)
|
||||
.tsu_sec_incr(true),
|
||||
);
|
||||
// Clear the buffer queues.
|
||||
GEM::regs().rx_qbar.write(
|
||||
regs::RxQbar::zeroed()
|
||||
);
|
||||
GEM::regs().tx_qbar.write(
|
||||
regs::TxQbar::zeroed()
|
||||
);
|
||||
GEM::regs().rx_qbar.write(regs::RxQbar::zeroed());
|
||||
GEM::regs().tx_qbar.write(regs::TxQbar::zeroed());
|
||||
}
|
||||
|
||||
fn configure(&mut self, macaddr: [u8; 6]) {
|
||||
@@ -658,27 +624,22 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
// RX checksum offload
|
||||
.rx_chksum_offld_en(true)
|
||||
// One of the slower speeds
|
||||
.mdc_clk_div((mdc_clk_div >> 4).min(0b111) as u8)
|
||||
.mdc_clk_div((mdc_clk_div >> 4).min(0b111) as u8),
|
||||
);
|
||||
|
||||
let macaddr_msbs =
|
||||
(u16::from(macaddr[5]) << 8) |
|
||||
u16::from(macaddr[4]);
|
||||
let macaddr_lsbs =
|
||||
(u32::from(macaddr[3]) << 24) |
|
||||
(u32::from(macaddr[2]) << 16) |
|
||||
(u32::from(macaddr[1]) << 8) |
|
||||
u32::from(macaddr[0]);
|
||||
let macaddr_msbs = (u16::from(macaddr[5]) << 8) | u16::from(macaddr[4]);
|
||||
let macaddr_lsbs = (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)
|
||||
);
|
||||
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()
|
||||
.spec_addr1_top
|
||||
.write(regs::SpecAddrTop::zeroed().addr_msbs(macaddr_msbs));
|
||||
|
||||
GEM::regs().dma_cfg.write(
|
||||
regs::DmaCfg::zeroed()
|
||||
@@ -693,21 +654,16 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
// Little-endian
|
||||
.ahb_endian_swp_mgmt_en(false)
|
||||
// INCR16 AHB burst
|
||||
.ahb_fixed_burst_len(0x10)
|
||||
.ahb_fixed_burst_len(0x10),
|
||||
);
|
||||
|
||||
GEM::regs().net_ctrl.write(
|
||||
regs::NetCtrl::zeroed()
|
||||
.mgmt_port_en(true)
|
||||
);
|
||||
GEM::regs().net_ctrl.write(regs::NetCtrl::zeroed().mgmt_port_en(true));
|
||||
}
|
||||
|
||||
|
||||
fn wait_phy_idle(&self) {
|
||||
while !GEM::regs().net_status.read().phy_mgmt_idle() {}
|
||||
}
|
||||
|
||||
|
||||
fn check_link_change(&mut self, phy: &Phy) -> Option<Option<phy::Link>> {
|
||||
let link = phy.get_link(self);
|
||||
|
||||
@@ -724,18 +680,17 @@ impl<GEM: Gem> EthInner<GEM> {
|
||||
S1000 => TX_1000,
|
||||
};
|
||||
GEM::setup_clock(txclock);
|
||||
GEM::regs().net_cfg.modify(|_, w| w
|
||||
.full_duplex(link.duplex == Full)
|
||||
.gige_en(link.speed == S1000)
|
||||
.speed(link.speed != S10)
|
||||
);
|
||||
GEM::regs().net_cfg.modify(|_, w| {
|
||||
w.full_duplex(link.duplex == Full)
|
||||
.gige_en(link.speed == S1000)
|
||||
.speed(link.speed != S10)
|
||||
});
|
||||
}
|
||||
None => {
|
||||
warn!("eth: link lost");
|
||||
phy.modify_control(self, |control|
|
||||
control.set_autoneg_enable(true)
|
||||
.set_restart_autoneg(true)
|
||||
);
|
||||
phy.modify_control(self, |control| {
|
||||
control.set_autoneg_enable(true).set_restart_autoneg(true)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,7 +711,7 @@ impl<GEM: Gem> PhyAccess for EthInner<GEM> {
|
||||
.operation(regs::PhyOperation::Read)
|
||||
.phy_addr(addr)
|
||||
.reg_addr(reg)
|
||||
.must_10(0b10)
|
||||
.must_10(0b10),
|
||||
);
|
||||
self.wait_phy_idle();
|
||||
GEM::regs().phy_maint.read().data()
|
||||
@@ -771,10 +726,8 @@ impl<GEM: Gem> PhyAccess for EthInner<GEM> {
|
||||
.phy_addr(addr)
|
||||
.reg_addr(reg)
|
||||
.must_10(0b10)
|
||||
.data(data)
|
||||
.data(data),
|
||||
);
|
||||
self.wait_phy_idle();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use bit_field::BitField;
|
||||
|
||||
use super::PhyRegister;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -82,7 +83,7 @@ impl PhyRegister for Control {
|
||||
fn addr() -> u8 {
|
||||
0
|
||||
}
|
||||
|
||||
|
||||
fn page() -> u8 {
|
||||
0
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ use bit_field::BitField;
|
||||
|
||||
use super::PhyAccess;
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PhyIdentifier {
|
||||
pub oui: u32,
|
||||
@@ -13,7 +12,7 @@ pub struct PhyIdentifier {
|
||||
pub fn identify_phy<PA: PhyAccess>(pa: &mut PA, addr: u8) -> Option<PhyIdentifier> {
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
pa.write_phy(addr, 0x16, 0); //reset page
|
||||
|
||||
|
||||
let id1 = pa.read_phy(addr, 2);
|
||||
let id2 = pa.read_phy(addr, 3);
|
||||
if id1 != 0xFFFF || id2 != 0xFFFF {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use bit_field::BitField;
|
||||
use super::{PhyRegister, Led0Control, Led1Control};
|
||||
|
||||
use super::{Led0Control, Led1Control, PhyRegister};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// LED Control Register
|
||||
@@ -24,7 +25,7 @@ impl Leds {
|
||||
0b1101 => Led0Control::Mode2,
|
||||
0b1110 => Led0Control::Mode3,
|
||||
0b1111 => Led0Control::Mode4,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn led1(&self) -> Led1Control {
|
||||
@@ -41,7 +42,7 @@ impl Leds {
|
||||
0b1001 => Led1Control::ForceOn,
|
||||
0b1010 => Led1Control::ForceHiZ,
|
||||
0b1011 => Led1Control::ForceBlink,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ impl PhyRegister for Leds {
|
||||
fn addr() -> u8 {
|
||||
0x10
|
||||
}
|
||||
|
||||
|
||||
fn page() -> u8 {
|
||||
3
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
pub mod id;
|
||||
use id::{identify_phy, PhyIdentifier};
|
||||
use id::{PhyIdentifier, identify_phy};
|
||||
mod status;
|
||||
pub use status::Status;
|
||||
mod control;
|
||||
@@ -45,7 +45,7 @@ pub enum Led0Control {
|
||||
Mode1 = 0b1100,
|
||||
Mode2 = 0b1101,
|
||||
Mode3 = 0b1110,
|
||||
Mode4 = 0b1111
|
||||
Mode4 = 0b1111,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
@@ -74,7 +74,6 @@ pub trait PhyRegister {
|
||||
fn page() -> u8;
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Phy {
|
||||
pub addr: u8,
|
||||
@@ -82,51 +81,53 @@ pub struct Phy {
|
||||
|
||||
const OUI_MARVELL: u32 = 0x005043;
|
||||
const OUI_REALTEK: u32 = 0x000732;
|
||||
const OUI_LANTIQ : u32 = 0x355969;
|
||||
const OUI_ICPLUS : u32 = 0x0090c3;
|
||||
const OUI_LANTIQ: u32 = 0x355969;
|
||||
const OUI_ICPLUS: u32 = 0x0090c3;
|
||||
|
||||
//only change pages on Kasli-SoC's Marvel 88E11xx
|
||||
#[cfg(feature="target_kasli_soc")]
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
const PAGE_REGISTER: u8 = 0x16;
|
||||
|
||||
impl Phy {
|
||||
/// Probe all addresses on MDIO for a known PHY
|
||||
pub fn find<PA: PhyAccess>(pa: &mut PA) -> Option<Phy> {
|
||||
(0..32).find(|addr| {
|
||||
match identify_phy(pa, *addr) {
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_MARVELL,
|
||||
// Marvell 88E1116R
|
||||
model: 36,
|
||||
..
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_MARVELL,
|
||||
// Marvell 88E1512
|
||||
model: 29,
|
||||
..
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_REALTEK,
|
||||
// RTL 8211E
|
||||
model: 0b010001,
|
||||
rev: 0b0101,
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_LANTIQ,
|
||||
// Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6
|
||||
model: 0,
|
||||
..
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_ICPLUS,
|
||||
// IP101G-DS-R01
|
||||
model: 5,
|
||||
rev: 4,
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
}).map(|addr| Phy { addr })
|
||||
(0..32)
|
||||
.find(|addr| {
|
||||
match identify_phy(pa, *addr) {
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_MARVELL,
|
||||
// Marvell 88E1116R
|
||||
model: 36,
|
||||
..
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_MARVELL,
|
||||
// Marvell 88E1512
|
||||
model: 29,
|
||||
..
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_REALTEK,
|
||||
// RTL 8211E
|
||||
model: 0b010001,
|
||||
rev: 0b0101,
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_LANTIQ,
|
||||
// Intel XWAY PHY11G (PEF 7071/PEF 7072) v1.5 / v1.6
|
||||
model: 0,
|
||||
..
|
||||
}) => true,
|
||||
Some(PhyIdentifier {
|
||||
oui: OUI_ICPLUS,
|
||||
// IP101G-DS-R01
|
||||
model: 5,
|
||||
rev: 4,
|
||||
}) => true,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
.map(|addr| Phy { addr })
|
||||
}
|
||||
|
||||
pub fn read_reg<PA, PR>(&self, pa: &mut PA) -> PR
|
||||
@@ -134,7 +135,7 @@ impl Phy {
|
||||
PA: PhyAccess,
|
||||
PR: PhyRegister + From<u16>,
|
||||
{
|
||||
#[cfg(feature="target_kasli_soc")]
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
pa.write_phy(self.addr, PAGE_REGISTER, PR::page().into());
|
||||
|
||||
pa.read_phy(self.addr, PR::addr()).into()
|
||||
@@ -146,9 +147,9 @@ impl Phy {
|
||||
PR: PhyRegister + From<u16> + Into<u16>,
|
||||
F: FnMut(PR) -> PR,
|
||||
{
|
||||
#[cfg(feature="target_kasli_soc")]
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
pa.write_phy(self.addr, PAGE_REGISTER, PR::page().into());
|
||||
|
||||
|
||||
let reg = pa.read_phy(self.addr, PR::addr()).into();
|
||||
let reg = f(reg);
|
||||
pa.write_phy(self.addr, PR::addr(), reg.into())
|
||||
@@ -167,7 +168,7 @@ impl Phy {
|
||||
PA: PhyAccess,
|
||||
F: FnMut(Leds) -> Leds,
|
||||
{
|
||||
self.modify_reg(pa, f)
|
||||
self.modify_reg(pa, f)
|
||||
}
|
||||
|
||||
pub fn get_control<PA: PhyAccess>(&self, pa: &mut PA) -> Control {
|
||||
@@ -191,24 +192,19 @@ impl Phy {
|
||||
}
|
||||
|
||||
pub fn reset<PA: PhyAccess>(&self, pa: &mut PA) {
|
||||
self.modify_control(pa, |control|
|
||||
control.set_reset(true)
|
||||
);
|
||||
self.modify_control(pa, |control| control.set_reset(true));
|
||||
while self.get_control(pa).reset() {}
|
||||
}
|
||||
|
||||
pub fn restart_autoneg<PA: PhyAccess>(&self, pa: &mut PA) {
|
||||
self.modify_control(pa, |control|
|
||||
control.set_autoneg_enable(true)
|
||||
.set_restart_autoneg(true)
|
||||
);
|
||||
self.modify_control(pa, |control| control.set_autoneg_enable(true).set_restart_autoneg(true));
|
||||
}
|
||||
|
||||
#[cfg(feature="target_kasli_soc")]
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
pub fn set_leds<PA: PhyAccess>(&self, pa: &mut PA) {
|
||||
self.modify_leds(pa, |leds|
|
||||
self.modify_leds(pa, |leds| {
|
||||
leds.set_led0(Led0Control::OnCopperLinkOffElse)
|
||||
.set_led1(Led1Control::BlinkActivityOffNoActivity)
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use bit_field::BitField;
|
||||
use super::{PhyRegister, Link, LinkDuplex, LinkSpeed};
|
||||
|
||||
use super::{Link, LinkDuplex, LinkSpeed, PhyRegister};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// PHY-Specific Status Register
|
||||
@@ -43,7 +44,7 @@ impl PhyRegister for PSSR {
|
||||
fn addr() -> u8 {
|
||||
0x11
|
||||
}
|
||||
|
||||
|
||||
fn page() -> u8 {
|
||||
0
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use bit_field::BitField;
|
||||
use super::{PhyRegister, Link, LinkDuplex, LinkSpeed};
|
||||
|
||||
use super::{Link, LinkDuplex, LinkSpeed, PhyRegister};
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
/// Basic Mode Status Register
|
||||
@@ -53,7 +54,7 @@ impl Status {
|
||||
}
|
||||
|
||||
pub fn get_link(&self) -> Option<Link> {
|
||||
if ! self.link_status() {
|
||||
if !self.link_status() {
|
||||
None
|
||||
} else if self.cap_100base_tx_full() {
|
||||
Some(Link {
|
||||
@@ -100,7 +101,7 @@ impl PhyRegister for Status {
|
||||
fn addr() -> u8 {
|
||||
1
|
||||
}
|
||||
|
||||
|
||||
fn page() -> u8 {
|
||||
0
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use volatile_register::{RO, WO, RW};
|
||||
|
||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
use volatile_register::{RO, RW, WO};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
@@ -126,17 +125,16 @@ impl GpioRegisterBlock {
|
||||
}
|
||||
}
|
||||
|
||||
register!(gpio_output_mask,
|
||||
register!(gpio_output_mask,
|
||||
/// MASK_DATA_1_SW:
|
||||
/// Maskable output data for MIO[47:32]
|
||||
OutputMask, RW, u32);
|
||||
register_at!(OutputMask, 0xE000A008, new);
|
||||
register_bit!(gpio_output_mask,
|
||||
register_bit!(gpio_output_mask,
|
||||
/// Output for PHY_RST (MIO[47])
|
||||
phy_rst, 15);
|
||||
register_bits!(gpio_output_mask,
|
||||
mask, u16, 16, 31);
|
||||
register!(gpio_direction,
|
||||
register_bits!(gpio_output_mask, mask, u16, 16, 31);
|
||||
register!(gpio_direction,
|
||||
/// DIRM_1:
|
||||
/// Direction mode for MIO[53:32]; 0/1 = in/out
|
||||
Direction, RW, u32);
|
||||
@@ -152,7 +150,7 @@ register_at!(OutputEnable, 0xE000A248, new);
|
||||
register_bit!(gpio_output_enable,
|
||||
/// Output enable for PHY_RST
|
||||
phy_rst, 15);
|
||||
|
||||
|
||||
register_at!(RegisterBlock, 0xE000B000, gem0);
|
||||
register_at!(RegisterBlock, 0xE000C000, gem1);
|
||||
|
||||
@@ -332,7 +330,7 @@ register_bit!(intr_dis, tsu_sec_incr, 26);
|
||||
#[repr(u8)]
|
||||
pub enum PhyOperation {
|
||||
Write = 0b01,
|
||||
Read = 0b10,
|
||||
Read = 0b10,
|
||||
}
|
||||
|
||||
register!(phy_maint, PhyMaint, RW, u32);
|
||||
@@ -352,9 +350,7 @@ register_bits_typed!(phy_maint, operation, u8, PhyOperation, 28, 29);
|
||||
register_bit!(phy_maint, clause_22, 30);
|
||||
|
||||
register!(spec_addr_top, SpecAddrTop, RW, u32);
|
||||
register_bits!(spec_addr_top,
|
||||
addr_msbs, u16, 0, 15);
|
||||
register_bits!(spec_addr_top, addr_msbs, u16, 0, 15);
|
||||
|
||||
register!(spec_addr_bot, SpecAddrBot, RW, u32);
|
||||
register_bits!(spec_addr_bot,
|
||||
addr_lsbs, u32, 0, 31);
|
||||
register_bits!(spec_addr_bot, addr_lsbs, u32, 0, 31);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use core::ops::Deref;
|
||||
use alloc::{vec, vec::Vec};
|
||||
use libcortex_a9::{asm::*, cache::*, UncachedSlice};
|
||||
use core::ops::Deref;
|
||||
|
||||
use libcortex_a9::{UncachedSlice, asm::*, cache::*};
|
||||
use libregister::*;
|
||||
|
||||
use super::Buffer;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -22,8 +24,12 @@ pub struct DescEntry {
|
||||
impl DescEntry {
|
||||
pub fn zeroed() -> Self {
|
||||
DescEntry {
|
||||
word0: DescWord0 { inner: VolatileCell::new(0) },
|
||||
word1: DescWord1 { inner: VolatileCell::new(0) },
|
||||
word0: DescWord0 {
|
||||
inner: VolatileCell::new(0),
|
||||
},
|
||||
word1: DescWord1 {
|
||||
inner: VolatileCell::new(0),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,8 +69,7 @@ pub struct DescList {
|
||||
|
||||
impl DescList {
|
||||
pub fn new(size: usize) -> Self {
|
||||
let mut list = UncachedSlice::new(size, || DescEntry::zeroed())
|
||||
.unwrap();
|
||||
let mut list = UncachedSlice::new(size, || DescEntry::zeroed()).unwrap();
|
||||
let mut buffers = vec![Buffer::new(); size];
|
||||
|
||||
let last = list.len().min(buffers.len()) - 1;
|
||||
@@ -72,25 +77,16 @@ impl DescList {
|
||||
let is_last = i == last;
|
||||
let buffer_addr = &mut buffer.0[0] as *mut _ as u32;
|
||||
assert!(buffer_addr & 0b11 == 0);
|
||||
entry.word0.write(
|
||||
DescWord0::zeroed()
|
||||
.used(false)
|
||||
.wrap(is_last)
|
||||
.address(buffer_addr >> 2)
|
||||
);
|
||||
entry.word1.write(
|
||||
DescWord1::zeroed()
|
||||
);
|
||||
entry
|
||||
.word0
|
||||
.write(DescWord0::zeroed().used(false).wrap(is_last).address(buffer_addr >> 2));
|
||||
entry.word1.write(DescWord1::zeroed());
|
||||
// Flush buffer from cache, to be filled by the peripheral
|
||||
// before next read
|
||||
dcci_slice(&buffer[..]);
|
||||
}
|
||||
|
||||
DescList {
|
||||
list,
|
||||
buffers,
|
||||
next: 0,
|
||||
}
|
||||
DescList { list, buffers, next: 0 }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
@@ -110,11 +106,7 @@ impl DescList {
|
||||
let len = word1.frame_length_lsbs().into();
|
||||
let padding = {
|
||||
let diff = len % 0x20;
|
||||
if diff == 0 {
|
||||
0
|
||||
} else {
|
||||
0x20 - diff
|
||||
}
|
||||
if diff == 0 { 0 } else { 0x20 - diff }
|
||||
};
|
||||
unsafe {
|
||||
// invalidate the buffer
|
||||
@@ -163,9 +155,7 @@ impl<'a> Deref for PktRef<'a> {
|
||||
|
||||
impl<'a> smoltcp::phy::RxToken for PktRef<'a> {
|
||||
fn consume<R, F>(self, _timestamp: smoltcp::time::Instant, f: F) -> smoltcp::Result<R>
|
||||
where
|
||||
F: FnOnce(&mut [u8]) -> smoltcp::Result<R>
|
||||
{
|
||||
where F: FnOnce(&mut [u8]) -> smoltcp::Result<R> {
|
||||
f(self.buffer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use libcortex_a9::{cache::dcc_slice, UncachedSlice};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
|
||||
use libcortex_a9::{UncachedSlice, cache::dcc_slice};
|
||||
use libregister::*;
|
||||
|
||||
use super::{Buffer, regs};
|
||||
|
||||
/// Descriptor entry
|
||||
@@ -32,8 +34,12 @@ register_bit!(desc_word1,
|
||||
impl DescEntry {
|
||||
pub fn zeroed() -> Self {
|
||||
DescEntry {
|
||||
word0: DescWord0 { inner: VolatileCell::new(0) },
|
||||
word1: DescWord1 { inner: VolatileCell::new(0) },
|
||||
word0: DescWord0 {
|
||||
inner: VolatileCell::new(0),
|
||||
},
|
||||
word1: DescWord1 {
|
||||
inner: VolatileCell::new(0),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,8 +56,7 @@ pub struct DescList {
|
||||
|
||||
impl DescList {
|
||||
pub fn new(size: usize) -> Self {
|
||||
let mut list = UncachedSlice::new(size, || DescEntry::zeroed())
|
||||
.unwrap();
|
||||
let mut list = UncachedSlice::new(size, || DescEntry::zeroed()).unwrap();
|
||||
let mut buffers = vec![Buffer::new(); size];
|
||||
|
||||
let last = list.len().min(buffers.len()) - 1;
|
||||
@@ -65,24 +70,17 @@ impl DescList {
|
||||
let is_last = i == last;
|
||||
let buffer_addr = &mut buffer.0[0] as *mut _ as u32;
|
||||
assert!(buffer_addr & 0b11 == 0);
|
||||
entry.word0.write(
|
||||
DescWord0::zeroed()
|
||||
.address(buffer_addr)
|
||||
);
|
||||
entry.word0.write(DescWord0::zeroed().address(buffer_addr));
|
||||
entry.word1.write(
|
||||
DescWord1::zeroed()
|
||||
.used(true)
|
||||
.wrap(is_last)
|
||||
// every frame contains 1 packet
|
||||
.last_buffer(true)
|
||||
.last_buffer(true),
|
||||
);
|
||||
}
|
||||
|
||||
DescList {
|
||||
list,
|
||||
buffers,
|
||||
next: 0,
|
||||
}
|
||||
DescList { list, buffers, next: 0 }
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
@@ -98,11 +96,12 @@ impl DescList {
|
||||
let entry = &mut self.list[self.next];
|
||||
if entry.word1.read().used() {
|
||||
let buffer = &mut self.buffers[self.next][0..length];
|
||||
entry.word1.write(DescWord1::zeroed()
|
||||
.length(length as u16)
|
||||
.last_buffer(true)
|
||||
.wrap(self.next >= list_len - 1)
|
||||
.used(true)
|
||||
entry.word1.write(
|
||||
DescWord1::zeroed()
|
||||
.length(length as u16)
|
||||
.last_buffer(true)
|
||||
.wrap(self.next >= list_len - 1)
|
||||
.used(true),
|
||||
);
|
||||
|
||||
self.next += 1;
|
||||
@@ -158,14 +157,10 @@ pub struct Token<'a> {
|
||||
|
||||
impl<'a> smoltcp::phy::TxToken for Token<'a> {
|
||||
fn consume<R, F>(self, _timestamp: smoltcp::time::Instant, len: usize, f: F) -> smoltcp::Result<R>
|
||||
where F: FnOnce(&mut [u8]) -> smoltcp::Result<R>
|
||||
{
|
||||
where F: FnOnce(&mut [u8]) -> smoltcp::Result<R> {
|
||||
match self.desc_list.send(self.regs, len) {
|
||||
None =>
|
||||
Err(smoltcp::Error::Exhausted),
|
||||
Some(mut pktref) => {
|
||||
f(pktref.deref_mut())
|
||||
}
|
||||
None => Err(smoltcp::Error::Exhausted),
|
||||
Some(mut pktref) => f(pktref.deref_mut()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
//! ARM Generic Interrupt Controller
|
||||
|
||||
use bit_field::BitField;
|
||||
use libregister::{RegisterW, RegisterRW, RegisterR};
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||
|
||||
use super::mpcore;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -11,7 +12,7 @@ pub struct InterruptId(pub u8);
|
||||
#[repr(u8)]
|
||||
pub enum CPUCore {
|
||||
Core0 = 0b01,
|
||||
Core1 = 0b10
|
||||
Core1 = 0b10,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -36,7 +37,7 @@ impl From<CPUCore> for TargetCPU {
|
||||
pub enum TargetList {
|
||||
CPUList(TargetCPU),
|
||||
Others,
|
||||
This
|
||||
This,
|
||||
}
|
||||
|
||||
impl From<CPUCore> for TargetList {
|
||||
@@ -67,8 +68,7 @@ impl InterruptController {
|
||||
}
|
||||
|
||||
pub fn disable_interrupts(&mut self) {
|
||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(false)
|
||||
.enable_s(false));
|
||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(false).enable_s(false));
|
||||
// FIXME: Should we disable the distributor globally when we disable interrupt (for a single
|
||||
// core)?
|
||||
// self.mpcore.icddcr.modify(|_, w| w.enable_secure(false)
|
||||
@@ -77,8 +77,7 @@ impl InterruptController {
|
||||
|
||||
/// enable interrupt signaling
|
||||
pub fn enable_interrupts(&mut self) {
|
||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true)
|
||||
.enable_s(true));
|
||||
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true).enable_s(true));
|
||||
self.mpcore.icddcr.modify(|_, w| w.enable_secure(true));
|
||||
|
||||
// Enable all interrupts except those of the lowest priority.
|
||||
@@ -88,11 +87,15 @@ impl InterruptController {
|
||||
/// send software generated interrupt
|
||||
pub fn send_sgi(&mut self, id: InterruptId, targets: TargetList) {
|
||||
assert!(id.0 < 16);
|
||||
self.mpcore.icdsgir.modify(|_, w| match targets {
|
||||
TargetList::CPUList(list) => w.target_list_filter(0).cpu_target_list(list.0),
|
||||
TargetList::Others => w.target_list_filter(0b01),
|
||||
TargetList::This => w.target_list_filter(0b10)
|
||||
}.sgiintid(id.0).satt(false));
|
||||
self.mpcore.icdsgir.modify(|_, w| {
|
||||
match targets {
|
||||
TargetList::CPUList(list) => w.target_list_filter(0).cpu_target_list(list.0),
|
||||
TargetList::Others => w.target_list_filter(0b01),
|
||||
TargetList::This => w.target_list_filter(0b10),
|
||||
}
|
||||
.sgiintid(id.0)
|
||||
.satt(false)
|
||||
});
|
||||
}
|
||||
|
||||
/// enable the interrupt *for this core*.
|
||||
@@ -115,17 +118,22 @@ impl InterruptController {
|
||||
let m = (id.0 >> 2) as usize;
|
||||
let n = (8 * (id.0 & 3)) as usize;
|
||||
unsafe {
|
||||
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32));
|
||||
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n + 1, target_cpu as u32));
|
||||
}
|
||||
|
||||
// sensitivity
|
||||
let m = (id.0 >> 4) as usize;
|
||||
let n = (2 * (id.0 & 0xF)) as usize;
|
||||
unsafe {
|
||||
self.mpcore.icdicfr[m].modify(|mut icdicfr| *icdicfr.set_bits(n..=n+1, match sensitivity {
|
||||
InterruptSensitivity::Level => 0b00,
|
||||
InterruptSensitivity::Edge => 0b10,
|
||||
}));
|
||||
self.mpcore.icdicfr[m].modify(|mut icdicfr| {
|
||||
*icdicfr.set_bits(
|
||||
n..=n + 1,
|
||||
match sensitivity {
|
||||
InterruptSensitivity::Level => 0b00,
|
||||
InterruptSensitivity::Edge => 0b10,
|
||||
},
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
// priority
|
||||
@@ -146,5 +154,4 @@ impl InterruptController {
|
||||
pub fn get_interrupt_id(&self) -> InterruptId {
|
||||
InterruptId(self.mpcore.icciar.read().ackintid() as u8)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
use super::{I2c, Error};
|
||||
use crate::time::Milliseconds;
|
||||
use embedded_hal::timer::CountDown;
|
||||
|
||||
use super::{Error, I2c};
|
||||
use crate::time::Milliseconds;
|
||||
|
||||
pub struct EEPROM<'a> {
|
||||
i2c: &'a mut I2c,
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
port: u8,
|
||||
address: u8,
|
||||
page_size: u8,
|
||||
count_down: crate::timer::global::CountDown<Milliseconds>
|
||||
count_down: crate::timer::global::CountDown<Milliseconds>,
|
||||
}
|
||||
|
||||
impl<'a> EEPROM<'a> {
|
||||
@@ -19,7 +20,7 @@ impl<'a> EEPROM<'a> {
|
||||
port: 2,
|
||||
address: 0b1010100,
|
||||
page_size: page_size,
|
||||
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown()
|
||||
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +31,7 @@ impl<'a> EEPROM<'a> {
|
||||
port: 3,
|
||||
address: 0x57,
|
||||
page_size: page_size,
|
||||
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown()
|
||||
count_down: unsafe { crate::timer::GlobalTimer::get() }.countdown(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,8 +75,8 @@ impl<'a> EEPROM<'a> {
|
||||
|
||||
/// Smart multi-page writing
|
||||
/// Using the "Page Write" function of an EEPROM, the memory region for each transaction
|
||||
/// (i.e. from byte `addr` to byte `addr+buf.len()`) should fit under each page
|
||||
/// (i.e. `addr+buf.len()` < `addr/self.page_size+1`); otherwise, a roll-oever occurs,
|
||||
/// (i.e. from byte `addr` to byte `addr+buf.len()`) should fit under each page
|
||||
/// (i.e. `addr+buf.len()` < `addr/self.page_size+1`); otherwise, a roll-oever occurs,
|
||||
/// where bytes beyond the page end. This smart function takes care of the scenario to avoid
|
||||
/// any roll-over when writing ambiguous memory regions.
|
||||
pub fn write(&mut self, addr: u8, buf: &[u8]) -> Result<(), Error> {
|
||||
@@ -92,7 +93,7 @@ impl<'a> EEPROM<'a> {
|
||||
self.i2c.write(*byte)?;
|
||||
pb += 1;
|
||||
|
||||
if (i == buf_len-1) || (pb == self.page_size) {
|
||||
if (i == buf_len - 1) || (pb == self.page_size) {
|
||||
self.i2c.stop()?;
|
||||
self.poll(1_000)?;
|
||||
pb = 0;
|
||||
@@ -114,10 +115,10 @@ impl<'a> EEPROM<'a> {
|
||||
match res {
|
||||
Ok(()) => break,
|
||||
Err(Error::Nack) => (),
|
||||
Err(e) => return Err(e)
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
if !self.count_down.waiting() {
|
||||
return Err(Error::PollingTimeout)
|
||||
return Err(Error::PollingTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,4 +130,4 @@ impl<'a> EEPROM<'a> {
|
||||
self.read(0xFA, &mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
//! I2C Bit-banging Controller
|
||||
|
||||
mod regs;
|
||||
pub mod eeprom;
|
||||
mod regs;
|
||||
use embedded_hal::timer::CountDown;
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
use libregister::RegisterW;
|
||||
use libregister::{RegisterR, RegisterRW};
|
||||
use log::error;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use log::info;
|
||||
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
use super::slcr;
|
||||
use super::time::Microseconds;
|
||||
use embedded_hal::timer::CountDown;
|
||||
use libregister::{RegisterR, RegisterRW};
|
||||
#[cfg(not(feature = "target_ebaz4205"))]
|
||||
use libregister::RegisterW;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use log::info;
|
||||
use log::error;
|
||||
|
||||
pub enum I2cMultiplexer {
|
||||
PCA9548 = 0,
|
||||
@@ -47,7 +48,7 @@ impl From<Error> for &str {
|
||||
pub struct I2c {
|
||||
regs: regs::RegisterBlock,
|
||||
count_down: super::timer::global::CountDown<Microseconds>,
|
||||
pca_type: I2cMultiplexer
|
||||
pca_type: I2cMultiplexer,
|
||||
}
|
||||
|
||||
impl I2c {
|
||||
@@ -59,18 +60,18 @@ impl I2c {
|
||||
// SCL
|
||||
slcr.mio_pin_50.write(
|
||||
slcr::MioPin50::zeroed()
|
||||
.l3_sel(0b000) // as GPIO 50
|
||||
.l3_sel(0b000) // as GPIO 50
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// SDA
|
||||
slcr.mio_pin_51.write(
|
||||
slcr::MioPin51::zeroed()
|
||||
.l3_sel(0b000) // as GPIO 51
|
||||
.l3_sel(0b000) // as GPIO 51
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
// On Kasli-SoC prototype, leakage through the unconfigured I2C_SW_RESET
|
||||
// MIO pin develops enough voltage on the T21 gate to assert the reset.
|
||||
@@ -81,7 +82,7 @@ impl I2c {
|
||||
.l3_sel(0b000)
|
||||
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||
.pullup(false)
|
||||
.disable_rcvr(true)
|
||||
.disable_rcvr(true),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -93,27 +94,22 @@ impl I2c {
|
||||
let self_ = Self {
|
||||
regs: regs::RegisterBlock::i2c(),
|
||||
count_down: unsafe { super::timer::GlobalTimer::get() }.countdown(),
|
||||
pca_type: I2cMultiplexer::PCA9548 //default for zc706
|
||||
pca_type: I2cMultiplexer::PCA9548, //default for zc706
|
||||
};
|
||||
|
||||
// Setup GPIO output mask
|
||||
self_.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.mask(gpio_output_mask)
|
||||
});
|
||||
self_.regs.gpio_output_mask.modify(|_, w| w.mask(gpio_output_mask));
|
||||
// Setup GPIO driver direction
|
||||
self_.regs.gpio_direction.modify(|_, w| {
|
||||
w.scl(true).sda(true)
|
||||
});
|
||||
self_.regs.gpio_direction.modify(|_, w| w.scl(true).sda(true));
|
||||
|
||||
//Kasli-SoC only: I2C_SW_RESET configuration
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
{
|
||||
self_.regs.gpio_output_mask_lower.modify(|_, w| {
|
||||
w.mask(_gpio_output_mask_lower)
|
||||
});
|
||||
self_.regs.gpio_direction.modify(|_, w| {
|
||||
w.i2cswr(true)
|
||||
});
|
||||
self_
|
||||
.regs
|
||||
.gpio_output_mask_lower
|
||||
.modify(|_, w| w.mask(_gpio_output_mask_lower));
|
||||
self_.regs.gpio_direction.modify(|_, w| w.i2cswr(true));
|
||||
}
|
||||
|
||||
self_
|
||||
@@ -125,7 +121,9 @@ impl I2c {
|
||||
nb::block!(self.count_down.wait()).unwrap();
|
||||
}
|
||||
|
||||
fn unit_delay(&mut self) { self.delay_us(100) }
|
||||
fn unit_delay(&mut self) {
|
||||
self.delay_us(100)
|
||||
}
|
||||
|
||||
fn sda_i(&mut self) -> bool {
|
||||
self.regs.gpio_input.read().sda()
|
||||
@@ -136,41 +134,29 @@ impl I2c {
|
||||
}
|
||||
|
||||
fn sda_oe(&mut self, oe: bool) {
|
||||
self.regs.gpio_output_enable.modify(|_, w| {
|
||||
w.sda(oe)
|
||||
})
|
||||
self.regs.gpio_output_enable.modify(|_, w| w.sda(oe))
|
||||
}
|
||||
|
||||
fn sda_o(&mut self, o: bool) {
|
||||
self.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.sda_o(o)
|
||||
})
|
||||
self.regs.gpio_output_mask.modify(|_, w| w.sda_o(o))
|
||||
}
|
||||
|
||||
fn scl_oe(&mut self, oe: bool) {
|
||||
self.regs.gpio_output_enable.modify(|_, w| {
|
||||
w.scl(oe)
|
||||
})
|
||||
self.regs.gpio_output_enable.modify(|_, w| w.scl(oe))
|
||||
}
|
||||
|
||||
fn scl_o(&mut self, o: bool) {
|
||||
self.regs.gpio_output_mask.modify(|_, w| {
|
||||
w.scl_o(o)
|
||||
})
|
||||
self.regs.gpio_output_mask.modify(|_, w| w.scl_o(o))
|
||||
}
|
||||
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
fn i2cswr_oe(&mut self, oe: bool) {
|
||||
self.regs.gpio_output_enable.modify(|_, w| {
|
||||
w.i2cswr(oe)
|
||||
})
|
||||
self.regs.gpio_output_enable.modify(|_, w| w.i2cswr(oe))
|
||||
}
|
||||
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
fn i2cswr_o(&mut self, o: bool) {
|
||||
self.regs.gpio_output_mask_lower.modify(|_, w| {
|
||||
w.i2cswr_o(o)
|
||||
})
|
||||
self.regs.gpio_output_mask_lower.modify(|_, w| w.i2cswr_o(o))
|
||||
}
|
||||
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
@@ -182,25 +168,30 @@ impl I2c {
|
||||
self.unit_delay();
|
||||
self.i2cswr_o(false);
|
||||
self.unit_delay();
|
||||
|
||||
|
||||
let pca954x_read_addr = (0x71 << 1) | 0x01;
|
||||
|
||||
self.start()?;
|
||||
// read the config register
|
||||
self.write(pca954x_read_addr).map_err(|err| {
|
||||
match err {
|
||||
Error::Nack => error!("PCA954X failed to ack read address"),
|
||||
_ => ()
|
||||
}
|
||||
err
|
||||
match err {
|
||||
Error::Nack => error!("PCA954X failed to ack read address"),
|
||||
_ => (),
|
||||
}
|
||||
)?;
|
||||
err
|
||||
})?;
|
||||
let config = self.read(false)?;
|
||||
|
||||
let pca = match config {
|
||||
0x00 => { info!("PCA9548 detected"); I2cMultiplexer::PCA9548 },
|
||||
0x08 => { info!("PCA9547 detected"); I2cMultiplexer::PCA9547 },
|
||||
_ => { return Err(Error::UnknownSwitch)},
|
||||
0x00 => {
|
||||
info!("PCA9548 detected");
|
||||
I2cMultiplexer::PCA9548
|
||||
}
|
||||
0x08 => {
|
||||
info!("PCA9547 detected");
|
||||
I2cMultiplexer::PCA9547
|
||||
}
|
||||
_ => return Err(Error::UnknownSwitch),
|
||||
};
|
||||
self.stop()?;
|
||||
Ok(pca)
|
||||
@@ -232,13 +223,13 @@ impl I2c {
|
||||
return Err(Error::SCLLow);
|
||||
}
|
||||
// postcondition: SCL and SDA high
|
||||
|
||||
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
{
|
||||
self.i2cswr_oe(true);
|
||||
self.pca_type = self.pca_autodetect()?;
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -319,7 +310,9 @@ impl I2c {
|
||||
self.unit_delay();
|
||||
self.scl_oe(false);
|
||||
self.unit_delay();
|
||||
if self.sda_i() { data |= 1 << bit }
|
||||
if self.sda_i() {
|
||||
data |= 1 << bit
|
||||
}
|
||||
self.scl_oe(true);
|
||||
}
|
||||
// Send ack/nack (true = nack, false = ack)
|
||||
@@ -340,29 +333,29 @@ impl I2c {
|
||||
// for compatibility, PCA9548 is treated as such too
|
||||
// channel - Some(x) - # of the channel [0,7], or None for all disabled
|
||||
let setting = match self.pca_type {
|
||||
I2cMultiplexer::PCA9548 => {
|
||||
match channel {
|
||||
Some(ch) => 1 << ch,
|
||||
None => 0,
|
||||
}
|
||||
I2cMultiplexer::PCA9548 => match channel {
|
||||
Some(ch) => 1 << ch,
|
||||
None => 0,
|
||||
},
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
I2cMultiplexer::PCA9547 => {
|
||||
match channel {
|
||||
Some(ch) => ch | 0x08,
|
||||
None => 0,
|
||||
}
|
||||
}
|
||||
I2cMultiplexer::PCA9547 => match channel {
|
||||
Some(ch) => ch | 0x08,
|
||||
None => 0,
|
||||
},
|
||||
};
|
||||
|
||||
let write_res = self.write(address << 1).or_else( |err| {
|
||||
let write_res = self
|
||||
.write(address << 1)
|
||||
.or_else(|err| {
|
||||
error!("PCA954X write address fail: {:?}", err);
|
||||
Err(err)
|
||||
}).and_then(|_| self.write(setting).or_else(|err| {
|
||||
error!("PCA954X control word fail: {:?}", err);
|
||||
Err(err)
|
||||
})
|
||||
);
|
||||
.and_then(|_| {
|
||||
self.write(setting).or_else(|err| {
|
||||
error!("PCA954X control word fail: {:?}", err);
|
||||
Err(err)
|
||||
})
|
||||
});
|
||||
let stop_res = self.stop();
|
||||
|
||||
write_res.and(stop_res)
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits
|
||||
};
|
||||
use libregister::{register, register_at, register_bit, register_bits};
|
||||
|
||||
// With reference to:
|
||||
//
|
||||
@@ -15,7 +12,7 @@ use libregister::{
|
||||
// self._in = CSRStatus(l)
|
||||
// self._out = CSRStorage(l, reset=reset_out)
|
||||
// self._oe = CSRStorage(l, reset=reset_oe)
|
||||
//
|
||||
//
|
||||
// Hence, using GPIOs as SCL and SDA GPIOs respectively.
|
||||
//
|
||||
// Current compatibility:
|
||||
@@ -64,7 +61,6 @@ register_bits!(gpio_output_mask,
|
||||
/// Mask for keeping bits except SCL and SDA unchanged
|
||||
mask, u16, 16, 31);
|
||||
|
||||
|
||||
register!(gpio_output_mask_lower,
|
||||
/// MASK_DATA_1_LSW:
|
||||
/// Maskable output data for MIO[47:32]
|
||||
@@ -76,8 +72,7 @@ register_bit!(gpio_output_mask_lower,
|
||||
/// Output for I2C_SW_RESET (MIO[33])
|
||||
i2cswr_o, 1);
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
register_bits!(gpio_output_mask_lower,
|
||||
mask, u16, 16, 31);
|
||||
register_bits!(gpio_output_mask_lower, mask, u16, 16, 31);
|
||||
|
||||
register!(gpio_input,
|
||||
/// DATA_1_RO:
|
||||
@@ -94,7 +89,6 @@ register_bit!(gpio_input,
|
||||
/// Input for SDA
|
||||
sda, 19);
|
||||
|
||||
|
||||
register!(gpio_direction,
|
||||
/// DIRM_1:
|
||||
/// Direction mode for MIO[53:32]; 0/1 = in/out
|
||||
@@ -132,4 +126,3 @@ register_bit!(gpio_output_enable,
|
||||
register_bit!(gpio_output_enable,
|
||||
/// Output enable for I2C_SW_RESET
|
||||
i2cswr, 1);
|
||||
|
||||
@@ -5,23 +5,23 @@ extern crate alloc;
|
||||
/// Re-export so that dependents can always use the same version
|
||||
pub use smoltcp;
|
||||
|
||||
pub mod slcr;
|
||||
pub mod clocks;
|
||||
pub mod uart;
|
||||
pub mod devc;
|
||||
pub mod stdio;
|
||||
pub mod eth;
|
||||
pub mod axi_hp;
|
||||
pub mod axi_gp;
|
||||
pub mod axi_hp;
|
||||
pub mod clocks;
|
||||
pub mod ddr;
|
||||
pub mod mpcore;
|
||||
pub mod devc;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
pub mod error_led;
|
||||
pub mod eth;
|
||||
pub mod gic;
|
||||
pub mod time;
|
||||
pub mod timer;
|
||||
pub mod sdio;
|
||||
#[cfg(any(feature = "target_zc706", feature = "target_kasli_soc", feature = "target_ebaz4205"))]
|
||||
pub mod i2c;
|
||||
pub mod logger;
|
||||
pub mod mpcore;
|
||||
pub mod ps7_init;
|
||||
#[cfg(feature="target_kasli_soc")]
|
||||
pub mod error_led;
|
||||
pub mod sdio;
|
||||
pub mod slcr;
|
||||
pub mod stdio;
|
||||
pub mod time;
|
||||
pub mod timer;
|
||||
pub mod uart;
|
||||
|
||||
@@ -17,14 +17,18 @@ impl log::Log for Logger {
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
if self.enabled(record.metadata()) {
|
||||
let timestamp = unsafe {
|
||||
GlobalTimer::get()
|
||||
}.get_us().0;
|
||||
let seconds = timestamp / 1_000_000;
|
||||
let micros = timestamp % 1_000_000;
|
||||
let timestamp = unsafe { GlobalTimer::get() }.get_us().0;
|
||||
let seconds = timestamp / 1_000_000;
|
||||
let micros = timestamp % 1_000_000;
|
||||
|
||||
println!("[{:6}.{:06}s] {:>5}({}): {}",
|
||||
seconds, micros, record.level(), record.target(), record.args());
|
||||
println!(
|
||||
"[{:6}.{:06}s] {:>5}({}): {}",
|
||||
seconds,
|
||||
micros,
|
||||
record.level(),
|
||||
record.target(),
|
||||
record.args()
|
||||
);
|
||||
}
|
||||
}
|
||||
fn flush(&self) {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
use libregister::{RegisterRW, RegisterW, register, register_at, register_bit, register_bits};
|
||||
///! Register definitions for Application Processing Unit (mpcore)
|
||||
|
||||
use volatile_register::{RO, RW};
|
||||
use libregister::{
|
||||
register, register_at, register_bit, register_bits,
|
||||
RegisterW, RegisterRW,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
@@ -177,18 +173,17 @@ register_bits!(scu_invalidate, cpu3_ways, u8, 12, 15);
|
||||
|
||||
impl ScuInvalidate {
|
||||
pub fn invalidate_all_cores(&mut self) {
|
||||
self.write(ScuInvalidate::zeroed()
|
||||
.cpu0_ways(0xf)
|
||||
.cpu1_ways(0xf)
|
||||
.cpu2_ways(0xf)
|
||||
.cpu3_ways(0xf)
|
||||
self.write(
|
||||
ScuInvalidate::zeroed()
|
||||
.cpu0_ways(0xf)
|
||||
.cpu1_ways(0xf)
|
||||
.cpu2_ways(0xf)
|
||||
.cpu3_ways(0xf),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn invalidate_core1(&mut self) {
|
||||
self.write(ScuInvalidate::zeroed()
|
||||
.cpu1_ways(0xf)
|
||||
);
|
||||
self.write(ScuInvalidate::zeroed().cpu1_ways(0xf));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +201,12 @@ register_bit!(scu_access_control_sac, cp_u2, 2);
|
||||
register_bit!(scu_access_control_sac, cp_u1, 1);
|
||||
register_bit!(scu_access_control_sac, cp_u0, 0);
|
||||
|
||||
register!(scu_non_secure_access_control, SCUNonSecureAccessControlRegister, RO, u32);
|
||||
register!(
|
||||
scu_non_secure_access_control,
|
||||
SCUNonSecureAccessControlRegister,
|
||||
RO,
|
||||
u32
|
||||
);
|
||||
register_bits!(scu_non_secure_access_control, sbz, u32, 12, 31);
|
||||
register_bit!(scu_non_secure_access_control, cpu3_global_timer, 11);
|
||||
register_bit!(scu_non_secure_access_control, cpu2_global_timer, 10);
|
||||
@@ -265,7 +265,12 @@ register_bit!(global_timer_control, irq_enable, 2);
|
||||
register_bit!(global_timer_control, comp_enablea, 1);
|
||||
register_bit!(global_timer_control, timer_enable, 0);
|
||||
|
||||
register!(global_timer_interrupt_status, GlobalTimerInterruptStatusRegister, RW, u32);
|
||||
register!(
|
||||
global_timer_interrupt_status,
|
||||
GlobalTimerInterruptStatusRegister,
|
||||
RW,
|
||||
u32
|
||||
);
|
||||
register_bit!(global_timer_interrupt_status, event_flag, 0);
|
||||
|
||||
register!(private_timer_control, PrivateTimerControlRegister, RW, u32);
|
||||
@@ -276,7 +281,12 @@ register_bit!(private_timer_control, irq_enable, 2);
|
||||
register_bit!(private_timer_control, auto_reload, 1);
|
||||
register_bit!(private_timer_control, timer_enable, 0);
|
||||
|
||||
register!(private_timer_interrupt_status, PrivateTimerInterruptStatusRegister, RW, u32);
|
||||
register!(
|
||||
private_timer_interrupt_status,
|
||||
PrivateTimerInterruptStatusRegister,
|
||||
RW,
|
||||
u32
|
||||
);
|
||||
register_bits!(private_timer_interrupt_status, unk_sbzp, u32, 1, 31);
|
||||
|
||||
register!(watchdog_control, WatchdogControlRegister, RW, u32);
|
||||
@@ -318,4 +328,3 @@ register_bits!(icdsgir, cpu_target_list, u8, 16, 23);
|
||||
register_bit!(icdsgir, satt, 15);
|
||||
register_bits!(icdsgir, sbz, u32, 4, 14);
|
||||
register_bits!(icdsgir, sgiintid, u8, 0, 3);
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
use crate::println;
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
mod zc706;
|
||||
#[cfg(not(feature = "target_zc706"))]
|
||||
mod none;
|
||||
|
||||
#[cfg(feature = "target_zc706")]
|
||||
use zc706 as target;
|
||||
mod zc706;
|
||||
|
||||
#[cfg(not(feature = "target_zc706"))]
|
||||
use none as target;
|
||||
#[cfg(feature = "target_zc706")]
|
||||
use zc706 as target;
|
||||
|
||||
pub fn report_differences() {
|
||||
for (i, op) in target::INIT_DATA.iter().enumerate() {
|
||||
let address = op.address();
|
||||
let overwritten_later = target::INIT_DATA[(i + 1)..].iter()
|
||||
let overwritten_later = target::INIT_DATA[(i + 1)..]
|
||||
.iter()
|
||||
.any(|later_op| later_op.address() == address);
|
||||
|
||||
if !overwritten_later {
|
||||
@@ -50,10 +51,8 @@ impl InitOp {
|
||||
|
||||
fn difference(&self) -> Option<(usize, usize)> {
|
||||
let expected = match self {
|
||||
InitOp::MaskWrite(_, mask, expected) =>
|
||||
Some((*mask, *expected)),
|
||||
InitOp::MaskPoll(_, mask) =>
|
||||
Some((*mask, *mask)),
|
||||
InitOp::MaskWrite(_, mask, expected) => Some((*mask, *expected)),
|
||||
InitOp::MaskPoll(_, mask) => Some((*mask, *mask)),
|
||||
_ => None,
|
||||
};
|
||||
match expected {
|
||||
@@ -65,8 +64,7 @@ impl InitOp {
|
||||
Some((actual & mask, expected))
|
||||
}
|
||||
}
|
||||
None =>
|
||||
None
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,12 +84,10 @@ impl InitOp {
|
||||
let reg = self.address() as *mut usize;
|
||||
println!("apply {:?}", self);
|
||||
match self {
|
||||
InitOp::MaskWrite(_, mask, val) =>
|
||||
unsafe {
|
||||
*reg = (val & mask) | (*reg & !mask);
|
||||
},
|
||||
InitOp::MaskPoll(_, mask) =>
|
||||
while unsafe { *reg } & mask == 0 {},
|
||||
InitOp::MaskWrite(_, mask, val) => unsafe {
|
||||
*reg = (val & mask) | (*reg & !mask);
|
||||
},
|
||||
InitOp::MaskPoll(_, mask) => while unsafe { *reg } & mask == 0 {},
|
||||
InitOp::MaskDelay(_, mask) => {
|
||||
let delay = get_number_of_cycles_for_delay(*mask);
|
||||
while unsafe { *reg } < delay {
|
||||
@@ -104,5 +100,5 @@ impl InitOp {
|
||||
|
||||
fn get_number_of_cycles_for_delay(delay: usize) -> usize {
|
||||
const APU_FREQ: usize = 666666687;
|
||||
APU_FREQ * delay/ (2 * 1000)
|
||||
APU_FREQ * delay / (2 * 1000)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use super::InitOp;
|
||||
|
||||
pub const INIT_DATA: &'static [InitOp] = &[
|
||||
];
|
||||
pub const INIT_DATA: &'static [InitOp] = &[];
|
||||
|
||||
@@ -8,17 +8,17 @@ pub const INIT_DATA: &'static [InitOp] = &[
|
||||
// .. .. KEY = 0xC5ACCE55
|
||||
// .. .. ==> 0xF8898FB0[31:0] = 0xC5ACCE55U
|
||||
// .. .. ==> MASK : 0xFFFFFFFFU VAL : 0xC5ACCE55U
|
||||
// .. ..
|
||||
// .. ..
|
||||
MaskWrite(0xF8898FB0, 0xFFFFFFFF, 0xC5ACCE55),
|
||||
// .. .. KEY = 0xC5ACCE55
|
||||
// .. .. ==> 0xF8899FB0[31:0] = 0xC5ACCE55U
|
||||
// .. .. ==> MASK : 0xFFFFFFFFU VAL : 0xC5ACCE55U
|
||||
// .. ..
|
||||
// .. ..
|
||||
MaskWrite(0xF8899FB0, 0xFFFFFFFF, 0xC5ACCE55),
|
||||
// .. .. KEY = 0xC5ACCE55
|
||||
// .. .. ==> 0xF8809FB0[31:0] = 0xC5ACCE55U
|
||||
// .. .. ==> MASK : 0xFFFFFFFFU VAL : 0xC5ACCE55U
|
||||
// .. ..
|
||||
// .. ..
|
||||
MaskWrite(0xF8809FB0, 0xFFFFFFFF, 0xC5ACCE55),
|
||||
// .. .. FINISH: UNLOCKING CTI REGISTERS
|
||||
// .. .. START: ENABLING CTI MODULES AND CHANNELS
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/// ADMA library
|
||||
use core::mem::MaybeUninit;
|
||||
use super::Sdio;
|
||||
|
||||
use libcortex_a9::cache;
|
||||
use libregister::{
|
||||
register, register_bit,
|
||||
RegisterR, RegisterW, RegisterRW, VolatileCell,
|
||||
};
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW, VolatileCell, register, register_bit};
|
||||
|
||||
use super::Sdio;
|
||||
|
||||
#[repr(C, align(4))]
|
||||
pub struct Adma2Desc32 {
|
||||
@@ -34,11 +33,7 @@ impl Adma2DescTable {
|
||||
/// Initialize the table and setup `adma_system_address`
|
||||
pub fn setup(&mut self, sdio: &mut Sdio, blk_cnt: u32, buffer: &[u8]) {
|
||||
let descr_table = &mut self.0;
|
||||
let blk_size = sdio
|
||||
.regs
|
||||
.block_size_block_count
|
||||
.read()
|
||||
.transfer_block_size() as u32;
|
||||
let blk_size = sdio.regs.block_size_block_count.read().transfer_block_size() as u32;
|
||||
|
||||
let total_desc_lines = if blk_size * blk_cnt < DESC_MAX_LENGTH {
|
||||
1
|
||||
@@ -53,23 +48,21 @@ impl Adma2DescTable {
|
||||
|
||||
let ptr = buffer.as_ptr() as u32;
|
||||
for desc_num in 0..total_desc_lines {
|
||||
descr_table[desc_num].address.set(ptr + (desc_num as u32) * DESC_MAX_LENGTH);
|
||||
descr_table[desc_num].attribute.write(
|
||||
Desc32Attribute::zeroed()
|
||||
.trans(true)
|
||||
.valid(true)
|
||||
);
|
||||
descr_table[desc_num]
|
||||
.address
|
||||
.set(ptr + (desc_num as u32) * DESC_MAX_LENGTH);
|
||||
descr_table[desc_num]
|
||||
.attribute
|
||||
.write(Desc32Attribute::zeroed().trans(true).valid(true));
|
||||
// 0 is the max length (65536)
|
||||
descr_table[desc_num].length.set(0);
|
||||
}
|
||||
descr_table[total_desc_lines - 1].attribute.modify(|_, w| w.end(true));
|
||||
descr_table[total_desc_lines - 1].length.set(
|
||||
(blk_cnt * blk_size - ((total_desc_lines as u32) - 1) * DESC_MAX_LENGTH) as u16,
|
||||
);
|
||||
descr_table[total_desc_lines - 1]
|
||||
.length
|
||||
.set((blk_cnt * blk_size - ((total_desc_lines as u32) - 1) * DESC_MAX_LENGTH) as u16);
|
||||
unsafe {
|
||||
sdio.regs
|
||||
.adma_system_address
|
||||
.write(descr_table.as_ptr() as u32);
|
||||
sdio.regs.adma_system_address.write(descr_table.as_ptr() as u32);
|
||||
}
|
||||
cache::dcci_slice(descr_table);
|
||||
}
|
||||
|
||||
@@ -121,9 +121,7 @@ pub fn set_cmd_reg(cmd: SdCmd, is_sd_card: bool, w: CmdReg) -> CmdReg {
|
||||
CMD10 | CMD11 | CMD12 => resp_r1(w),
|
||||
ACMD13 => resp_r1(w).data_present_select(true),
|
||||
CMD16 => resp_r1(w),
|
||||
CMD17 | CMD18 | CMD19 | CMD21 | CMD23 | ACMD23 | CMD24 | CMD25 => {
|
||||
resp_r1(w).data_present_select(true)
|
||||
}
|
||||
CMD17 | CMD18 | CMD19 | CMD21 | CMD23 | ACMD23 | CMD24 | CMD25 => resp_r1(w).data_present_select(true),
|
||||
ACMD41 => resp_r3(w),
|
||||
ACMD42 => resp_r1(w),
|
||||
ACMD51 => resp_r1(w).data_present_select(true),
|
||||
|
||||
@@ -3,12 +3,11 @@ pub mod sd_card;
|
||||
mod adma;
|
||||
mod cmd;
|
||||
mod regs;
|
||||
use super::clocks::Clocks;
|
||||
use super::slcr;
|
||||
use super::time::Milliseconds;
|
||||
use embedded_hal::timer::CountDown;
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||
use log::{trace, debug};
|
||||
use log::{debug, trace};
|
||||
|
||||
use super::{clocks::Clocks, slcr, time::Milliseconds};
|
||||
|
||||
/// Basic SDIO Struct with common low-level functions.
|
||||
pub struct Sdio {
|
||||
@@ -209,9 +208,7 @@ impl Sdio {
|
||||
|
||||
// reset all
|
||||
debug!("Reset SDIO!");
|
||||
self.regs
|
||||
.clock_control
|
||||
.modify(|_, w| w.software_reset_all(true));
|
||||
self.regs.clock_control.modify(|_, w| w.software_reset_all(true));
|
||||
while self.regs.clock_control.read().software_reset_all() {}
|
||||
|
||||
// set power to 3.3V
|
||||
@@ -233,20 +230,15 @@ impl Sdio {
|
||||
};
|
||||
self.regs.control.modify(|_, w| w.bus_voltage(voltage));
|
||||
|
||||
self.regs
|
||||
.control
|
||||
.modify(|_, w| w.dma_select(regs::DmaSelect::ADMA2_32));
|
||||
self.regs.control.modify(|_, w| w.dma_select(regs::DmaSelect::ADMA2_32));
|
||||
|
||||
// enable all interrupt status except card interrupt
|
||||
self.regs.interrupt_status_en.write(
|
||||
(regs::interrupt_status_en::Write { inner: 0xFFFFFFFF })
|
||||
.card_interrupt_status_en(false),
|
||||
);
|
||||
self.regs
|
||||
.interrupt_status_en
|
||||
.write((regs::interrupt_status_en::Write { inner: 0xFFFFFFFF }).card_interrupt_status_en(false));
|
||||
|
||||
// disable all interrupt signals
|
||||
self.regs
|
||||
.interrupt_signal_en
|
||||
.write(regs::InterruptSignalEn::zeroed());
|
||||
self.regs.interrupt_signal_en.write(regs::InterruptSignalEn::zeroed());
|
||||
|
||||
// set block size to 512 by default
|
||||
self.regs
|
||||
@@ -263,12 +255,7 @@ impl Sdio {
|
||||
/// Send SD command. Basically `cmd_transfer_with_mode` with mode
|
||||
/// `regs::TransferModeCommand::zeroed()`.
|
||||
/// Return: Ok if success, Err(status) if failed.
|
||||
fn cmd_transfer(
|
||||
&mut self,
|
||||
cmd: cmd::SdCmd,
|
||||
arg: u32,
|
||||
block_cnt: u16,
|
||||
) -> Result<(), CmdTransferError> {
|
||||
fn cmd_transfer(&mut self, cmd: cmd::SdCmd, arg: u32, block_cnt: u16) -> Result<(), CmdTransferError> {
|
||||
self.cmd_transfer_with_mode(cmd, arg, block_cnt, regs::TransferModeCommand::zeroed())
|
||||
}
|
||||
|
||||
@@ -290,9 +277,7 @@ impl Sdio {
|
||||
self.regs
|
||||
.block_size_block_count
|
||||
.modify(|_, w| w.blocks_count(block_cnt));
|
||||
self.regs
|
||||
.clock_control
|
||||
.modify(|_, w| w.timeout_counter_value(0xE));
|
||||
self.regs.clock_control.modify(|_, w| w.timeout_counter_value(0xE));
|
||||
unsafe {
|
||||
self.regs.argument.write(arg);
|
||||
}
|
||||
@@ -303,9 +288,7 @@ impl Sdio {
|
||||
let is_sd_card = self.card_type == CardType::CardSd;
|
||||
// Check DAT Line
|
||||
if cmd != cmd::SdCmd::CMD21 && cmd != cmd::SdCmd::CMD19 {
|
||||
if self.regs.present_state.read().command_inhibit_dat()
|
||||
&& cmd::require_dat(cmd, is_sd_card)
|
||||
{
|
||||
if self.regs.present_state.read().command_inhibit_dat() && cmd::require_dat(cmd, is_sd_card) {
|
||||
return Err(CmdTransferError::DatLineInhibited);
|
||||
}
|
||||
}
|
||||
@@ -320,9 +303,7 @@ impl Sdio {
|
||||
let status = self.regs.interrupt_status.read();
|
||||
if cmd == cmd::SdCmd::CMD21 || cmd == cmd::SdCmd::CMD19 {
|
||||
if status.buffer_read_ready() {
|
||||
self.regs
|
||||
.interrupt_status
|
||||
.modify(|_, w| w.buffer_read_ready());
|
||||
self.regs.interrupt_status.modify(|_, w| w.buffer_read_ready());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -333,9 +314,7 @@ impl Sdio {
|
||||
}
|
||||
// wait for command complete
|
||||
while !self.regs.interrupt_status.read().command_complete() {}
|
||||
self.regs
|
||||
.interrupt_status
|
||||
.modify(|_, w| w.command_complete());
|
||||
self.regs.interrupt_status.modify(|_, w| w.command_complete());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -364,9 +343,7 @@ impl Sdio {
|
||||
.clock_control
|
||||
.modify(|_, w| w.sd_clk_en(false).internal_clk_en(false));
|
||||
// enabling 1.8v in controller
|
||||
self.regs
|
||||
.control
|
||||
.modify(|_, w| w.bus_voltage(regs::BusVoltage::V18));
|
||||
self.regs.control.modify(|_, w| w.bus_voltage(regs::BusVoltage::V18));
|
||||
|
||||
// wait minimum 5ms
|
||||
self.delay(5);
|
||||
@@ -378,9 +355,7 @@ impl Sdio {
|
||||
}
|
||||
|
||||
// wait for internal clock to stabilize
|
||||
self.regs
|
||||
.clock_control
|
||||
.modify(|_, w| w.internal_clk_en(true));
|
||||
self.regs.clock_control.modify(|_, w| w.internal_clk_en(true));
|
||||
while !self.regs.clock_control.read().internal_clk_stable() {}
|
||||
|
||||
// enable SD clock
|
||||
@@ -406,7 +381,7 @@ impl Sdio {
|
||||
/// Detect inserted card type, and set the corresponding field.
|
||||
/// Return Ok(CardType) on success, Err(CmdTransferError) when failed to identify.
|
||||
pub fn identify_card(&mut self) -> Result<CardType, CmdTransferError> {
|
||||
use cmd::{args::*, SdCmd::*};
|
||||
use cmd::{SdCmd::*, args::*};
|
||||
// actually the delay for this one is unclear in the xilinx code.
|
||||
self.delay(10);
|
||||
self.cmd_transfer(CMD0, 0, 0)?;
|
||||
@@ -419,9 +394,7 @@ impl Sdio {
|
||||
self.regs
|
||||
.interrupt_status
|
||||
.write(regs::interrupt_status::Write { inner: 0xF3FFFFFF });
|
||||
self.regs
|
||||
.clock_control
|
||||
.modify(|_, w| w.software_reset_cmd(true));
|
||||
self.regs.clock_control.modify(|_, w| w.software_reset_cmd(true));
|
||||
// wait for reset completion
|
||||
while self.regs.clock_control.read().software_reset_cmd() {}
|
||||
Ok(self.card_type)
|
||||
@@ -451,17 +424,12 @@ impl Sdio {
|
||||
|
||||
/// Check if error occured, and reset the error status.
|
||||
/// Return Err(CmdTransferError) if error occured, Ok(()) otherwise.
|
||||
fn check_error(
|
||||
&mut self,
|
||||
status: ®s::interrupt_status::Read,
|
||||
) -> Result<(), CmdTransferError> {
|
||||
fn check_error(&mut self, status: ®s::interrupt_status::Read) -> Result<(), CmdTransferError> {
|
||||
if status.error_interrupt() {
|
||||
let err_status = if status.inner & 0xFFFE0000 == 0 {
|
||||
CmdTransferError::CmdTimeout
|
||||
} else {
|
||||
CmdTransferError::Other(regs::interrupt_status::Read {
|
||||
inner: status.inner,
|
||||
})
|
||||
CmdTransferError::Other(regs::interrupt_status::Read { inner: status.inner })
|
||||
};
|
||||
// reset all error status
|
||||
self.regs
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use core::fmt;
|
||||
|
||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
use volatile_register::{RO, RW};
|
||||
|
||||
@@ -453,11 +454,7 @@ register_bit!(interrupt_signal_en, transfer_complete_signal_en, 1);
|
||||
register_bit!(interrupt_signal_en, cmd_complete_signal_en, 0);
|
||||
|
||||
register!(auto_cmd12_error_status, AutoCmd12ErrorStatus, RO, u32);
|
||||
register_bit!(
|
||||
auto_cmd12_error_status,
|
||||
cmd_not_issued_by_auto_cmd12_error,
|
||||
7
|
||||
);
|
||||
register_bit!(auto_cmd12_error_status, cmd_not_issued_by_auto_cmd12_error, 7);
|
||||
register_bit!(auto_cmd12_error_status, index_error, 4);
|
||||
register_bit!(auto_cmd12_error_status, end_bit_error, 3);
|
||||
register_bit!(auto_cmd12_error_status, crc_error, 2);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::{adma::Adma2DescTable, cmd, CardType, CmdTransferError, Sdio};
|
||||
use libcortex_a9::cache;
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW};
|
||||
use log::{trace, debug};
|
||||
use log::{debug, trace};
|
||||
|
||||
use super::{CardType, CmdTransferError, Sdio, adma::Adma2DescTable, cmd};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CardInitializationError {
|
||||
@@ -19,7 +20,7 @@ impl core::fmt::Display for CardInitializationError {
|
||||
AlreadyInitialized => write!(f, "Card already initialized."),
|
||||
NoCardInserted => write!(f, "No card inserted, check if the card is inserted properly."),
|
||||
InitializationFailedOther => write!(f, "Unknown error. Please check the debug messages."),
|
||||
InitializationFailedCmd(x) => write!(f, "{}", x)
|
||||
InitializationFailedCmd(x) => write!(f, "{}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,14 +53,17 @@ const BLK_SIZE_MASK: u16 = 0x00000FFF;
|
||||
|
||||
impl core::fmt::Display for SdCard {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(f, "SdCard: \n card version: {:?}\n hcs: {}\n card id: {:?}\n rel card addr: {}\n sector count: {}",
|
||||
self.card_version, self.hcs, self.card_id, self.rel_card_addr, self.sector_cnt)
|
||||
write!(
|
||||
f,
|
||||
"SdCard: \n card version: {:?}\n hcs: {}\n card id: {:?}\n rel card addr: {}\n sector count: {}",
|
||||
self.card_version, self.hcs, self.card_id, self.rel_card_addr, self.sector_cnt
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl SdCard {
|
||||
fn sd_card_initialize(&mut self) -> Result<(), CardInitializationError> {
|
||||
use cmd::{args::*, SdCmd::*};
|
||||
use cmd::{SdCmd::*, args::*};
|
||||
if !self.sdio.is_card_inserted() {
|
||||
return Err(CardInitializationError::NoCardInserted);
|
||||
}
|
||||
@@ -68,10 +72,7 @@ impl SdCard {
|
||||
match self.sdio.cmd_transfer(CMD8, CMD8_VOL_PATTERN, 0) {
|
||||
Err(CmdTransferError::CmdTimeout) => {
|
||||
// reset
|
||||
self.sdio
|
||||
.regs
|
||||
.clock_control
|
||||
.modify(|_, w| w.software_reset_cmd(true));
|
||||
self.sdio.regs.clock_control.modify(|_, w| w.software_reset_cmd(true));
|
||||
// wait until reset is completed
|
||||
while self.sdio.regs.clock_control.read().software_reset_cmd() {}
|
||||
}
|
||||
@@ -117,10 +118,7 @@ impl SdCard {
|
||||
}
|
||||
|
||||
self.sdio.cmd_transfer(CMD9, self.rel_card_addr, 0)?;
|
||||
self.sdio
|
||||
.regs
|
||||
.interrupt_status
|
||||
.modify(|_, w| w.transfer_complete());
|
||||
self.sdio.regs.interrupt_status.modify(|_, w| w.transfer_complete());
|
||||
|
||||
let mut csd: [u32; 4] = [0, 0, 0, 0];
|
||||
for i in 0..=3 {
|
||||
@@ -199,22 +197,10 @@ impl SdCard {
|
||||
|
||||
/// read blocks starting from an address. Each block has length 512 byte.
|
||||
/// Note that the address is block address, i.e. 0 for 0~512, 1 for 512~1024, etc.
|
||||
pub fn read_block(
|
||||
&mut self,
|
||||
address: u32,
|
||||
block_cnt: u16,
|
||||
buffer: &mut [u8],
|
||||
) -> Result<(), CmdTransferError> {
|
||||
pub fn read_block(&mut self, address: u32, block_cnt: u16, buffer: &mut [u8]) -> Result<(), CmdTransferError> {
|
||||
assert!(buffer.len() >= (block_cnt as usize) * 512);
|
||||
// set block size if not set already
|
||||
if self
|
||||
.sdio
|
||||
.regs
|
||||
.block_size_block_count
|
||||
.read()
|
||||
.transfer_block_size()
|
||||
!= 512
|
||||
{
|
||||
if self.sdio.regs.block_size_block_count.read().transfer_block_size() != 512 {
|
||||
self.sdio.set_block_size(512)?;
|
||||
}
|
||||
|
||||
@@ -249,8 +235,7 @@ impl SdCard {
|
||||
.dma_en(true)
|
||||
};
|
||||
|
||||
self.sdio
|
||||
.cmd_transfer_with_mode(cmd, real_addr, block_cnt, mode)?;
|
||||
self.sdio.cmd_transfer_with_mode(cmd, real_addr, block_cnt, mode)?;
|
||||
|
||||
self.wait_transfer_complete()?;
|
||||
cache::dcci_slice(buffer);
|
||||
@@ -259,22 +244,10 @@ impl SdCard {
|
||||
|
||||
/// write blocks starting from an address. Each block has length 512 byte.
|
||||
/// Note that the address is block address, i.e. 0 for 0~512, 1 for 512~1024, etc.
|
||||
pub fn write_block(
|
||||
&mut self,
|
||||
address: u32,
|
||||
block_cnt: u16,
|
||||
buffer: &[u8],
|
||||
) -> Result<(), CmdTransferError> {
|
||||
pub fn write_block(&mut self, address: u32, block_cnt: u16, buffer: &[u8]) -> Result<(), CmdTransferError> {
|
||||
assert!(buffer.len() >= (block_cnt as usize) * 512);
|
||||
// set block size if not set already
|
||||
if self
|
||||
.sdio
|
||||
.regs
|
||||
.block_size_block_count
|
||||
.read()
|
||||
.transfer_block_size()
|
||||
!= 512
|
||||
{
|
||||
if self.sdio.regs.block_size_block_count.read().transfer_block_size() != 512 {
|
||||
self.sdio.set_block_size(512)?;
|
||||
}
|
||||
|
||||
@@ -307,8 +280,7 @@ impl SdCard {
|
||||
.dma_en(true)
|
||||
};
|
||||
|
||||
self.sdio
|
||||
.cmd_transfer_with_mode(cmd, real_addr, block_cnt, mode)?;
|
||||
self.sdio.cmd_transfer_with_mode(cmd, real_addr, block_cnt, mode)?;
|
||||
// wait for transfer complete interrupt
|
||||
self.wait_transfer_complete()?;
|
||||
|
||||
@@ -355,10 +327,7 @@ impl SdCard {
|
||||
self.width_4_bit = true;
|
||||
self.sdio.cmd_transfer(ACMD6, 0x2, 0)?;
|
||||
self.sdio.delay(1);
|
||||
self.sdio
|
||||
.regs
|
||||
.control
|
||||
.modify(|_, w| w.data_width_select(true));
|
||||
self.sdio.regs.control.modify(|_, w| w.data_width_select(true));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -370,10 +339,7 @@ impl SdCard {
|
||||
status = self.sdio.regs.interrupt_status.read();
|
||||
}
|
||||
trace!("Clearing transfer complete");
|
||||
self.sdio
|
||||
.regs
|
||||
.interrupt_status
|
||||
.modify(|_, w| w.transfer_complete());
|
||||
self.sdio.regs.interrupt_status.modify(|_, w| w.transfer_complete());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
use libregister::{RegisterRW, RegisterW, register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
///! Register definitions for System Level Control
|
||||
|
||||
use volatile_register::{RO, RW};
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits, register_bits_typed,
|
||||
RegisterW, RegisterRW,
|
||||
};
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum PllSource {
|
||||
IoPll = 0b000,
|
||||
IoPll = 0b000,
|
||||
ArmPll = 0b010,
|
||||
DdrPll = 0b011,
|
||||
// Ethernet controller 0 EMIO clock
|
||||
Emio = 0b100,
|
||||
Emio = 0b100,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum ArmPllSource {
|
||||
ArmPll = 0b00,
|
||||
DdrPll = 0b10,
|
||||
IoPll = 0b11,
|
||||
IoPll = 0b11,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
@@ -48,7 +43,6 @@ pub enum DdriobOutputEn {
|
||||
Obuf = 0b11,
|
||||
}
|
||||
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum DdriobVrefSel {
|
||||
/// For LPDDR2 with 1.2V IO
|
||||
@@ -68,7 +62,6 @@ pub enum LevelShifterEnable {
|
||||
EnableAll = 0xF,
|
||||
}
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub scl: RW<u32>,
|
||||
@@ -274,29 +267,21 @@ impl RegisterBlock {
|
||||
.fpga0_out_rst(true)
|
||||
.fpga1_out_rst(true)
|
||||
.fpga2_out_rst(true)
|
||||
.fpga3_out_rst(true)
|
||||
.fpga3_out_rst(true),
|
||||
);
|
||||
// Disable level shifters
|
||||
self.lvl_shftr_en.write(
|
||||
LvlShftr::zeroed()
|
||||
);
|
||||
self.lvl_shftr_en.write(LvlShftr::zeroed());
|
||||
// Enable output level shifters
|
||||
self.lvl_shftr_en.write(
|
||||
LvlShftr::zeroed()
|
||||
.user_lvl_shftr_en(LevelShifterEnable::EnablePsToPl)
|
||||
);
|
||||
self.lvl_shftr_en
|
||||
.write(LvlShftr::zeroed().user_lvl_shftr_en(LevelShifterEnable::EnablePsToPl));
|
||||
}
|
||||
|
||||
pub fn init_postload_fpga(&mut self) {
|
||||
// Enable level shifters
|
||||
self.lvl_shftr_en.write(
|
||||
LvlShftr::zeroed()
|
||||
.user_lvl_shftr_en(LevelShifterEnable::EnableAll)
|
||||
);
|
||||
self.lvl_shftr_en
|
||||
.write(LvlShftr::zeroed().user_lvl_shftr_en(LevelShifterEnable::EnableAll));
|
||||
// Deassert AXI interface resets
|
||||
self.fpga_rst_ctrl.write(
|
||||
FpgaRstCtrl::zeroed()
|
||||
);
|
||||
self.fpga_rst_ctrl.write(FpgaRstCtrl::zeroed());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,10 +289,7 @@ register!(slcr_lock, SlcrLock, WO, u32);
|
||||
register_bits!(slcr_lock, lock_key, u16, 0, 15);
|
||||
impl SlcrLock {
|
||||
pub fn lock(&mut self) {
|
||||
self.write(
|
||||
Self::zeroed()
|
||||
.lock_key(0x767B)
|
||||
);
|
||||
self.write(Self::zeroed().lock_key(0x767B));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,10 +297,7 @@ register!(slcr_unlock, SlcrUnlock, WO, u32);
|
||||
register_bits!(slcr_unlock, unlock_key, u16, 0, 15);
|
||||
impl SlcrUnlock {
|
||||
pub fn unlock(&mut self) {
|
||||
self.write(
|
||||
Self::zeroed()
|
||||
.unlock_key(0xDF0D)
|
||||
);
|
||||
self.write(Self::zeroed().unlock_key(0xDF0D));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,13 +318,15 @@ register_bit!(pll_status, io_pll_stable, 5);
|
||||
|
||||
impl core::fmt::Display for pll_status::Read {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
|
||||
write!(fmt, "ARM: {}/{} DDR: {}/{} IO: {}/{}",
|
||||
if self.arm_pll_lock() { "locked" } else { "NOT locked" },
|
||||
if self.arm_pll_stable() { "stable" } else { "UNSTABLE" },
|
||||
if self.ddr_pll_lock() { "locked" } else { "NOT locked" },
|
||||
if self.ddr_pll_stable() { "stable" } else { "UNSTABLE" },
|
||||
if self.io_pll_lock() { "locked" } else { "NOT locked" },
|
||||
if self.io_pll_stable() { "stable" } else { "UNSTABLE" },
|
||||
write!(
|
||||
fmt,
|
||||
"ARM: {}/{} DDR: {}/{} IO: {}/{}",
|
||||
if self.arm_pll_lock() { "locked" } else { "NOT locked" },
|
||||
if self.arm_pll_stable() { "stable" } else { "UNSTABLE" },
|
||||
if self.ddr_pll_lock() { "locked" } else { "NOT locked" },
|
||||
if self.ddr_pll_stable() { "stable" } else { "UNSTABLE" },
|
||||
if self.io_pll_lock() { "locked" } else { "NOT locked" },
|
||||
if self.io_pll_stable() { "stable" } else { "UNSTABLE" },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -434,14 +415,10 @@ register_bits!(sdio_clk_ctrl, divisor, u8, 8, 13);
|
||||
register_bits_typed!(sdio_clk_ctrl, srcsel, u8, PllSource, 4, 5);
|
||||
impl SdioClkCtrl {
|
||||
pub fn enable_sdio0(&mut self) {
|
||||
self.modify(|_, w| {
|
||||
w.divisor(0x14).srcsel(PllSource::IoPll).clkact0(true)
|
||||
})
|
||||
self.modify(|_, w| w.divisor(0x14).srcsel(PllSource::IoPll).clkact0(true))
|
||||
}
|
||||
pub fn enable_sdio1(&mut self) {
|
||||
self.modify(|_, w| {
|
||||
w.divisor(0x14).srcsel(PllSource::IoPll).clkact1(true)
|
||||
})
|
||||
self.modify(|_, w| w.divisor(0x14).srcsel(PllSource::IoPll).clkact1(true))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,9 +434,7 @@ impl UartClkCtrl {
|
||||
// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14.
|
||||
// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0.
|
||||
// c. Enable the UART 0 Reference clock, slcr.UART_CLK_CTRL [CLKACT0] = 1.
|
||||
w.divisor(0x14)
|
||||
.srcsel(PllSource::IoPll)
|
||||
.clkact0(true)
|
||||
w.divisor(0x14).srcsel(PllSource::IoPll).clkact0(true)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -468,9 +443,7 @@ impl UartClkCtrl {
|
||||
// a. Clock divisor, slcr.UART_CLK_CTRL[DIVISOR] = 0x14.
|
||||
// b. Select the IO PLL, slcr.UART_CLK_CTRL[SRCSEL] = 0.
|
||||
// c. Enable the UART 1 Reference clock, slcr.UART_CLK_CTRL [CLKACT1] = 1.
|
||||
w.divisor(0x14)
|
||||
.srcsel(PllSource::IoPll)
|
||||
.clkact1(true)
|
||||
w.divisor(0x14).srcsel(PllSource::IoPll).clkact1(true)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -482,24 +455,12 @@ register_bit!(sdio_rst_ctrl, sdio1_cpu1x_rst, 1);
|
||||
register_bit!(sdio_rst_ctrl, sdio0_cpu1x_rst, 0);
|
||||
impl SdioRstCtrl {
|
||||
pub fn reset_sdio0(&mut self) {
|
||||
self.modify(|_, w|
|
||||
w.sdio0_ref_rst(true)
|
||||
.sdio0_cpu1x_rst(true)
|
||||
);
|
||||
self.modify(|_, w|
|
||||
w.sdio0_ref_rst(false)
|
||||
.sdio0_cpu1x_rst(false)
|
||||
);
|
||||
self.modify(|_, w| w.sdio0_ref_rst(true).sdio0_cpu1x_rst(true));
|
||||
self.modify(|_, w| w.sdio0_ref_rst(false).sdio0_cpu1x_rst(false));
|
||||
}
|
||||
pub fn reset_sdio1(&mut self) {
|
||||
self.modify(|_, w|
|
||||
w.sdio1_ref_rst(true)
|
||||
.sdio1_cpu1x_rst(true)
|
||||
);
|
||||
self.modify(|_, w|
|
||||
w.sdio1_ref_rst(false)
|
||||
.sdio1_cpu1x_rst(false)
|
||||
);
|
||||
self.modify(|_, w| w.sdio1_ref_rst(true).sdio1_cpu1x_rst(true));
|
||||
self.modify(|_, w| w.sdio1_ref_rst(false).sdio1_cpu1x_rst(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,25 +472,13 @@ register_bit!(uart_rst_ctrl, uart1_cpu1x_rst, 0);
|
||||
register_at!(UartRstCtrl, 0xF8000228, new);
|
||||
impl UartRstCtrl {
|
||||
pub fn reset_uart0(&mut self) {
|
||||
self.modify(|_, w|
|
||||
w.uart0_ref_rst(true)
|
||||
.uart0_cpu1x_rst(true)
|
||||
);
|
||||
self.modify(|_, w|
|
||||
w.uart0_ref_rst(false)
|
||||
.uart0_cpu1x_rst(false)
|
||||
);
|
||||
self.modify(|_, w| w.uart0_ref_rst(true).uart0_cpu1x_rst(true));
|
||||
self.modify(|_, w| w.uart0_ref_rst(false).uart0_cpu1x_rst(false));
|
||||
}
|
||||
|
||||
pub fn reset_uart1(&mut self) {
|
||||
self.modify(|_, w|
|
||||
w.uart1_ref_rst(true)
|
||||
.uart1_cpu1x_rst(true)
|
||||
);
|
||||
self.modify(|_, w|
|
||||
w.uart1_ref_rst(false)
|
||||
.uart1_cpu1x_rst(false)
|
||||
);
|
||||
self.modify(|_, w| w.uart1_ref_rst(true).uart1_cpu1x_rst(true));
|
||||
self.modify(|_, w| w.uart1_ref_rst(false).uart1_cpu1x_rst(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,12 +487,8 @@ register_bit!(gpio_rst_ctrl, gpio_cpu1x_rst, 0);
|
||||
register_at!(GpioRstCtrl, 0xF800022C, new);
|
||||
impl GpioRstCtrl {
|
||||
pub fn reset_gpio(&mut self) {
|
||||
self.modify(|_, w|
|
||||
w.gpio_cpu1x_rst(true)
|
||||
);
|
||||
self.modify(|_, w|
|
||||
w.gpio_cpu1x_rst(false)
|
||||
);
|
||||
self.modify(|_, w| w.gpio_cpu1x_rst(true));
|
||||
self.modify(|_, w| w.gpio_cpu1x_rst(false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,16 +535,13 @@ register_bit!(a9_cpu_rst_ctrl, a9_rst1, 1);
|
||||
register_bit!(a9_cpu_rst_ctrl, a9_rst0, 0);
|
||||
|
||||
pub fn reboot() {
|
||||
RegisterBlock::unlocked(|slcr| {
|
||||
unsafe {
|
||||
let reboot = slcr.reboot_status.read();
|
||||
slcr.reboot_status.write(reboot & 0xF0FFFFFF);
|
||||
slcr.pss_rst_ctrl.modify(|_, w| w.soft_rst(true));
|
||||
}
|
||||
RegisterBlock::unlocked(|slcr| unsafe {
|
||||
let reboot = slcr.reboot_status.read();
|
||||
slcr.reboot_status.write(reboot & 0xF0FFFFFF);
|
||||
slcr.pss_rst_ctrl.modify(|_, w| w.soft_rst(true));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum BootModePins {
|
||||
@@ -626,11 +568,11 @@ pub enum IoBufferType {
|
||||
Lvcmos18 = 0b001,
|
||||
Lvcmos25 = 0b010,
|
||||
Lvcmos33 = 0b011,
|
||||
Hstl = 0b100,
|
||||
Hstl = 0b100,
|
||||
}
|
||||
|
||||
macro_rules! mio_pin_register {
|
||||
($mod_name: ident, $struct_name: ident) => (
|
||||
($mod_name:ident, $struct_name:ident) => {
|
||||
register!($mod_name, $struct_name, RW, u32);
|
||||
register_bit!($mod_name, disable_rcvr, 13);
|
||||
register_bit!($mod_name, pullup, 12);
|
||||
@@ -641,7 +583,7 @@ macro_rules! mio_pin_register {
|
||||
register_bit!($mod_name, l1_sel, 2);
|
||||
register_bit!($mod_name, l0_sel, 1);
|
||||
register_bit!($mod_name, tri_enable, 0);
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
mio_pin_register!(mio_pin_00, MioPin00);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use libcortex_a9::{asm, mutex::{Mutex, MutexGuard}};
|
||||
|
||||
use libcortex_a9::{asm,
|
||||
mutex::{Mutex, MutexGuard}};
|
||||
|
||||
use crate::uart::Uart;
|
||||
|
||||
const UART_RATE: u32 = 115_200;
|
||||
@@ -20,7 +23,9 @@ pub fn drop_uart() {
|
||||
asm::nop();
|
||||
}
|
||||
|
||||
unsafe { UART = Mutex::new(LazyUart::Uninitialized); }
|
||||
unsafe {
|
||||
UART = Mutex::new(LazyUart::Uninitialized);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes the UART on first use through `.deref_mut()` for debug
|
||||
@@ -34,10 +39,8 @@ impl Deref for LazyUart {
|
||||
type Target = Uart;
|
||||
fn deref(&self) -> &Uart {
|
||||
match self {
|
||||
LazyUart::Uninitialized =>
|
||||
panic!("stdio not initialized!"),
|
||||
LazyUart::Initialized(uart) =>
|
||||
uart,
|
||||
LazyUart::Uninitialized => panic!("stdio not initialized!"),
|
||||
LazyUart::Initialized(uart) => uart,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,17 +51,12 @@ impl DerefMut for LazyUart {
|
||||
LazyUart::Uninitialized => {
|
||||
#[cfg(any(feature = "target_coraz7", feature = "target_redpitaya"))]
|
||||
let uart = Uart::uart0(UART_RATE);
|
||||
#[cfg(any(
|
||||
feature = "target_zc706",
|
||||
feature = "target_ebaz4205",
|
||||
feature = "target_kasli_soc",
|
||||
))]
|
||||
#[cfg(any(feature = "target_zc706", feature = "target_ebaz4205", feature = "target_kasli_soc",))]
|
||||
let uart = Uart::uart1(UART_RATE);
|
||||
*self = LazyUart::Initialized(uart);
|
||||
self
|
||||
}
|
||||
LazyUart::Initialized(uart) =>
|
||||
uart,
|
||||
LazyUart::Initialized(uart) => uart,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use core::ops::Add;
|
||||
use void::Void;
|
||||
|
||||
use libregister::{RegisterR, RegisterW};
|
||||
use crate::{
|
||||
clocks::Clocks,
|
||||
mpcore,
|
||||
time::{Milliseconds, Microseconds, TimeSource},
|
||||
};
|
||||
use void::Void;
|
||||
|
||||
use crate::{clocks::Clocks,
|
||||
mpcore,
|
||||
time::{Microseconds, Milliseconds, TimeSource}};
|
||||
|
||||
/// "uptime"
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -29,17 +29,11 @@ impl GlobalTimer {
|
||||
|
||||
fn reset(regs: &mut mpcore::RegisterBlock) {
|
||||
// Disable
|
||||
regs.global_timer_control.write(
|
||||
mpcore::GlobalTimerControl::zeroed()
|
||||
);
|
||||
regs.global_timer_control.write(mpcore::GlobalTimerControl::zeroed());
|
||||
|
||||
// Reset counters
|
||||
regs.global_timer_counter0.write(
|
||||
mpcore::ValueRegister::zeroed()
|
||||
);
|
||||
regs.global_timer_counter1.write(
|
||||
mpcore::ValueRegister::zeroed()
|
||||
);
|
||||
regs.global_timer_counter0.write(mpcore::ValueRegister::zeroed());
|
||||
regs.global_timer_counter1.write(mpcore::ValueRegister::zeroed());
|
||||
|
||||
// find a prescaler value that matches CPU speed / 2 to us
|
||||
let clocks = Clocks::get();
|
||||
@@ -53,7 +47,7 @@ impl GlobalTimer {
|
||||
mpcore::GlobalTimerControl::zeroed()
|
||||
.prescaler((prescaler - 1) as u8)
|
||||
.auto_increment_mode(true)
|
||||
.timer_enable(true)
|
||||
.timer_enable(true),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,9 +84,7 @@ impl GlobalTimer {
|
||||
/// return a handle that has implements
|
||||
/// `embedded_hal::timer::CountDown`
|
||||
pub fn countdown<U>(&self) -> CountDown<U>
|
||||
where
|
||||
Self: TimeSource<U>,
|
||||
{
|
||||
where Self: TimeSource<U> {
|
||||
CountDown {
|
||||
timer: self.clone(),
|
||||
timeout: self.now(),
|
||||
@@ -119,9 +111,8 @@ pub struct CountDown<U> {
|
||||
}
|
||||
|
||||
/// embedded-hal async API
|
||||
impl<U: Add<Output=U> + PartialOrd> embedded_hal::timer::CountDown for CountDown<U>
|
||||
where
|
||||
GlobalTimer: TimeSource<U>,
|
||||
impl<U: Add<Output = U> + PartialOrd> embedded_hal::timer::CountDown for CountDown<U>
|
||||
where GlobalTimer: TimeSource<U>
|
||||
{
|
||||
type Time = U;
|
||||
|
||||
@@ -139,8 +130,7 @@ where
|
||||
}
|
||||
|
||||
impl<U: PartialOrd> CountDown<U>
|
||||
where
|
||||
GlobalTimer: TimeSource<U>,
|
||||
where GlobalTimer: TimeSource<U>
|
||||
{
|
||||
pub fn waiting(&self) -> bool {
|
||||
self.timer.now() <= self.timeout
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use libregister::*;
|
||||
use super::regs::{RegisterBlock, BaudRateGen, BaudRateDiv};
|
||||
|
||||
use super::regs::{BaudRateDiv, BaudRateGen, RegisterBlock};
|
||||
|
||||
const BDIV_MIN: u32 = 4;
|
||||
const BDIV_MAX: u32 = 255;
|
||||
@@ -28,9 +29,7 @@ pub fn configure(regs: &mut RegisterBlock, mut clk: u32, baud: u32) {
|
||||
} else {
|
||||
actual_baud - baud
|
||||
};
|
||||
let better = best
|
||||
.map(|(_cd, _bdiv, best_error)| error < best_error)
|
||||
.unwrap_or(true);
|
||||
let better = best.map(|(_cd, _bdiv, best_error)| error < best_error).unwrap_or(true);
|
||||
if better {
|
||||
best = Some((cd as u16, bdiv as u8, error));
|
||||
}
|
||||
@@ -41,6 +40,6 @@ pub fn configure(regs: &mut RegisterBlock, mut clk: u32, baud: u32) {
|
||||
regs.baud_rate_gen.write(BaudRateGen::zeroed().cd(cd));
|
||||
regs.baud_rate_divider.write(BaudRateDiv::zeroed().bdiv(bdiv));
|
||||
}
|
||||
None => panic!("Cannot configure baud rate")
|
||||
None => panic!("Cannot configure baud rate"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use core::fmt;
|
||||
use void::Void;
|
||||
|
||||
use libregister::*;
|
||||
use super::slcr;
|
||||
use super::clocks::Clocks;
|
||||
use void::Void;
|
||||
|
||||
use super::{clocks::Clocks, slcr};
|
||||
|
||||
mod regs;
|
||||
mod baud_rate_gen;
|
||||
mod regs;
|
||||
|
||||
pub struct Uart {
|
||||
regs: &'static mut regs::RegisterBlock,
|
||||
@@ -22,7 +22,7 @@ impl Uart {
|
||||
slcr::MioPin15::zeroed()
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RX pin
|
||||
slcr.mio_pin_14.write(
|
||||
@@ -30,7 +30,7 @@ impl Uart {
|
||||
.tri_enable(true)
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ impl Uart {
|
||||
slcr::MioPin48::zeroed()
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RX pin
|
||||
slcr.mio_pin_49.write(
|
||||
@@ -63,7 +63,7 @@ impl Uart {
|
||||
.tri_enable(true)
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos18)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -88,7 +88,7 @@ impl Uart {
|
||||
slcr::MioPin24::zeroed()
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
// RX pin
|
||||
slcr.mio_pin_25.write(
|
||||
@@ -96,7 +96,7 @@ impl Uart {
|
||||
.tri_enable(true)
|
||||
.l3_sel(0b111)
|
||||
.io_type(slcr::IoBufferType::Lvcmos33)
|
||||
.pullup(true)
|
||||
.pullup(true),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -115,10 +115,7 @@ impl Uart {
|
||||
pub fn write_byte(&mut self, value: u8) {
|
||||
while self.tx_fifo_full() {}
|
||||
|
||||
self.regs.tx_rx_fifo.write(
|
||||
regs::TxRxFifo::zeroed()
|
||||
.data(value.into())
|
||||
);
|
||||
self.regs.tx_rx_fifo.write(regs::TxRxFifo::zeroed().data(value.into()));
|
||||
}
|
||||
|
||||
pub fn configure(&mut self, baudrate: u32) {
|
||||
@@ -131,7 +128,7 @@ impl Uart {
|
||||
self.regs.mode.write(
|
||||
regs::Mode::zeroed()
|
||||
.par(regs::ParityMode::None)
|
||||
.chmode(regs::ChannelMode::Normal)
|
||||
.chmode(regs::ChannelMode::Normal),
|
||||
);
|
||||
|
||||
// Configure the Baud Rate
|
||||
@@ -153,43 +150,27 @@ impl Uart {
|
||||
}
|
||||
|
||||
fn disable_rx(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.rxen(false)
|
||||
.rxdis(true)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.rxen(false).rxdis(true))
|
||||
}
|
||||
|
||||
fn disable_tx(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.txen(false)
|
||||
.txdis(true)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.txen(false).txdis(true))
|
||||
}
|
||||
|
||||
fn enable_rx(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.rxen(true)
|
||||
.rxdis(false)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.rxen(true).rxdis(false))
|
||||
}
|
||||
|
||||
fn enable_tx(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.txen(true)
|
||||
.txdis(false)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.txen(true).txdis(false))
|
||||
}
|
||||
|
||||
fn reset_rx(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.rxrst(true)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.rxrst(true))
|
||||
}
|
||||
|
||||
fn reset_tx(&mut self) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.txrst(true)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.txrst(true))
|
||||
}
|
||||
|
||||
/// Wait for `reset_rx()` or `reset_tx()` to complete
|
||||
@@ -202,17 +183,12 @@ impl Uart {
|
||||
}
|
||||
|
||||
fn set_break(&mut self, startbrk: bool, stopbrk: bool) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.sttbrk(startbrk)
|
||||
.stpbrk(stopbrk)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.sttbrk(startbrk).stpbrk(stopbrk))
|
||||
}
|
||||
|
||||
// 0 disables
|
||||
fn set_rx_timeout(&mut self, enable: bool) {
|
||||
self.regs.control.modify(|_, w| {
|
||||
w.rstto(enable)
|
||||
})
|
||||
self.regs.control.modify(|_, w| w.rstto(enable))
|
||||
}
|
||||
|
||||
pub fn tx_fifo_full(&self) -> bool {
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
use volatile_register::{RO, WO, RW};
|
||||
|
||||
use libregister::{
|
||||
register, register_at,
|
||||
register_bit, register_bits, register_bits_typed,
|
||||
};
|
||||
use libregister::{register, register_at, register_bit, register_bits, register_bits_typed};
|
||||
use volatile_register::{RO, RW, WO};
|
||||
|
||||
#[allow(unused)]
|
||||
#[repr(u8)]
|
||||
pub enum ChannelMode {
|
||||
Normal = 0b00,
|
||||
AutomaticEcho = 0b01,
|
||||
LocalLoopback = 0b10,
|
||||
Normal = 0b00,
|
||||
AutomaticEcho = 0b01,
|
||||
LocalLoopback = 0b10,
|
||||
RemoteLoopback = 0b11,
|
||||
}
|
||||
|
||||
@@ -18,18 +14,18 @@ pub enum ChannelMode {
|
||||
#[repr(u8)]
|
||||
pub enum ParityMode {
|
||||
EvenParity = 0b000,
|
||||
OddParity = 0b001,
|
||||
ForceTo0 = 0b010,
|
||||
ForceTo1 = 0b011,
|
||||
None = 0b100,
|
||||
OddParity = 0b001,
|
||||
ForceTo0 = 0b010,
|
||||
ForceTo1 = 0b011,
|
||||
None = 0b100,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[repr(u8)]
|
||||
pub enum StopBits {
|
||||
One = 0b00,
|
||||
One = 0b00,
|
||||
OneAndHalf = 0b01,
|
||||
Two = 0b10,
|
||||
Two = 0b10,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use core_io::{Error, Read, Seek, SeekFrom};
|
||||
use libboard_zynq::devc;
|
||||
use log::debug;
|
||||
@@ -28,10 +29,7 @@ impl core::fmt::Display for BootgenLoadingError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
use BootgenLoadingError::*;
|
||||
match self {
|
||||
InvalidBootImageHeader => write!(
|
||||
f,
|
||||
"Invalid boot image header. Check if the file is correct."
|
||||
),
|
||||
InvalidBootImageHeader => write!(f, "Invalid boot image header. Check if the file is correct."),
|
||||
MissingPartition => write!(f, "Partition not found. Check your compile configuration."),
|
||||
EncryptedBitstream => write!(f, "Encrypted bitstream is not supported."),
|
||||
IoError(e) => write!(f, "Error while reading: {}", e),
|
||||
@@ -69,9 +67,7 @@ fn read_u32<Reader: Read>(reader: &mut Reader) -> Result<u32, BootgenLoadingErro
|
||||
}
|
||||
|
||||
/// Load PL partition header.
|
||||
fn load_pl_header<File: Read + Seek>(
|
||||
file: &mut File,
|
||||
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||
fn load_pl_header<File: Read + Seek>(file: &mut File) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||
let mut buffer: [u8; 0x40] = [0; 0x40];
|
||||
file.read_exact(&mut buffer)?;
|
||||
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
||||
@@ -82,9 +78,7 @@ fn load_pl_header<File: Read + Seek>(
|
||||
}
|
||||
}
|
||||
|
||||
fn load_ps_header<File: Read + Seek>(
|
||||
file: &mut File,
|
||||
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||
fn load_ps_header<File: Read + Seek>(file: &mut File) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||
let mut buffer: [u8; 0x40] = [0; 0x40];
|
||||
file.read_exact(&mut buffer)?;
|
||||
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
||||
@@ -97,10 +91,7 @@ fn load_ps_header<File: Read + Seek>(
|
||||
|
||||
/// Locate the partition from the image, and return the size (in bytes) of the partition if successful.
|
||||
/// This function would seek the file to the location of the partition.
|
||||
fn locate<
|
||||
File: Read + Seek,
|
||||
F: Fn(&mut File) -> Result<Option<PartitionHeader>, BootgenLoadingError>,
|
||||
>(
|
||||
fn locate<File: Read + Seek, F: Fn(&mut File) -> Result<Option<PartitionHeader>, BootgenLoadingError>>(
|
||||
file: &mut File,
|
||||
f: F,
|
||||
) -> Result<usize, BootgenLoadingError> {
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::{rc::Rc,
|
||||
string::{FromUtf8Error, String},
|
||||
vec::Vec};
|
||||
use core::fmt;
|
||||
use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc};
|
||||
use core_io::{self as io, BufRead, BufReader, Read, Write, Seek, SeekFrom};
|
||||
|
||||
use core_io::{self as io, BufRead, BufReader, Read, Seek, SeekFrom, Write};
|
||||
use libboard_zynq::sdio;
|
||||
|
||||
pub mod sd_reader;
|
||||
pub mod net_settings;
|
||||
pub mod bootgen;
|
||||
pub mod net_settings;
|
||||
pub mod sd_reader;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error<'a> {
|
||||
@@ -51,11 +54,7 @@ impl<'a> From<FromUtf8Error> for Error<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_config<'a>(
|
||||
key: &'a str,
|
||||
buffer: &mut Vec<u8>,
|
||||
file: fatfs::File<sd_reader::SdReader>,
|
||||
) -> Result<'a, ()> {
|
||||
fn parse_config<'a>(key: &'a str, buffer: &mut Vec<u8>, file: fatfs::File<sd_reader::SdReader>) -> Result<'a, ()> {
|
||||
let prefix = [key, "="].concat().to_ascii_lowercase();
|
||||
for line in BufReader::new(file).lines() {
|
||||
let line = line?.to_ascii_lowercase();
|
||||
@@ -135,8 +134,8 @@ impl Config {
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
Err(_) => Err(Error::KeyNotFoundError(key))
|
||||
}
|
||||
Err(_) => Err(Error::KeyNotFoundError(key)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,20 +10,19 @@ pub struct NetAddresses {
|
||||
#[cfg(feature = "ipv6")]
|
||||
pub ipv6_ll_addr: IpAddress,
|
||||
#[cfg(feature = "ipv6")]
|
||||
pub ipv6_addr: Option<IpAddress>
|
||||
pub ipv6_addr: Option<IpAddress>,
|
||||
}
|
||||
|
||||
impl fmt::Display for NetAddresses {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "MAC={} IPv4={} ",
|
||||
self.hardware_addr, self.ipv4_addr)?;
|
||||
write!(f, "MAC={} IPv4={} ", self.hardware_addr, self.ipv4_addr)?;
|
||||
|
||||
#[cfg(feature = "ipv6")]
|
||||
{
|
||||
write!(f, "IPv6-LL={}", self.ipv6_ll_addr)?;
|
||||
match self.ipv6_addr {
|
||||
Some(addr) => write!(f, " {}", addr)?,
|
||||
None => write!(f, " IPv6: no configured address")?
|
||||
None => write!(f, " IPv6: no configured address")?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -75,11 +74,15 @@ pub fn get_addresses(cfg: &Config) -> NetAddresses {
|
||||
|
||||
#[cfg(feature = "ipv6")]
|
||||
let ipv6_ll_addr = IpAddress::v6(
|
||||
0xfe80, 0x0000, 0x0000, 0x0000,
|
||||
0xfe80,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x0000,
|
||||
(((hardware_addr.0[0] ^ 0x02) as u16) << 8) | (hardware_addr.0[1] as u16),
|
||||
((hardware_addr.0[2] as u16) << 8) | 0x00ff,
|
||||
0xfe00 | (hardware_addr.0[3] as u16),
|
||||
((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16));
|
||||
((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16),
|
||||
);
|
||||
|
||||
NetAddresses {
|
||||
hardware_addr,
|
||||
@@ -87,6 +90,6 @@ pub fn get_addresses(cfg: &Config) -> NetAddresses {
|
||||
#[cfg(feature = "ipv6")]
|
||||
ipv6_ll_addr,
|
||||
#[cfg(feature = "ipv6")]
|
||||
ipv6_addr
|
||||
ipv6_addr,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write};
|
||||
use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError};
|
||||
use log::debug;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write};
|
||||
use libboard_zynq::sdio::{CmdTransferError, sd_card::SdCard};
|
||||
use log::debug;
|
||||
|
||||
const MBR_SIGNATURE: [u8; 2] = [0x55, 0xAA];
|
||||
const PARTID_FAT12: u8 = 0x01;
|
||||
const PARTID_FAT16_LESS32M: u8 = 0x04;
|
||||
@@ -160,8 +161,8 @@ impl SdReader {
|
||||
self.read_exact(&mut buffer[..1])?;
|
||||
debug!("Partition ID: {:0X}", buffer[0]);
|
||||
match buffer[0] {
|
||||
PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 |
|
||||
PARTID_FAT16_LBA | PARTID_FAT32 | PARTID_FAT32_LBA => {}
|
||||
PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 | PARTID_FAT16_LBA | PARTID_FAT32 | PARTID_FAT32_LBA => {
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
@@ -192,11 +193,10 @@ impl Read for SdReader {
|
||||
if b.len() > 0 {
|
||||
// invalidate internal buffer
|
||||
self.invalidate_buffer();
|
||||
if let Err(_) = self.sd.read_block(
|
||||
self.byte_addr / BLOCK_SIZE as u32,
|
||||
(b.len() / BLOCK_SIZE) as u16,
|
||||
b,
|
||||
) {
|
||||
if let Err(_) = self
|
||||
.sd
|
||||
.read_block(self.byte_addr / BLOCK_SIZE as u32, (b.len() / BLOCK_SIZE) as u16, b)
|
||||
{
|
||||
// we have to allow partial read, as per the trait required
|
||||
return Ok(a.len());
|
||||
}
|
||||
@@ -239,11 +239,10 @@ impl Write for SdReader {
|
||||
if b.len() > 0 {
|
||||
self.flush()?;
|
||||
self.invalidate_buffer();
|
||||
if let Err(_) = self.sd.write_block(
|
||||
self.byte_addr / BLOCK_SIZE as u32,
|
||||
(b.len() / BLOCK_SIZE) as u16,
|
||||
b,
|
||||
) {
|
||||
if let Err(_) = self
|
||||
.sd
|
||||
.write_block(self.byte_addr / BLOCK_SIZE as u32, (b.len() / BLOCK_SIZE) as u16, b)
|
||||
{
|
||||
return Ok(a.len());
|
||||
}
|
||||
self.byte_addr += b.len() as u32;
|
||||
@@ -277,8 +276,7 @@ impl Seek for SdReader {
|
||||
return Err(Error::new(ErrorKind::InvalidInput, "Invalid address"));
|
||||
}
|
||||
let target_byte_addr = raw_target as u32;
|
||||
let address_same_block =
|
||||
self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32);
|
||||
let address_same_block = self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32);
|
||||
// if the buffer was invalidated, we consider seek as different block
|
||||
let same_block = address_same_block && self.index != BLOCK_SIZE;
|
||||
if !same_block {
|
||||
|
||||
@@ -61,11 +61,7 @@ pub unsafe fn enter_critical() -> bool {
|
||||
#[inline]
|
||||
pub unsafe fn exit_critical(enable: bool) {
|
||||
// https://stackoverflow.com/questions/40019929/temporarily-disable-interrupts-on-arm
|
||||
let mask: u32 = if enable {
|
||||
1 << 7
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let mask: u32 = if enable { 1 << 7 } else { 0 };
|
||||
asm!(
|
||||
"mrs r1, cpsr
|
||||
bic r1, r1, {}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use super::asm::{dmb, dsb};
|
||||
use super::l2c::*;
|
||||
use core::arch::asm;
|
||||
|
||||
use super::{asm::{dmb, dsb},
|
||||
l2c::*};
|
||||
|
||||
/// Invalidate TLBs
|
||||
#[inline(always)]
|
||||
pub fn tlbiall() {
|
||||
@@ -117,7 +118,7 @@ pub fn dcciall_l1() {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn dcciall() {
|
||||
pub fn dcciall() {
|
||||
dmb();
|
||||
dcciall_l1();
|
||||
dsb();
|
||||
@@ -139,14 +140,13 @@ fn cache_line_addrs(first_addr: usize, beyond_addr: usize) -> impl Iterator<Item
|
||||
|
||||
fn object_cache_line_addrs<T>(object: *const T) -> impl Iterator<Item = usize> {
|
||||
let first_addr = object.addr();
|
||||
let beyond_addr = object.addr() + core::mem::size_of::<T>();
|
||||
let beyond_addr = object.addr() + core::mem::size_of::<T>();
|
||||
cache_line_addrs(first_addr, beyond_addr)
|
||||
}
|
||||
|
||||
fn slice_cache_line_addrs<T>(slice: &[T]) -> impl Iterator<Item = usize> {
|
||||
let first_addr = (&raw const slice[0]).addr();
|
||||
let beyond_addr = (&raw const slice[slice.len() - 1]).addr() +
|
||||
core::mem::size_of_val(&slice[slice.len() - 1]);
|
||||
let beyond_addr = (&raw const slice[slice.len() - 1]).addr() + core::mem::size_of_val(&slice[slice.len() - 1]);
|
||||
cache_line_addrs(first_addr, beyond_addr)
|
||||
}
|
||||
|
||||
@@ -247,7 +247,11 @@ pub unsafe fn dci<T>(object: &mut T) {
|
||||
let first_addr = object as *const _ as usize;
|
||||
let beyond_addr = (object as *const _ as usize) + core::mem::size_of_val(object);
|
||||
assert_eq!(first_addr & CACHE_LINE_MASK, 0, "dci object first_addr must be aligned");
|
||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci object beyond_addr must be aligned");
|
||||
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) {
|
||||
@@ -262,10 +266,13 @@ pub unsafe fn dci<T>(object: &mut T) {
|
||||
|
||||
pub unsafe fn dci_slice<T>(slice: &mut [T]) {
|
||||
let first_addr = &slice[0] as *const _ as usize;
|
||||
let beyond_addr = (&slice[slice.len() - 1] as *const _ as usize) +
|
||||
core::mem::size_of_val(&slice[slice.len() - 1]);
|
||||
let beyond_addr = (&slice[slice.len() - 1] as *const _ as usize) + core::mem::size_of_val(&slice[slice.len() - 1]);
|
||||
assert_eq!(first_addr & CACHE_LINE_MASK, 0, "dci slice first_addr must be aligned");
|
||||
assert_eq!(beyond_addr & CACHE_LINE_MASK, 0, "dci slice beyond_addr must be aligned");
|
||||
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) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use libregister::{register, register_at, register_bit, register_bits, RegisterRW, RegisterR, RegisterW};
|
||||
use super::asm::dmb;
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW, register, register_at, register_bit, register_bits};
|
||||
use volatile_register::RW;
|
||||
|
||||
use super::asm::dmb;
|
||||
|
||||
/// enable L2 cache with specific prefetch offset
|
||||
/// prefetch offset requires manual tuning, it seems that 8 is good for ZC706 current settings
|
||||
pub fn enable_l2_cache(offset: u8) {
|
||||
@@ -10,14 +11,14 @@ pub fn enable_l2_cache(offset: u8) {
|
||||
// disable L2 cache
|
||||
regs.reg1_control.modify(|_, w| w.l2_enable(false));
|
||||
|
||||
regs.reg15_prefetch_ctrl.modify(|_, w|
|
||||
regs.reg15_prefetch_ctrl.modify(|_, w| {
|
||||
w.instr_prefetch_en(true)
|
||||
.data_prefetch_en(true)
|
||||
.double_linefill_en(true)
|
||||
.incr_double_linefill_en(true)
|
||||
.pref_drop_en(true)
|
||||
.prefetch_offset(offset)
|
||||
);
|
||||
});
|
||||
regs.reg1_aux_control.modify(|_, w| {
|
||||
w.early_bresp_en(true)
|
||||
.instr_prefetch_en(true)
|
||||
@@ -25,8 +26,10 @@ pub fn enable_l2_cache(offset: u8) {
|
||||
.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));
|
||||
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);
|
||||
@@ -45,7 +48,7 @@ pub fn enable_l2_cache(offset: u8) {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_invalidate_all() {
|
||||
pub fn l2_cache_invalidate_all() {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_inv_way.write(0xFFFF);
|
||||
@@ -55,9 +58,9 @@ pub fn l2_cache_invalidate_all() {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_clean_all() {
|
||||
pub fn l2_cache_clean_all() {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
unsafe {
|
||||
regs.reg7_clean_way.write(0xFFFF);
|
||||
}
|
||||
// poll for completion
|
||||
@@ -65,7 +68,7 @@ pub fn l2_cache_clean_all() {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn l2_cache_clean_invalidate_all() {
|
||||
pub fn l2_cache_clean_invalidate_all() {
|
||||
let regs = RegisterBlock::new();
|
||||
unsafe {
|
||||
regs.reg7_clean_inv_way.write(0xFFFF);
|
||||
@@ -330,4 +333,3 @@ register_bit!(reg15_prefetch_ctrl, data_prefetch_en, 28);
|
||||
register_bit!(reg15_prefetch_ctrl, pref_drop_en, 24);
|
||||
register_bit!(reg15_prefetch_ctrl, incr_double_linefill_en, 23);
|
||||
register_bits!(reg15_prefetch_ctrl, prefetch_offset, u8, 0, 4);
|
||||
|
||||
|
||||
@@ -13,9 +13,10 @@ pub mod regs;
|
||||
pub mod semaphore;
|
||||
pub mod sync_channel;
|
||||
mod uncached;
|
||||
use core::arch::global_asm;
|
||||
|
||||
pub use fpu::enable_fpu;
|
||||
pub use uncached::UncachedSlice;
|
||||
use core::arch::global_asm;
|
||||
|
||||
global_asm!(include_str!("exceptions.s"));
|
||||
|
||||
@@ -37,7 +38,7 @@ pub fn notify_spin_lock() {
|
||||
#[macro_export]
|
||||
/// Interrupt handler, which setup the stack and preserve registers before jumping to actual interrupt handler.
|
||||
/// Registers r0-r12, PC, SP and CPSR are restored after the actual handler.
|
||||
///
|
||||
///
|
||||
/// - `name` is the name of the interrupt, should be the same as the one defined in vector table.
|
||||
/// - `name2` is the name for the actual handler, should be different from name.
|
||||
/// - `stack0` is the stack for the interrupt handler when called from core0.
|
||||
@@ -65,11 +66,11 @@ macro_rules! interrupt_handler {
|
||||
concat!("movtne r1, :upper16:", stringify!($stack1)),
|
||||
"mov r0, sp",
|
||||
"mov sp, r1",
|
||||
"push {{r0, r1}}", // 2 registers are pushed to maintain 8 byte stack alignment
|
||||
"push {{r0, r1}}", // 2 registers are pushed to maintain 8 byte stack alignment
|
||||
concat!("bl ", stringify!($name2)),
|
||||
"pop {{r0, r1}}",
|
||||
"mov sp, r0",
|
||||
"ldmfd sp!, {{r0-r12, pc}}^" // caret ^ : copy SPSR to the CPSR
|
||||
"ldmfd sp!, {{r0-r12, pc}}^" // caret ^ : copy SPSR to the CPSR
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use bit_field::BitField;
|
||||
use super::{regs::*, asm::*, cache::*};
|
||||
use libregister::RegisterW;
|
||||
|
||||
use super::{asm::*, cache::*, regs::*};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum AccessDomain {
|
||||
@@ -40,14 +41,12 @@ pub enum AccessPermissions {
|
||||
_Reserved1,
|
||||
PrivilegedReadOnly,
|
||||
ReadOnly,
|
||||
_Reserved2
|
||||
_Reserved2,
|
||||
}
|
||||
|
||||
impl AccessPermissions {
|
||||
fn new(ap: u8, apx: bool) -> Self {
|
||||
unsafe {
|
||||
core::mem::transmute(if apx { 0b100 } else { 0 } | ap)
|
||||
}
|
||||
unsafe { core::mem::transmute(if apx { 0b100 } else { 0 } | ap) }
|
||||
}
|
||||
|
||||
fn ap(&self) -> u8 {
|
||||
@@ -91,10 +90,7 @@ impl L1Entry {
|
||||
|
||||
pub fn get_section(&mut self) -> L1Section {
|
||||
assert_eq!(self.0.get_bits(0..=1), ENTRY_TYPE_SECTION);
|
||||
let access = AccessPermissions::new(
|
||||
self.0.get_bits(10..=11) as u8,
|
||||
self.0.get_bit(15)
|
||||
);
|
||||
let access = AccessPermissions::new(self.0.get_bits(10..=11) as u8, self.0.get_bit(15));
|
||||
L1Section {
|
||||
global: !self.0.get_bit(17),
|
||||
shareable: self.0.get_bit(16),
|
||||
@@ -125,12 +121,12 @@ impl L1Entry {
|
||||
|
||||
const L1_TABLE_SIZE: usize = 4096;
|
||||
static mut L1_TABLE: L1Table = L1Table {
|
||||
table: [L1Entry(0); L1_TABLE_SIZE]
|
||||
table: [L1Entry(0); L1_TABLE_SIZE],
|
||||
};
|
||||
|
||||
#[repr(C, align(16384))]
|
||||
pub struct L1Table {
|
||||
table: [L1Entry; L1_TABLE_SIZE]
|
||||
table: [L1Entry; L1_TABLE_SIZE],
|
||||
}
|
||||
|
||||
impl L1Table {
|
||||
@@ -141,210 +137,258 @@ impl L1Table {
|
||||
|
||||
pub fn setup_flat_layout(&mut self) -> &Self {
|
||||
/* 0x00000000 - 0x00100000 (cacheable) */
|
||||
self.direct_mapped_section(0, L1Section {
|
||||
global: true,
|
||||
shareable: true,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0b101,
|
||||
domain: 0b1111,
|
||||
exec: true,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
});
|
||||
/* (DDR cacheable) */
|
||||
for ddr in 1..=0x3ff {
|
||||
self.direct_mapped_section(ddr, L1Section {
|
||||
self.direct_mapped_section(
|
||||
0,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: true,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0b0,
|
||||
tex: 0b101,
|
||||
domain: 0b1111,
|
||||
exec: true,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
/* (DDR cacheable) */
|
||||
for ddr in 1..=0x3ff {
|
||||
self.direct_mapped_section(
|
||||
ddr,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: true,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0b0,
|
||||
domain: 0b1111,
|
||||
exec: true,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0x40000000 - 0x7fffffff (FPGA slave0) */
|
||||
for fpga_slave in 0x400..=0x7ff {
|
||||
self.direct_mapped_section(fpga_slave, L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
});
|
||||
self.direct_mapped_section(
|
||||
fpga_slave,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0x80000000 - 0xbfffffff (FPGA slave1) */
|
||||
for fpga_slave in 0x800..=0xbff {
|
||||
self.direct_mapped_section(fpga_slave, L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
});
|
||||
self.direct_mapped_section(
|
||||
fpga_slave,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xc0000000 - 0xdfffffff (unassigned/reserved). */
|
||||
for undef in 0xc00..=0xdff {
|
||||
self.direct_mapped_section(undef, L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
});
|
||||
self.direct_mapped_section(
|
||||
undef,
|
||||
L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xe0000000 - 0xe02fffff (Memory mapped devices)
|
||||
* UART/USB/IIC/SPI/CAN/GEM/GPIO/QSPI/SD/NAND */
|
||||
for mmapped_dev in 0xe00..=0xe02 {
|
||||
self.direct_mapped_section(mmapped_dev, L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
});
|
||||
self.direct_mapped_section(
|
||||
mmapped_dev,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xe0300000 - 0xe0ffffff (unassigned/reserved). */
|
||||
for undef in 0xe03..=0xe0f {
|
||||
self.direct_mapped_section(undef, L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
});
|
||||
self.direct_mapped_section(
|
||||
undef,
|
||||
L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xe1000000 - 0xe1ffffff (NAND) */
|
||||
for nand in 0xe10..=0xe1f {
|
||||
self.direct_mapped_section(nand, L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
});
|
||||
self.direct_mapped_section(
|
||||
nand,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xe2000000 - 0xe3ffffff (NOR) */
|
||||
for nor in 0xe20..=0xe3f {
|
||||
self.direct_mapped_section(nor, L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
});
|
||||
self.direct_mapped_section(
|
||||
nor,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xe4000000 - 0xe5ffffff (SRAM) */
|
||||
for nor in 0xe40..=0xe5f {
|
||||
self.direct_mapped_section(nor, L1Section {
|
||||
self.direct_mapped_section(
|
||||
nor,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xe6000000 - 0xf7ffffff (unassigned/reserved). */
|
||||
for undef in 0xe60..=0xf7f {
|
||||
self.direct_mapped_section(
|
||||
undef,
|
||||
L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xf8000000 - 0xf8ffffff (AMBA APB Peripherals) */
|
||||
for apb in 0xf80..=0xf8f {
|
||||
self.direct_mapped_section(
|
||||
apb,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xf9000000 - 0xfbffffff (unassigned/reserved). */
|
||||
for undef in 0xf90..=0xfbf {
|
||||
self.direct_mapped_section(
|
||||
undef,
|
||||
L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xfc000000 - 0xfdffffff (Linear QSPI - XIP) */
|
||||
for qspi in 0xfc0..=0xfdf {
|
||||
self.direct_mapped_section(
|
||||
qspi,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xfe000000 - 0xffefffff (unassigned/reserved). */
|
||||
for undef in 0xfe0..=0xffe {
|
||||
self.direct_mapped_section(
|
||||
undef,
|
||||
L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
/* 0xfff00000 - 0xffffffff (256K OCM when mapped to high address space) */
|
||||
self.direct_mapped_section(
|
||||
0xfff,
|
||||
L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
shareable: true,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
tex: 0b100,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
});
|
||||
}
|
||||
/* 0xe6000000 - 0xf7ffffff (unassigned/reserved). */
|
||||
for undef in 0xe60..=0xf7f {
|
||||
self.direct_mapped_section(undef, L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
});
|
||||
}
|
||||
/* 0xf8000000 - 0xf8ffffff (AMBA APB Peripherals) */
|
||||
for apb in 0xf80..=0xf8f {
|
||||
self.direct_mapped_section(apb, L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
});
|
||||
}
|
||||
/* 0xf9000000 - 0xfbffffff (unassigned/reserved). */
|
||||
for undef in 0xf90..=0xfbf {
|
||||
self.direct_mapped_section(undef, L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
});
|
||||
}
|
||||
/* 0xfc000000 - 0xfdffffff (Linear QSPI - XIP) */
|
||||
for qspi in 0xfc0..=0xfdf {
|
||||
self.direct_mapped_section(qspi, L1Section {
|
||||
global: true,
|
||||
shareable: false,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: false,
|
||||
bufferable: true,
|
||||
});
|
||||
}
|
||||
/* 0xfe000000 - 0xffefffff (unassigned/reserved). */
|
||||
for undef in 0xfe0..=0xffe {
|
||||
self.direct_mapped_section(undef, L1Section {
|
||||
global: false,
|
||||
shareable: false,
|
||||
access: AccessPermissions::PermissionFault,
|
||||
tex: 0,
|
||||
domain: 0,
|
||||
exec: false,
|
||||
cacheable: false,
|
||||
bufferable: false,
|
||||
});
|
||||
}
|
||||
/* 0xfff00000 - 0xffffffff (256K OCM when mapped to high address space) */
|
||||
self.direct_mapped_section(0xfff, L1Section {
|
||||
global: true,
|
||||
shareable: true,
|
||||
access: AccessPermissions::FullAccess,
|
||||
tex: 0b100,
|
||||
domain: 0,
|
||||
exec: true,
|
||||
cacheable: true,
|
||||
bufferable: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
self
|
||||
}
|
||||
@@ -358,9 +402,7 @@ impl L1Table {
|
||||
}
|
||||
|
||||
pub fn update<T, F, R>(&mut self, ptr: *const T, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&'_ mut L1Section) -> R,
|
||||
{
|
||||
where F: FnOnce(&'_ mut L1Section) -> R {
|
||||
let index = (ptr as usize) >> 20;
|
||||
let entry = &mut self.table[index];
|
||||
let mut section = entry.get_section();
|
||||
@@ -385,7 +427,6 @@ impl L1Table {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn with_mmu<F: FnMut() -> !>(l1table: &L1Table, mut f: F) -> ! {
|
||||
let domains = AccessDomains::all_manager();
|
||||
DACR.write(domains.into());
|
||||
@@ -399,19 +440,11 @@ pub fn with_mmu<F: FnMut() -> !>(l1table: &L1Table, mut f: F) -> ! {
|
||||
// Outer Cacheable Write-Back, no allocate on write.
|
||||
.rgn(0b11)
|
||||
.irgn0(true)
|
||||
.table_base(table_base >> 14)
|
||||
.table_base(table_base >> 14),
|
||||
);
|
||||
|
||||
// Enable I-Cache and D-Cache
|
||||
SCTLR.write(
|
||||
SCTLR::zeroed()
|
||||
.m(true)
|
||||
.a(false)
|
||||
.c(true)
|
||||
.i(true)
|
||||
.z(true)
|
||||
.unaligned(true)
|
||||
);
|
||||
SCTLR.write(SCTLR::zeroed().m(true).a(false).c(true).i(true).z(true).unaligned(true));
|
||||
|
||||
// Synchronization barriers
|
||||
// Allows MMU to start
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
use core::cell::UnsafeCell;
|
||||
use core::task::{Context, Poll};
|
||||
use core::pin::Pin;
|
||||
use core::future::Future;
|
||||
use super::{
|
||||
spin_lock_yield, notify_spin_lock,
|
||||
asm::{enter_critical, exit_critical}
|
||||
};
|
||||
use core::{cell::UnsafeCell,
|
||||
future::Future,
|
||||
ops::{Deref, DerefMut},
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
task::{Context, Poll}};
|
||||
|
||||
use super::{asm::{enter_critical, exit_critical},
|
||||
notify_spin_lock, spin_lock_yield};
|
||||
|
||||
const LOCKED: u32 = 1;
|
||||
const UNLOCKED: u32 = 0;
|
||||
@@ -29,12 +28,16 @@ impl<'a, T> Future for Fut<'a, T> {
|
||||
type Output = MutexGuard<'a, T>;
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let irq = unsafe { enter_critical() };
|
||||
if self.0.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
|
||||
if self
|
||||
.0
|
||||
.locked
|
||||
.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
unsafe { exit_critical(irq) };
|
||||
cx.waker().wake_by_ref();
|
||||
Poll::Pending
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Poll::Ready(MutexGuard { mutex: self.0, irq })
|
||||
}
|
||||
}
|
||||
@@ -43,7 +46,7 @@ impl<'a, T> Future for Fut<'a, T> {
|
||||
impl<T> Mutex<T> {
|
||||
/// Constructor, const-fn
|
||||
pub const fn new(inner: T) -> Self {
|
||||
Mutex{
|
||||
Mutex {
|
||||
locked: AtomicU32::new(UNLOCKED),
|
||||
inner: UnsafeCell::new(inner),
|
||||
}
|
||||
@@ -52,7 +55,11 @@ impl<T> Mutex<T> {
|
||||
/// Lock the Mutex, blocks when already locked
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
let mut irq = unsafe { enter_critical() };
|
||||
while self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
|
||||
while self
|
||||
.locked
|
||||
.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
unsafe {
|
||||
exit_critical(irq);
|
||||
spin_lock_yield();
|
||||
@@ -68,7 +75,11 @@ impl<T> Mutex<T> {
|
||||
|
||||
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
|
||||
let irq = unsafe { enter_critical() };
|
||||
if self.locked.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed).is_err() {
|
||||
if self
|
||||
.locked
|
||||
.compare_exchange_weak(UNLOCKED, LOCKED, Ordering::AcqRel, Ordering::Relaxed)
|
||||
.is_err()
|
||||
{
|
||||
unsafe { exit_critical(irq) };
|
||||
None
|
||||
} else {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use libregister::{
|
||||
register_bit, register_bits,
|
||||
RegisterR, RegisterW, RegisterRW,
|
||||
};
|
||||
use core::arch::asm;
|
||||
|
||||
use libregister::{RegisterR, RegisterRW, RegisterW, register_bit, register_bits};
|
||||
|
||||
macro_rules! def_reg_r {
|
||||
($name:tt, $type: ty, $asm_instr:tt) => {
|
||||
impl RegisterR for $name {
|
||||
@@ -39,7 +37,7 @@ macro_rules! def_reg_w {
|
||||
}
|
||||
|
||||
macro_rules! wrap_reg {
|
||||
($mod_name: ident) => {
|
||||
($mod_name:ident) => {
|
||||
pub mod $mod_name {
|
||||
pub struct Read {
|
||||
pub inner: u32,
|
||||
@@ -67,7 +65,7 @@ macro_rules! wrap_reg {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Stack Pointer
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
use super::{spin_lock_yield, notify_spin_lock};
|
||||
use core::{
|
||||
task::{Context, Poll},
|
||||
pin::Pin,
|
||||
future::Future,
|
||||
sync::atomic::{AtomicI32, Ordering}
|
||||
};
|
||||
use core::{future::Future,
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicI32, Ordering},
|
||||
task::{Context, Poll}};
|
||||
|
||||
use super::{notify_spin_lock, spin_lock_yield};
|
||||
|
||||
pub struct Semaphore {
|
||||
value: AtomicI32,
|
||||
max: i32
|
||||
max: i32,
|
||||
}
|
||||
|
||||
impl Semaphore {
|
||||
pub const fn new(value: i32, max: i32) -> Self {
|
||||
Semaphore { value: AtomicI32::new(value), max}
|
||||
Semaphore {
|
||||
value: AtomicI32::new(value),
|
||||
max,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_wait(&self) -> Option<()> {
|
||||
loop {
|
||||
let value = self.value.load(Ordering::Relaxed);
|
||||
if value > 0 {
|
||||
if self.value.compare_exchange_weak(value, value - 1, Ordering::SeqCst, Ordering::Relaxed).is_ok() {
|
||||
if self
|
||||
.value
|
||||
.compare_exchange_weak(value, value - 1, Ordering::SeqCst, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
return Some(());
|
||||
}
|
||||
} else {
|
||||
@@ -58,7 +64,11 @@ impl Semaphore {
|
||||
loop {
|
||||
let value = self.value.load(Ordering::Relaxed);
|
||||
if value < self.max {
|
||||
if self.value.compare_exchange_weak(value, value + 1, Ordering::SeqCst, Ordering::Relaxed).is_ok() {
|
||||
if self
|
||||
.value
|
||||
.compare_exchange_weak(value, value + 1, Ordering::SeqCst, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
notify_spin_lock();
|
||||
return;
|
||||
}
|
||||
@@ -68,4 +78,3 @@ impl Semaphore {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
use core::{
|
||||
pin::Pin,
|
||||
future::Future,
|
||||
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
|
||||
task::{Context, Poll},
|
||||
};
|
||||
use alloc::boxed::Box;
|
||||
use super::{spin_lock_yield, notify_spin_lock};
|
||||
use core::{future::Future,
|
||||
pin::Pin,
|
||||
sync::atomic::{AtomicPtr, AtomicUsize, Ordering},
|
||||
task::{Context, Poll}};
|
||||
|
||||
pub struct Sender<'a, T> where T: Clone {
|
||||
use super::{notify_spin_lock, spin_lock_yield};
|
||||
|
||||
pub struct Sender<'a, T>
|
||||
where T: Clone
|
||||
{
|
||||
list: &'a [AtomicPtr<T>],
|
||||
write: &'a AtomicUsize,
|
||||
read: &'a AtomicUsize,
|
||||
}
|
||||
|
||||
pub struct Receiver<'a, T> where T: Clone {
|
||||
pub struct Receiver<'a, T>
|
||||
where T: Clone
|
||||
{
|
||||
list: &'a [AtomicPtr<T>],
|
||||
write: &'a AtomicUsize,
|
||||
read: &'a AtomicUsize,
|
||||
}
|
||||
|
||||
impl<'a, T> Sender<'a, T> where T: Clone {
|
||||
impl<'a, T> Sender<'a, T>
|
||||
where T: Clone
|
||||
{
|
||||
pub const fn new(list: &'static [AtomicPtr<T>], write: &'static AtomicUsize, read: &'static AtomicUsize) -> Self {
|
||||
Sender {list, write, read}
|
||||
Sender { list, write, read }
|
||||
}
|
||||
|
||||
pub fn try_send<B: Into<Box<T>>>(&mut self, content: B) -> Result<(), B> {
|
||||
@@ -53,12 +58,18 @@ impl<'a, T> Sender<'a, T> where T: Clone {
|
||||
}
|
||||
|
||||
pub async fn async_send<B: Into<Box<T>>>(&mut self, content: B) {
|
||||
struct Send<'a, 'b, T> where T: Clone, 'b: 'a {
|
||||
struct Send<'a, 'b, T>
|
||||
where
|
||||
T: Clone,
|
||||
'b: 'a,
|
||||
{
|
||||
sender: &'a mut Sender<'b, T>,
|
||||
content: Result<(), Box<T>>,
|
||||
}
|
||||
|
||||
impl<T> Future for Send<'_, '_, T> where T: Clone {
|
||||
impl<T> Future for Send<'_, '_, T>
|
||||
where T: Clone
|
||||
{
|
||||
type Output = ();
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
@@ -82,7 +93,8 @@ impl<'a, T> Sender<'a, T> where T: Clone {
|
||||
Send {
|
||||
sender: self,
|
||||
content: Err(content.into()),
|
||||
}.await
|
||||
}
|
||||
.await
|
||||
}
|
||||
|
||||
/// free all items in the queue. It is the user's responsibility to
|
||||
@@ -107,9 +119,11 @@ impl<'a, T> Sender<'a, T> where T: Clone {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Receiver<'a, T> where T: Clone {
|
||||
impl<'a, T> Receiver<'a, T>
|
||||
where T: Clone
|
||||
{
|
||||
pub const fn new(list: &'static [AtomicPtr<T>], write: &'static AtomicUsize, read: &'static AtomicUsize) -> Self {
|
||||
Receiver {list, write, read}
|
||||
Receiver { list, write, read }
|
||||
}
|
||||
|
||||
pub fn try_recv(&mut self) -> Result<T, ()> {
|
||||
@@ -139,11 +153,17 @@ impl<'a, T> Receiver<'a, T> where T: Clone {
|
||||
}
|
||||
|
||||
pub async fn async_recv(&mut self) -> T {
|
||||
struct Recv<'a, 'b, T> where T: Clone, 'b: 'a {
|
||||
struct Recv<'a, 'b, T>
|
||||
where
|
||||
T: Clone,
|
||||
'b: 'a,
|
||||
{
|
||||
receiver: &'a mut Receiver<'b, T>,
|
||||
}
|
||||
|
||||
impl<T> Future for Recv<'_, '_, T> where T: Clone {
|
||||
impl<T> Future for Recv<'_, '_, T>
|
||||
where T: Clone
|
||||
{
|
||||
type Output = T;
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
@@ -156,13 +176,13 @@ impl<'a, T> Receiver<'a, T> where T: Clone {
|
||||
}
|
||||
}
|
||||
|
||||
Recv {
|
||||
receiver: self,
|
||||
}.await
|
||||
Recv { receiver: self }.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Iterator for Receiver<'a, T> where T: Clone {
|
||||
impl<'a, T> Iterator for Receiver<'a, T>
|
||||
where T: Clone
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
@@ -173,14 +193,13 @@ impl<'a, T> Iterator for Receiver<'a, T> where T: Clone {
|
||||
#[macro_export]
|
||||
/// Macro for initializing the sync_channel with static buffer and indexes.
|
||||
macro_rules! sync_channel {
|
||||
($t: ty, $cap: expr) => {
|
||||
{
|
||||
use core::sync::atomic::{AtomicUsize, AtomicPtr};
|
||||
use $crate::sync_channel::{Sender, Receiver};
|
||||
static LIST: [AtomicPtr<$t>; $cap + 1] = [const { AtomicPtr::new(core::ptr::null_mut()) }; $cap + 1];
|
||||
static WRITE: AtomicUsize = AtomicUsize::new(0);
|
||||
static READ: AtomicUsize = AtomicUsize::new(0);
|
||||
(Sender::new(&LIST, &WRITE, &READ), Receiver::new(&LIST, &WRITE, &READ))
|
||||
}
|
||||
};
|
||||
($t:ty, $cap:expr) => {{
|
||||
use core::sync::atomic::{AtomicPtr, AtomicUsize};
|
||||
|
||||
use $crate::sync_channel::{Receiver, Sender};
|
||||
static LIST: [AtomicPtr<$t>; $cap + 1] = [const { AtomicPtr::new(core::ptr::null_mut()) }; $cap + 1];
|
||||
static WRITE: AtomicUsize = AtomicUsize::new(0);
|
||||
static READ: AtomicUsize = AtomicUsize::new(0);
|
||||
(Sender::new(&LIST, &WRITE, &READ), Receiver::new(&LIST, &WRITE, &READ))
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
mem::{align_of, size_of},
|
||||
};
|
||||
use alloc::alloc::{dealloc, Layout, LayoutError};
|
||||
use alloc::alloc::{Layout, LayoutError, dealloc};
|
||||
use core::{mem::{align_of, size_of},
|
||||
ops::{Deref, DerefMut}};
|
||||
|
||||
use crate::mmu::{L1_PAGE_SIZE, L1Table};
|
||||
|
||||
pub struct UncachedSlice<T: 'static> {
|
||||
@@ -15,8 +14,7 @@ impl<T> UncachedSlice<T> {
|
||||
pub fn new<F: Fn() -> T>(len: usize, default: F) -> Result<Self, LayoutError> {
|
||||
// round to full pages
|
||||
let size = ((len * size_of::<T>() - 1) | (L1_PAGE_SIZE - 1)) + 1;
|
||||
let align = align_of::<T>()
|
||||
.max(L1_PAGE_SIZE);
|
||||
let align = align_of::<T>().max(L1_PAGE_SIZE);
|
||||
let layout = Layout::from_size_align(size, align)?;
|
||||
let ptr = unsafe { alloc::alloc::alloc(layout).cast::<T>() };
|
||||
assert!(!ptr.is_null());
|
||||
@@ -24,12 +22,11 @@ impl<T> UncachedSlice<T> {
|
||||
|
||||
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 = 0b10;
|
||||
l1_section.cacheable = true;
|
||||
l1_section.bufferable = false;
|
||||
});
|
||||
L1Table::get().update(page_start as *const (), |l1_section| {
|
||||
l1_section.tex = 0b10;
|
||||
l1_section.cacheable = true;
|
||||
l1_section.bufferable = false;
|
||||
});
|
||||
}
|
||||
|
||||
let slice = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
#![no_std]
|
||||
|
||||
pub use vcell::VolatileCell;
|
||||
pub use volatile_register::{RO, WO, RW};
|
||||
pub use bit_field::BitField;
|
||||
pub use vcell::VolatileCell;
|
||||
pub use volatile_register::{RO, RW, WO};
|
||||
|
||||
/// A readable register
|
||||
pub trait RegisterR {
|
||||
@@ -52,7 +52,7 @@ macro_rules! register_common {
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! register_r {
|
||||
($mod_name: ident, $struct_name: ident) => (
|
||||
($mod_name:ident, $struct_name:ident) => {
|
||||
impl $crate::RegisterR for $struct_name {
|
||||
type R = $mod_name::Read;
|
||||
|
||||
@@ -62,12 +62,12 @@ macro_rules! register_r {
|
||||
$mod_name::Read { inner }
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! register_w {
|
||||
($mod_name: ident, $struct_name: ident) => (
|
||||
($mod_name:ident, $struct_name:ident) => {
|
||||
impl $crate::RegisterW for $struct_name {
|
||||
type W = $mod_name::Write;
|
||||
|
||||
@@ -83,43 +83,46 @@ macro_rules! register_w {
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! register_rw {
|
||||
($mod_name: ident, $struct_name: ident) => (
|
||||
($mod_name:ident, $struct_name:ident) => {
|
||||
impl $crate::RegisterRW for $struct_name {
|
||||
#[inline]
|
||||
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
||||
unsafe {
|
||||
self.inner
|
||||
.modify(|inner| f($mod_name::Read { inner }, $mod_name::Write { inner }).inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
($mod_name:ident, $struct_name:ident, $mask:expr) => {
|
||||
impl $crate::RegisterRW for $struct_name {
|
||||
#[inline]
|
||||
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
||||
unsafe {
|
||||
self.inner.modify(|inner| {
|
||||
f($mod_name::Read { inner }, $mod_name::Write { inner })
|
||||
.inner
|
||||
f(
|
||||
$mod_name::Read { inner },
|
||||
$mod_name::Write {
|
||||
inner: inner & ($mask),
|
||||
},
|
||||
)
|
||||
.inner
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
($mod_name: ident, $struct_name: ident, $mask: expr) => (
|
||||
impl $crate::RegisterRW for $struct_name {
|
||||
#[inline]
|
||||
fn modify<F: FnOnce(Self::R, Self::W) -> Self::W>(&mut self, f: F) {
|
||||
unsafe {
|
||||
self.inner.modify(|inner| {
|
||||
f($mod_name::Read { inner }, $mod_name::Write { inner: inner & ($mask) })
|
||||
.inner
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! register_vcell {
|
||||
($mod_name: ident, $struct_name: ident) => (
|
||||
($mod_name:ident, $struct_name:ident) => {
|
||||
impl $crate::RegisterR for $struct_name {
|
||||
type R = $mod_name::Read;
|
||||
|
||||
@@ -151,7 +154,7 @@ macro_rules! register_vcell {
|
||||
self.write(w);
|
||||
}
|
||||
}
|
||||