fw: update some drivers for LiteX
Still need to re-do some stuff and clean up, but it runs on LiteX now
This commit is contained in:
parent
c5db01c70f
commit
35a8841aa5
@ -14,30 +14,22 @@
|
|||||||
// - Slots are sized to ethernet MTU (1530), and addressed by the closest log2
|
// - Slots are sized to ethernet MTU (1530), and addressed by the closest log2
|
||||||
// thing, so 2048 bytes each
|
// thing, so 2048 bytes each
|
||||||
|
|
||||||
const LITEETH_BASE: u32 = 0x0300_0000;
|
|
||||||
|
|
||||||
const CTRL_RESET: u32 = 0x000;
|
|
||||||
const CTRL_SCRATCH: u32 = 0x004;
|
|
||||||
|
|
||||||
// Writer, or RX register blocks
|
// Writer, or RX register blocks
|
||||||
const ETHMAC_SRAM_WRITER_SLOT: u32 = 0x800;
|
const ETHMAC_SRAM_WRITER_SLOT: u32 = 0x000;
|
||||||
const ETHMAC_SRAM_WRITER_LENGTH: u32 = 0x804;
|
const ETHMAC_SRAM_WRITER_LENGTH: u32 = 0x004;
|
||||||
const ETHMAC_SRAM_WRITER_EV_STATUS: u32 = 0x80c;
|
const ETHMAC_SRAM_WRITER_EV_STATUS: u32 = 0x00c;
|
||||||
const ETHMAC_SRAM_WRITER_EV_PENDING: u32 = 0x810;
|
const ETHMAC_SRAM_WRITER_EV_PENDING: u32 = 0x010;
|
||||||
const ETHMAC_SRAM_WRITER_EV_ENABLE: u32 = 0x814;
|
const ETHMAC_SRAM_WRITER_EV_ENABLE: u32 = 0x014;
|
||||||
|
|
||||||
// Reader, or TX register blocks
|
// Reader, or TX register blocks
|
||||||
const ETHMAC_SRAM_READER_START: u32 = 0x818;
|
const ETHMAC_SRAM_READER_START: u32 = 0x018;
|
||||||
const ETHMAC_SRAM_READER_READY: u32 = 0x81c;
|
const ETHMAC_SRAM_READER_READY: u32 = 0x01c;
|
||||||
const ETHMAC_SRAM_READER_LEVEL: u32 = 0x820;
|
const ETHMAC_SRAM_READER_LEVEL: u32 = 0x020;
|
||||||
const ETHMAC_SRAM_READER_SLOT: u32 = 0x824;
|
const ETHMAC_SRAM_READER_SLOT: u32 = 0x024;
|
||||||
const ETHMAC_SRAM_READER_LENGTH: u32 = 0x828;
|
const ETHMAC_SRAM_READER_LENGTH: u32 = 0x028;
|
||||||
const ETHMAC_SRAM_READER_EV_STATUS: u32 = 0x82c;
|
const ETHMAC_SRAM_READER_EV_STATUS: u32 = 0x02c;
|
||||||
const ETHMAC_SRAM_READER_EV_PENDING: u32 = 0x830;
|
const ETHMAC_SRAM_READER_EV_PENDING: u32 = 0x030;
|
||||||
const ETHMAC_SRAM_READER_EV_ENABLE: u32 = 0x834;
|
const ETHMAC_SRAM_READER_EV_ENABLE: u32 = 0x014;
|
||||||
|
|
||||||
// Offset of ETHMAC SRAM from base
|
|
||||||
const ETHMAC_OFFSET: u32 = 0x0002_0000;
|
|
||||||
|
|
||||||
const NUM_RX_SLOTS: u32 = 2;
|
const NUM_RX_SLOTS: u32 = 2;
|
||||||
const NUM_TX_SLOTS: u32 = 2;
|
const NUM_TX_SLOTS: u32 = 2;
|
||||||
@ -69,15 +61,6 @@ impl LiteEthDevice {
|
|||||||
/// Initialises the device and returns an instance. Unsafe because there are
|
/// Initialises the device and returns an instance. Unsafe because there are
|
||||||
/// no checks for other users.
|
/// no checks for other users.
|
||||||
pub unsafe fn try_init(csr_addr: u32, ethmac_addr: u32) -> Option<Self> {
|
pub unsafe fn try_init(csr_addr: u32, ethmac_addr: u32) -> Option<Self> {
|
||||||
if !LiteEthDevice::check_wishbone_access(csr_addr) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
// Reset liteeth
|
|
||||||
write_reg(csr_addr + CTRL_RESET, 1u32);
|
|
||||||
busy_wait(200);
|
|
||||||
write_reg(csr_addr + CTRL_RESET, 0u32);
|
|
||||||
busy_wait(200);
|
|
||||||
|
|
||||||
// Clear RX event to mark the slot as available
|
// Clear RX event to mark the slot as available
|
||||||
write_reg(csr_addr + ETHMAC_SRAM_WRITER_EV_PENDING, 1u32);
|
write_reg(csr_addr + ETHMAC_SRAM_WRITER_EV_PENDING, 1u32);
|
||||||
|
|
||||||
@ -91,15 +74,6 @@ impl LiteEthDevice {
|
|||||||
// Return a new device
|
// Return a new device
|
||||||
Some(Self { csr_addr, ethmac_addr })
|
Some(Self { csr_addr, ethmac_addr })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks that wishbone memory access is correct for the given base address
|
|
||||||
unsafe fn check_wishbone_access(csr_addr: u32) -> bool {
|
|
||||||
// Read scratch register, which resets to 0x12345678
|
|
||||||
let value: u32 = read_reg(csr_addr + CTRL_SCRATCH);
|
|
||||||
|
|
||||||
// If this isn't true, we screwed.
|
|
||||||
return value == 0x12345678;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl smoltcp::phy::Device for LiteEthDevice {
|
impl smoltcp::phy::Device for LiteEthDevice {
|
||||||
|
45
firmware/src/litex_uart.rs
Normal file
45
firmware/src/litex_uart.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//! Quick and dirty LiteX uart drier
|
||||||
|
|
||||||
|
|
||||||
|
const REG_RXTX: u32 = 0;
|
||||||
|
const REG_TXFULL: u32 = 0x4;
|
||||||
|
//const REG_RXEMPTY: u32 = 0x8;
|
||||||
|
|
||||||
|
use crate::{write_reg, read_reg};
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
pub enum Error {
|
||||||
|
TxFull,
|
||||||
|
RxEmpty,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LiteXUart {
|
||||||
|
base_addr: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LiteXUart {
|
||||||
|
pub fn new(base_addr: u32) -> Self{ Self {base_addr} }
|
||||||
|
|
||||||
|
pub fn try_put_char(&mut self, c: u8) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
if read_reg::<u32>(self.base_addr + REG_TXFULL) != 0 {
|
||||||
|
return Err(Error::TxFull);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_reg::<u32>(self.base_addr + REG_RXTX, c as u32);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for LiteXUart {
|
||||||
|
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||||
|
for b in s.as_bytes() {
|
||||||
|
// It's okay to loop on this because we'll always clear the buffer
|
||||||
|
while let Err(Error::TxFull) = self.try_put_char(*b) {}
|
||||||
|
//self.try_put_char(*b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -22,17 +22,17 @@ unsafe impl defmt::Logger for DefmtLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn write(bytes: &[u8]) {
|
unsafe fn write(bytes: &[u8]) {
|
||||||
static mut UART: Option<AmlibUart> = None;
|
//static mut UART: Option<AmlibUart> = None;
|
||||||
if UART.is_none() {
|
//if UART.is_none() {
|
||||||
UART = Some(AmlibUart::new(0x0200_0040));
|
// UART = Some(AmlibUart::new(0x0200_0040));
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
let mut dev = UART.unwrap();
|
//let mut dev = UART.unwrap();
|
||||||
//writeln!(dev, "a").unwrap();
|
////writeln!(dev, "a").unwrap();
|
||||||
//writeln!(dev, "length: {}", bytes.len());
|
////writeln!(dev, "length: {}", bytes.len());
|
||||||
for byte in bytes {
|
//for byte in bytes {
|
||||||
while let Err(_) = dev.try_put_char(*byte) {}
|
// while let Err(_) = dev.try_put_char(*byte) {}
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,30 @@ mod eth;
|
|||||||
mod i2c;
|
mod i2c;
|
||||||
mod mcp4726;
|
mod mcp4726;
|
||||||
mod uart;
|
mod uart;
|
||||||
|
mod litex_uart;
|
||||||
mod logging;
|
mod logging;
|
||||||
|
|
||||||
const MAC: [u8; 6] = [0xA0, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0];
|
const MAC: [u8; 6] = [0xA0, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0];
|
||||||
|
|
||||||
|
static mut SECONDS: u32 = 0;
|
||||||
|
|
||||||
|
/// External interrupt handler
|
||||||
|
#[export_name = "MachineExternal"]
|
||||||
|
fn external_interrupt_handler() {
|
||||||
|
let cause = riscv::register::mcause::read();
|
||||||
|
let mut uart = litex_uart::LiteXUart::new(0xf000_4000);
|
||||||
|
writeln!(uart, "mcause: {}", cause.bits());
|
||||||
|
|
||||||
|
if (cause.is_interrupt()) {
|
||||||
|
let mut uart = litex_uart::LiteXUart::new(0xf000_4000);
|
||||||
|
writeln!(uart, "mcause: {}", cause.code());
|
||||||
|
|
||||||
|
if cause.code() == 1 {
|
||||||
|
// TIMER0 event, we have reset so count another second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// use `main` as the entry point of this application
|
// use `main` as the entry point of this application
|
||||||
// `main` is not allowed to return
|
// `main` is not allowed to return
|
||||||
#[entry]
|
#[entry]
|
||||||
@ -44,9 +64,13 @@ fn main() -> ! {
|
|||||||
// }
|
// }
|
||||||
//};
|
//};
|
||||||
let blink_period = 10_000_000u32;
|
let blink_period = 10_000_000u32;
|
||||||
let mut uart = uart::AmlibUart::new(0x0200_0040);
|
let mut uart = litex_uart::LiteXUart::new(0xf000_4000);
|
||||||
|
writeln!(uart, "uart init");
|
||||||
|
|
||||||
let mut device = unsafe { eth::LiteEthDevice::try_init(0x0300_0000).unwrap() };
|
// enable timer
|
||||||
|
|
||||||
|
let mut device = unsafe { eth::LiteEthDevice::try_init(0xf000_0800, 0x8000_0000).unwrap() };
|
||||||
|
writeln!(uart, "eth init");
|
||||||
|
|
||||||
use smoltcp::wire::{EthernetAddress, HardwareAddress};
|
use smoltcp::wire::{EthernetAddress, HardwareAddress};
|
||||||
let mut config = smoltcp::iface::Config::default();
|
let mut config = smoltcp::iface::Config::default();
|
||||||
@ -74,7 +98,25 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let mut last_blink: u32 = 0;
|
let mut last_blink: u32 = 0;
|
||||||
let mut toggle = false;
|
let mut toggle = false;
|
||||||
defmt::info!("Done setup");
|
//defmt::info!("Done setup");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
//riscv::interrupt::enable();
|
||||||
|
//riscv::register::mie::set_mext();
|
||||||
|
//riscv::register::mie::set_msoft();
|
||||||
|
|
||||||
|
// Enable UART rx event for test
|
||||||
|
//write_reg(0xf000_4014, 1u32);
|
||||||
|
|
||||||
|
// Timer stuff
|
||||||
|
write_reg(0xf000_3808, 0u32); // Disable timer
|
||||||
|
write_reg(0xf000_3800, 0u32); // Set LOAD value
|
||||||
|
write_reg(0xf000_3804, 60_000_000u32); // Set RELOAD value
|
||||||
|
write_reg(0xf000_3808, 1u32); // Enable timer
|
||||||
|
|
||||||
|
// Enable timer event
|
||||||
|
//write_reg(0xf000_381c, 1u32);
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let now = millis();
|
let now = millis();
|
||||||
@ -82,26 +124,47 @@ fn main() -> ! {
|
|||||||
last_blink = now;
|
last_blink = now;
|
||||||
toggle = !toggle;
|
toggle = !toggle;
|
||||||
write_led(if toggle { 1 } else { 0 });
|
write_led(if toggle { 1 } else { 0 });
|
||||||
|
|
||||||
|
let val: u32 = unsafe {read_reg(0x8000_2000)};
|
||||||
|
writeln!(uart, "Sampler value: 0x{:08x}", val).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if iface.poll(Instant::from_millis(now), &mut device, &mut socket_set) {
|
if iface.poll(Instant::from_millis(now), &mut device, &mut socket_set) {
|
||||||
//writeln!(uart, "iface did something");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle_timer_event();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn busy_wait(ms: u32) {
|
fn handle_timer_event() {
|
||||||
let start = millis();
|
unsafe {
|
||||||
while millis() - start < ms {
|
if read_reg::<u32>(0xf000_3818) == 0 {
|
||||||
unsafe {
|
return;
|
||||||
asm!("nop");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear TIMER0 event status, and update time
|
||||||
|
write_reg(0xf000_3818, 1u32);
|
||||||
|
SECONDS += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn busy_wait(ms: u32) {
|
||||||
|
//let start = millis();
|
||||||
|
//while millis() - start < ms {
|
||||||
|
// unsafe {
|
||||||
|
// asm!("nop");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
for i in 0..ms*20_000 {
|
||||||
|
unsafe {asm!("nop");}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_led(val: u32) {
|
fn write_led(val: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
write_reg(0x01200000, val);
|
write_reg(0xf000_2000, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,5 +177,14 @@ unsafe fn read_reg<T>(addr: u32) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn millis() -> u32 {
|
fn millis() -> u32 {
|
||||||
unsafe { read_reg(0x01300000) }
|
riscv::interrupt::free(|| {
|
||||||
|
unsafe {
|
||||||
|
// Latch timer value
|
||||||
|
write_reg(0xf000_380c, 1u32);
|
||||||
|
// Read timer value
|
||||||
|
let val: u32 = read_reg(0xf000_3810);
|
||||||
|
let val = 60_000_000 - val;
|
||||||
|
(SECONDS * 1000) + val / 60_000
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user