continue, update MMU handling

This commit is contained in:
Robin Müller 2025-05-30 11:46:13 +02:00
parent d0d0d48780
commit b8bb7e23c7
Signed by: muellerr
GPG Key ID: A649FB78196E3849
15 changed files with 4278 additions and 4222 deletions

View File

@ -7,6 +7,6 @@ members = [
"zynq7000-embassy",
"examples/simple",
"examples/embassy",
"examples/zedboard",
"examples/zedboard", "zynq-mmu",
]
exclude = ["experiments"]

View File

@ -1,8 +1,23 @@
MEMORY
{
/* Zedboard: 512 MB DDR3. Only use 256 MB for now, should be plenty for a bare-metal app. */
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 256M
/* Zedboard: 512 MB DDR3. Only use 63 MB for now, should be plenty for a bare-metal app.
Leave 1 MB of memory which will be configured as uncached device memory by the MPU. This is
recommended for something like DMA descriptors. */
CODE(rx) : ORIGIN = 0x00100000, LENGTH = 63MB
UNCACHED(rx): ORIGIN = 0x4000000, LENGTH = 1MB
}
REGION_ALIAS("DATA", CODE);
SECTIONS
{
.uncached: ALIGN(4)
{
. = ALIGN(4);
_start_uncached = .;
*(.uncached .uncached.*);
. = ALIGN(4);
_end_uncached = .;
} > UNCACHED;
}

7
zynq-mmu/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "zynq-mmu"
description = "Zynq MMU structures"
version = "0.1.0"
edition = "2024"
[dependencies]

20
zynq-mmu/src/lib.rs Normal file
View File

@ -0,0 +1,20 @@
//! The MMU structures live inside a dedicated shared crate so it can be used by both the Zynq
//! runtime crate and teh HAL crate.
#![no_std]
pub const NUM_L1_PAGE_TABLE_ENTRIES: usize = 4096;
#[repr(C, align(16384))]
pub struct L1Table(pub [u32; NUM_L1_PAGE_TABLE_ENTRIES]);
impl L1Table {
#[inline(always)]
pub const fn as_ptr(&self) -> *const u32 {
self.0.as_ptr()
}
#[inline(always)]
pub const fn as_mut_ptr(&mut self) -> *mut u32 {
self.0.as_mut_ptr()
}
}

View File

@ -13,6 +13,7 @@ categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main" }
zynq7000 = { path = "../zynq7000" }
zynq-mmu = { path = "../zynq-mmu", version = "0.1.0" }
bitbybit = "1.3"
arbitrary-int = "1.3"

View File

@ -169,8 +169,11 @@ impl EthernetLowLevel {
}
#[inline]
pub fn configure_mdc_clk_div() {
// TODO:
pub fn set_promiscous_mode(&mut self, enable: bool) {
self.regs.modify_net_cfg(|mut val| {
val.set_copy_all_frames(enable);
val
});
}
/// Performs initialization according to TRM p.541.

View File

@ -1,6 +1,9 @@
use arbitrary_int::u3;
use arbitrary_int::{u2, u3};
pub use zynq7000::eth::MdcClkDiv;
use zynq7000::eth::{MmioEthernet, SpeedMode, GEM_0_BASE_ADDR, GEM_1_BASE_ADDR};
use zynq7000::eth::{
BurstLength, DmaRxBufSize, MmioEthernet, NetworkConfig, SpeedMode, GEM_0_BASE_ADDR,
GEM_1_BASE_ADDR,
};
pub use ll::{ClkConfig, EthernetLowLevel};
@ -9,6 +12,8 @@ pub mod mdio;
pub mod rx_descr;
pub mod tx_descr;
const MTU: usize = 1536;
#[cfg(not(feature = "7z010-7z007s-clg225"))]
use crate::gpio::mio::{
Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27,
@ -198,6 +203,23 @@ impl RxData3 for Pin<Mio38> {
const ETH_ID: EthernetId = EthernetId::Eth1;
}
#[derive(Debug, Clone, Copy)]
pub struct EthernetConfig {
pub clk_config: ClkConfig,
pub mdc_clk_div: MdcClkDiv,
pub mac_address: [u8; 6],
}
impl EthernetConfig {
pub fn new(clk_config: ClkConfig, mdc_clk_div: MdcClkDiv, mac_address: [u8; 6]) -> Self {
Self {
clk_config,
mdc_clk_div,
mac_address,
}
}
}
pub struct Ethernet {
ll: ll::EthernetLowLevel,
mdio: mdio::Mdio,
@ -222,8 +244,7 @@ impl Ethernet {
MdIoPin: MdIo,
>(
mut ll: ll::EthernetLowLevel,
clk_config: ll::ClkConfig,
mdc_clk_div: MdcClkDiv,
config: EthernetConfig,
tx_clk: TxClkPin,
tx_ctrl: TxCtrlPin,
tx_data: (TxData0Pin, TxData1Pin, TxData2Pin, TxData3Pin),
@ -232,7 +253,7 @@ impl Ethernet {
rx_data: (RxData0Pin, RxData1Pin, RxData2Pin, RxData3Pin),
md_pins: Option<(MdClkPin, MdIoPin)>,
) -> Self {
Self::common_init(&mut ll);
Self::common_init(&mut ll, config.mac_address);
let tx_mio_config = zynq7000::slcr::mio::Config::builder()
.with_disable_hstl_rcvr(true)
.with_pullup(true)
@ -348,30 +369,53 @@ impl Ethernet {
});
});
}
ll.configure_clock(clk_config);
ll.configure_clock(config.clk_config);
let mut mdio = mdio::Mdio::new(&ll, true);
mdio.configure_clock_div(mdc_clk_div);
mdio.configure_clock_div(config.mdc_clk_div);
Ethernet { ll, mdio }
}
pub fn new(mut ll: EthernetLowLevel, clk_config: ClkConfig, mdc_clk_div: MdcClkDiv) -> Self {
Self::common_init(&mut ll);
ll.configure_clock(clk_config);
pub fn new(mut ll: EthernetLowLevel, config: EthernetConfig) -> Self {
Self::common_init(&mut ll, config.mac_address);
ll.configure_clock(config.clk_config);
let mut mdio = mdio::Mdio::new(&ll, true);
mdio.configure_clock_div(mdc_clk_div);
mdio.configure_clock_div(config.mdc_clk_div);
Ethernet { ll, mdio }
}
fn common_init(ll: &mut EthernetLowLevel) {
fn common_init(ll: &mut EthernetLowLevel, mac_address: [u8; 6]) {
ll.enable_peripheral_clock();
ll.reset(3);
ll.initialize();
// By default, only modify critical network control bits to retain user configuration
// like the MDC clock divisor.
ll.regs.modify_net_cfg(|mut net_cfg| {
net_cfg.set_full_duplex(true);
net_cfg.set_gigabit_enable(true);
net_cfg.set_speed_mode(SpeedMode::High100Mbps);
net_cfg
});
let macaddr_msbs = (u32::from(mac_address[5]) << 8) | u32::from(mac_address[4]);
let macaddr_lsbs = (u32::from(mac_address[3]) << 24)
| (u32::from(mac_address[2]) << 16)
| (u32::from(mac_address[1]) << 8)
| u32::from(mac_address[0]);
// Writing to the lower address portion disables the address match, writing to the higher
// portion enables it again. Address matching is disabled on reset, so we do not need
// to disable the other addresses here.
ll.regs.write_addr1_low(macaddr_lsbs);
ll.regs.write_addr1_high(macaddr_msbs);
// TODO
ll.regs.modify_dma_cfg(|mut val| {
val.set_rx_packet_buf_size_sel(u2::new(0b11));
val.set_tx_packet_buf_size_sel(true);
val.set_burst_length(BurstLength::Incr16.reg_value());
// Configure 1536 bytes receive buffer size. This is sufficient for regular Ethernet
// frames.
val.set_dma_rx_ahb_buf_size_sel(DmaRxBufSize::new((MTU >> 6) as u8).unwrap());
val.set_endian_swap_mgmt_descriptor(zynq7000::eth::AhbEndianess::Little);
val
});
}
#[inline]

View File

@ -2,7 +2,7 @@ use arbitrary_int::u14;
pub use super::shared::Ownership;
/// RX buffer descriptor.
/// TX buffer descriptor.
///
/// The user should declare an array of this structure inside uncached memory.
///
@ -29,7 +29,7 @@ pub enum TransmitChecksumGenerationStatus {
PrematureEndOfFrame = 0b111,
}
#[bitbybit::bitfield(u32)]
#[bitbybit::bitfield(u32, default = 0x0)]
#[derive(Debug, PartialEq, Eq)]
pub struct Word1 {
#[bit(31, rw)]
@ -51,3 +51,28 @@ pub struct Word1 {
#[bits(0..=13, rw)]
tx_len: u14,
}
impl Descriptor {
#[inline]
pub fn set_ownership(&mut self, ownership: Ownership) {
self.word1.set_ownership(ownership);
}
/// Set the wrap bit, which should be done for the last descriptor in the descriptor list.
#[inline]
pub fn set_wrap_bit(&mut self) {
self.word1.set_wrap(true);
}
/// Set the information for a transfer.
pub fn set_tx_transfer_info(
&mut self,
tx_len: u14,
last_buffer: bool,
no_crc_generation: bool,
) {
self.word1.set_tx_len(tx_len);
self.word1.set_last_buffer(last_buffer);
self.word1.set_no_crc_generation(no_crc_generation);
}
}

View File

@ -13,6 +13,7 @@ use slcr::Slcr;
use zynq7000::slcr::LevelShifterReg;
pub mod clocks;
pub mod mmu;
pub mod eth;
pub mod gic;
pub mod gpio;

16
zynq7000-hal/src/mmu.rs Normal file
View File

@ -0,0 +1,16 @@
use zynq_mmu::L1Table;
pub struct Mmu(&'static mut L1Table);
impl Mmu {
#[inline]
pub const fn new(table: &'static mut L1Table) -> Self {
Mmu(table)
}
pub fn update_l1_table(&mut self, f: impl FnOnce(&mut L1Table)) {
// TODO: Disable MMU
f(self.0);
// DSB, ISB? enable MMU again.
}
}

View File

@ -11,8 +11,9 @@ keywords = ["no-std", "arm", "cortex-a", "amd", "zynq7000"]
categories = ["embedded", "no-std", "hardware-support"]
[dependencies]
cortex-a-rt = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main", optional = true, features = ["vfp-dp"] }
cortex-ar = { git = "https://github.com/rust-embedded/cortex-ar", branch = "main" }
cortex-a-rt = { version = "0.1", optional = true, features = ["vfp-dp"] }
cortex-ar = "0.2"
zynq-mmu = { path = "../zynq-mmu", version = "0.1.0" }
[features]
default = ["rt"]

View File

@ -1,8 +1,14 @@
use std::fs::File;
use std::io::Write;
use std::process::Command;
use zynq7000_rt::mmu::ONE_MB;
pub use zynq7000_rt::mmu::segments::*;
use zynq7000_rt::mmu::ONE_MB;
macro_rules! write_l1_section {
($writer:expr, $offset:expr, $attr:expr) => {
writeln!($writer, "L1Section::new({:#010x}, {}).raw_value(),", $offset, $attr).unwrap();
};
}
fn main() {
let file_path = "src/mmu_table.rs";
@ -35,6 +41,7 @@ fn main() {
+ OCM_MAPPED_HIGH,
4096
);
let mut buf_writer = std::io::BufWriter::new(file);
writeln!(
buf_writer,
@ -63,44 +70,24 @@ fn main() {
"// First DDR segment, OCM memory (0x0000_0000 - 0x0010_0000)"
)
.unwrap();
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_ddr
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_ddr);
offset += ONE_MB;
writeln!(buf_writer, "// DDR memory (0x00100000 - 0x4000_0000)").unwrap();
for _ in 0..DDR_FULL_ACCESSIBLE {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_ddr
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_ddr);
offset += ONE_MB;
}
writeln!(buf_writer, "// FPGA slave 0 (0x4000_0000 - 0x8000_0000)").unwrap();
for _ in 0..FPGA_SLAVE {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_fpga_slaves
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_fpga_slaves);
offset += ONE_MB;
}
writeln!(buf_writer, "// FPGA slave 1 (0x8000_0000 - 0xC000_0000)").unwrap();
for _ in 0..FPGA_SLAVE {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_fpga_slaves
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_fpga_slaves);
offset += ONE_MB;
}
@ -110,12 +97,7 @@ fn main() {
)
.unwrap();
for _ in 0..UNASSIGNED_0 {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_unassigned
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_unassigned);
offset += ONE_MB;
}
@ -125,12 +107,7 @@ fn main() {
)
.unwrap();
for _ in 0..IO_PERIPHS {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_shared_dev
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_shared_dev);
offset += ONE_MB;
}
@ -140,45 +117,25 @@ fn main() {
)
.unwrap();
for _ in 0..UNASSIGNED_1 {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_unassigned
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_unassigned);
offset += ONE_MB;
}
writeln!(buf_writer, "// NAND (0xE100_0000 - 0xE200_0000)").unwrap();
for _ in 0..NAND {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_shared_dev
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_shared_dev);
offset += ONE_MB;
}
writeln!(buf_writer, "// NOR (0xE200_0000 - 0xE400_0000)").unwrap();
for _ in 0..NOR {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_shared_dev
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_shared_dev);
offset += ONE_MB;
}
writeln!(buf_writer, "// SRAM (0xE400_0000 - 0xE600_0000)").unwrap();
for _ in 0..SRAM {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_sram
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_sram);
offset += ONE_MB;
}
@ -188,12 +145,7 @@ fn main() {
)
.unwrap();
for _ in 0..SEGMENTS_UNASSIGNED_2 {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_unassigned
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_unassigned);
offset += ONE_MB;
}
@ -203,12 +155,7 @@ fn main() {
)
.unwrap();
for _ in 0..AMBA_APB {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_shared_dev
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_shared_dev);
offset += ONE_MB;
}
@ -218,23 +165,13 @@ fn main() {
)
.unwrap();
for _ in 0..UNASSIGNED_3 {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_unassigned
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_unassigned);
offset += ONE_MB;
}
writeln!(buf_writer, "// QSPI XIP (0xFC00_0000 - 0xFE00_0000)").unwrap();
for _ in 0..QSPI_XIP {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_qspi
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_qspi);
offset += ONE_MB;
}
@ -244,24 +181,14 @@ fn main() {
)
.unwrap();
for _ in 0..UNASSIGNED_4 {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_unassigned
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_unassigned);
offset += ONE_MB;
}
writeln!(buf_writer, "// OCM High (0xFFF0_0000 - 0xFFFF_FFFF)").unwrap();
let mut offset_u64 = offset as u64;
for _ in 0..OCM_MAPPED_HIGH {
writeln!(
buf_writer,
"L1Section::new({}, {}).raw_value(),",
offset, attr_ocm_high
)
.unwrap();
write_l1_section!(buf_writer, offset, attr_ocm_high);
offset_u64 += ONE_MB as u64;
}

View File

@ -162,12 +162,6 @@ pub mod section_attrs {
};
}
pub const NUM_L1_PAGE_TABLE_ENTRIES: usize = 4096;
#[repr(C, align(16384))]
#[cfg(feature = "rt")]
pub struct L1Table(pub(crate) [u32; NUM_L1_PAGE_TABLE_ENTRIES]);
/// Load the MMU translation table base address into the MMU.
///
/// # Safety

File diff suppressed because it is too large Load Diff

View File

@ -80,7 +80,7 @@ impl MdcClkDiv {
}
}
#[bitbybit::bitfield(u32)]
#[bitbybit::bitfield(u32, default = 0x0)]
#[derive(Debug)]
pub struct NetworkConfig {
#[bit(30, rw)]
@ -234,6 +234,7 @@ pub struct DmaConfig {
/// Default value is 0x1 (big endian)
#[bit(7, rw)]
endian_swap_packet_data: AhbEndianess,
// Default value is 0x0 (little endian)
#[bit(6, rw)]
endian_swap_mgmt_descriptor: AhbEndianess,
#[bits(0..=4, rw)]