phy stuff
Some checks failed
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
Some checks failed
ci / Check build (push) Has been cancelled
ci / Check formatting (push) Has been cancelled
ci / Check Documentation Build (push) Has been cancelled
ci / Clippy (push) Has been cancelled
ci / Check build (pull_request) Has been cancelled
ci / Check formatting (pull_request) Has been cancelled
ci / Check Documentation Build (pull_request) Has been cancelled
ci / Clippy (pull_request) Has been cancelled
This commit is contained in:
@@ -20,6 +20,7 @@ zynq7000-hal = { path = "../../zynq7000-hal" }
|
||||
zynq7000-embassy = { path = "../../zynq7000-embassy" }
|
||||
l3gd20 = { git = "https://github.com/us-irs/l3gd20.git", branch = "add-async-if" }
|
||||
embedded-io = "0.6"
|
||||
bitbybit = "1.3"
|
||||
arbitrary-int = "1.3"
|
||||
embedded-io-async = "0.6"
|
||||
critical-section = "1"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use arbitrary_int::{u2, u4, u5};
|
||||
use bitbybit::bitfield;
|
||||
use core::{mem::MaybeUninit, panic::PanicInfo};
|
||||
use cortex_ar::asm::nop;
|
||||
use embassy_executor::Spawner;
|
||||
@@ -10,19 +12,21 @@ use embedded_io::Write;
|
||||
use log::{error, info};
|
||||
use zedboard::PS_CLOCK_FREQUENCY;
|
||||
use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
configure_level_shifter,
|
||||
eth::{EthernetConfig, EthernetLowLevel},
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
gpio::{GpioPins, Output, PinState},
|
||||
gtc::Gtc,
|
||||
uart::{ClkConfigRaw, Uart, UartConfig},
|
||||
BootMode,
|
||||
};
|
||||
|
||||
use zynq7000::{PsPeripherals, slcr::LevelShifterConfig};
|
||||
use zynq7000::{eth::MdcClkDiv, slcr::LevelShifterConfig, PsPeripherals};
|
||||
use zynq7000_rt::{self as _, mmu::section_attrs::SHAREABLE_DEVICE, mmu_l1_table_mut};
|
||||
|
||||
const INIT_STRING: &str = "-- Zynq 7000 Zedboard Ethernet Example --\n\r";
|
||||
const MAC_ADDRESS: [u8; 6] = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06];
|
||||
|
||||
#[unsafe(link_section = ".uncached")]
|
||||
static RX_DESCRIPTORS: static_cell::ConstStaticCell<
|
||||
@@ -59,11 +63,117 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
|
||||
main();
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PhyIdentifier {
|
||||
pub oui: u32,
|
||||
pub model: u8,
|
||||
pub rev: u8,
|
||||
}
|
||||
|
||||
// Organizational Unique Identifier for Marvell 88E1518 PHY
|
||||
const MARVELL_88E1518_OUI: u32 = 0x005043;
|
||||
const MARVELL_88E1518_MODELL_NUMBER: u8 = 0b011101;
|
||||
|
||||
#[bitbybit::bitenum(u5, exhaustive = false)]
|
||||
pub enum MarvellRegistersPage0 {
|
||||
CopperControl = 0x00,
|
||||
CopperStatus = 0x01,
|
||||
IdReg1 = 0x02,
|
||||
IdReg2 = 0x03,
|
||||
}
|
||||
|
||||
pub struct Marvell88E1518Phy {
|
||||
mdio: zynq7000_hal::eth::mdio::Mdio,
|
||||
addr: u5,
|
||||
}
|
||||
|
||||
impl<'mdio> Marvell88E1518Phy<'mdio> {
|
||||
pub fn new_autoprobe_addr(
|
||||
mdio: &zynq7000_hal::eth::mdio::Mdio,
|
||||
) -> Option<(Self, u4)> {
|
||||
for addr in 0..32 {
|
||||
let phy_id_1 =
|
||||
mdio.read_blocking(u5::new(addr), MarvellRegistersPage0::IdReg1.raw_value());
|
||||
let phy_id_2 =
|
||||
mdio.read_blocking(u5::new(addr), MarvellRegistersPage0::IdReg2.raw_value());
|
||||
let oui = (((phy_id_2 as u32) >> 10) << 19) | ((phy_id_1 as u32) << 3);
|
||||
let model_number = ((phy_id_2 >> 4) & 0b111111) as u8;
|
||||
let revision_number = u4::new((phy_id_2 & 0b1111) as u8);
|
||||
if oui == MARVELL_88E1518_OUI && model_number == MARVELL_88E1518_MODELL_NUMBER {
|
||||
return Some((
|
||||
Self {
|
||||
mdio: unsafe { mdio.clone() },
|
||||
addr: u5::new(addr),
|
||||
},
|
||||
revision_number,
|
||||
));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn new(mdio: zynq7000_hal::eth::mdio::Mdio, addr: u5) -> Self {
|
||||
Self { mdio, addr }
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u16)]
|
||||
pub struct CopperControlRegister {
|
||||
#[bit(15, rw)]
|
||||
copper_reset: bool,
|
||||
#[bit(14, rw)]
|
||||
loopback: bool,
|
||||
#[bit(12, rw)]
|
||||
auto_negotiation_enable: bool,
|
||||
#[bit(11, rw)]
|
||||
power_down: bool,
|
||||
#[bit(10, rw)]
|
||||
isolate: bool,
|
||||
#[bit(9, rw)]
|
||||
restart_auto_negotiation: bool,
|
||||
/// 1: Full-duplex, 0: Half-duplex
|
||||
#[bit(8, rw)]
|
||||
copper_duplex_mode: bool,
|
||||
#[bits([13, 6], rw)]
|
||||
speed_selection: u2,
|
||||
}
|
||||
|
||||
impl Marvell88E1518Phy<'_> {
|
||||
pub fn reset(&mut self) {
|
||||
let mut ctrl = CopperControlRegister::new_with_raw_value(
|
||||
self.mdio
|
||||
.read_blocking(self.addr, MarvellRegistersPage0::CopperControl.raw_value()),
|
||||
);
|
||||
ctrl.set_copper_reset(true);
|
||||
self.mdio.write_blocking(
|
||||
self.addr,
|
||||
MarvellRegistersPage0::CopperControl.raw_value(),
|
||||
ctrl.raw_value(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn restart_auto_negotiation(&mut self) {
|
||||
let mut ctrl = CopperControlRegister::new_with_raw_value(
|
||||
self.mdio
|
||||
.read_blocking(self.addr, MarvellRegistersPage0::CopperControl.raw_value()),
|
||||
);
|
||||
ctrl.set_auto_negotiation_enable(true);
|
||||
ctrl.set_restart_auto_negotiation(true);
|
||||
self.mdio.write_blocking(
|
||||
self.addr,
|
||||
MarvellRegistersPage0::CopperControl.raw_value(),
|
||||
ctrl.raw_value(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
#[unsafe(export_name = "main")]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
// Configure the uncached memory region using the MMU.
|
||||
mmu_l1_table_mut().update(UNCACHED_ADDR, SHAREABLE_DEVICE);
|
||||
mmu_l1_table_mut()
|
||||
.update(UNCACHED_ADDR, SHAREABLE_DEVICE)
|
||||
.expect("configuring uncached memory section failed");
|
||||
|
||||
// Enable PS-PL level shifters.
|
||||
configure_level_shifter(LevelShifterConfig::EnableAll);
|
||||
@@ -121,6 +231,57 @@ async fn main(_spawner: Spawner) -> ! {
|
||||
rx_descr_ref.set_rx_buf_address(index, rx_buf.0.as_ptr() as u32);
|
||||
}
|
||||
|
||||
// Unwrap okay, this is a valid peripheral.
|
||||
let eth_ll = EthernetLowLevel::new(dp.eth_0).unwrap();
|
||||
let (clk_config, clk_error) = zynq7000_hal::eth::ClkConfig::calculate_for_rgmii(
|
||||
clocks.io_clocks().ref_clk(),
|
||||
zynq7000_hal::eth::Speed::Mbps1000,
|
||||
);
|
||||
info!(
|
||||
"Calculated RGMII clock configuration: {:?}, error: {}",
|
||||
clk_config, clk_error
|
||||
);
|
||||
// Unwrap okay, we use a standard clock config, and the clock config should never fail.
|
||||
let eth_cfg = EthernetConfig::new(
|
||||
clk_config,
|
||||
zynq7000_hal::eth::calculate_mdc_clk_div(clocks.arm_clocks()).unwrap(),
|
||||
MAC_ADDRESS,
|
||||
);
|
||||
// Configures all the physical pins for ethernet operation and sets up the
|
||||
// ethernet peripheral.
|
||||
let mut eth = zynq7000_hal::eth::Ethernet::new_with_mio(
|
||||
eth_ll,
|
||||
eth_cfg,
|
||||
gpio_pins.mio.mio16,
|
||||
gpio_pins.mio.mio21,
|
||||
(
|
||||
gpio_pins.mio.mio17,
|
||||
gpio_pins.mio.mio18,
|
||||
gpio_pins.mio.mio19,
|
||||
gpio_pins.mio.mio20,
|
||||
),
|
||||
gpio_pins.mio.mio22,
|
||||
gpio_pins.mio.mio27,
|
||||
(
|
||||
gpio_pins.mio.mio23,
|
||||
gpio_pins.mio.mio24,
|
||||
gpio_pins.mio.mio25,
|
||||
gpio_pins.mio.mio26,
|
||||
),
|
||||
Some((gpio_pins.mio.mio52, gpio_pins.mio.mio53)),
|
||||
);
|
||||
eth.set_rx_buf_descriptor_base_address(rx_descr_ref.base_addr());
|
||||
eth.set_tx_buf_descriptor_base_address(tx_descr_ref.base_addr());
|
||||
let (mut phy, phy_rev) = Marvell88E1518Phy::new_autoprobe_addr(eth.mdio_mut()).unwrap();
|
||||
info!("Detected Marvell 88E1518 PHY with revision number: {:?}", phy_rev);
|
||||
phy.reset();
|
||||
phy.restart_auto_negotiation();
|
||||
|
||||
// TODO:
|
||||
// 1. PHY configuration.
|
||||
// 2. Interrupt handler for ethernet RX and TX. Need to pass the buffers and descriptors
|
||||
// to the interrupt handler.
|
||||
//
|
||||
info!("Boot mode: {:?}", boot_mode);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(200));
|
||||
|
||||
@@ -15,12 +15,7 @@ critical-section = "1"
|
||||
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
|
||||
zynq7000-hal = { path = "../zynq7000-hal" }
|
||||
|
||||
<<<<<<< HEAD
|
||||
embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", version = "0.2" }
|
||||
embassy-time-queue-utils = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", version = "0.1" }
|
||||
=======
|
||||
# embassy-time-driver = { git = "https://github.com/us-irs/embassy", branch = "add-cortex-ar-support", version = "0.2" }
|
||||
# embassy-time-queue-utils = { git = "https://github.com/us-irs/embassy", branch = "add-cortex-ar-support", version = "0.2" }
|
||||
# embassy-time-driver = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", version = "0.2" }
|
||||
# embassy-time-queue-utils = { git = "https://github.com/embassy-rs/embassy.git", branch = "main", version = "0.1" }
|
||||
embassy-time-driver = { path = "../../../Rust/embassy/embassy-time-driver", version = "0.2" }
|
||||
embassy-time-queue-utils = { path = "../../../Rust/embassy/embassy-time-queue-utils", version = "0.1" }
|
||||
>>>>>>> 807d9df (start adding ethernet support)
|
||||
|
||||
@@ -26,6 +26,18 @@ impl Mdio {
|
||||
}
|
||||
}
|
||||
|
||||
/// Steals the MDIO handle from the given Ethernet low-level interface.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Circumvents ownership and safety guarantees of the HAL.
|
||||
pub unsafe fn clone(&self) -> Self {
|
||||
Self {
|
||||
regs: unsafe { self.regs.clone() },
|
||||
clause22: self.clause22,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn configure_clock_div(&mut self, clk_div: MdcClkDiv) {
|
||||
self.regs.modify_net_cfg(|mut val| {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use arbitrary_int::{u2, u3};
|
||||
pub use zynq7000::eth::MdcClkDiv;
|
||||
use zynq7000::eth::{
|
||||
BurstLength, DmaRxBufSize, GEM_0_BASE_ADDR, GEM_1_BASE_ADDR, MmioEthernet, NetworkConfig,
|
||||
SpeedMode,
|
||||
BurstLength, DmaRxBufSize, MmioEthernet, NetworkConfig, SpeedMode, GEM_0_BASE_ADDR,
|
||||
GEM_1_BASE_ADDR,
|
||||
};
|
||||
|
||||
pub use ll::{ClkConfig, EthernetLowLevel};
|
||||
pub use ll::{ClkConfig, EthernetLowLevel, Speed};
|
||||
|
||||
pub mod ll;
|
||||
pub mod mdio;
|
||||
@@ -13,17 +13,22 @@ pub mod rx_descr;
|
||||
pub mod tx_descr;
|
||||
|
||||
pub const MTU: usize = 1536;
|
||||
pub const MAX_MDC_SPEED: Hertz = Hertz::from_raw(2_500_000);
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
use crate::gpio::mio::{
|
||||
Mio16, Mio17, Mio18, Mio19, Mio20, Mio21, Mio22, Mio23, Mio24, Mio25, Mio26, Mio27,
|
||||
};
|
||||
use crate::gpio::{
|
||||
IoPeriphPin,
|
||||
mio::{
|
||||
Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio52,
|
||||
Mio53, MioPinMarker, MuxConf, Pin,
|
||||
use crate::{
|
||||
clocks::ArmClocks,
|
||||
gpio::{
|
||||
mio::{
|
||||
Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34, Mio35, Mio36, Mio37, Mio38, Mio39,
|
||||
Mio52, Mio53, MioPinMarker, MuxConf, Pin,
|
||||
},
|
||||
IoPeriphPin,
|
||||
},
|
||||
time::Hertz,
|
||||
};
|
||||
|
||||
pub const MUX_CONF_PHY: MuxConf = MuxConf::new_with_l0();
|
||||
@@ -203,6 +208,23 @@ impl RxData3 for Pin<Mio38> {
|
||||
const ETH_ID: EthernetId = EthernetId::Eth1;
|
||||
}
|
||||
|
||||
/// Calculate the CPU 1x clock divisor required to achieve a clock speed which is below
|
||||
/// 2.5 MHz, as specified by the 802.3 standard.
|
||||
pub fn calculate_mdc_clk_div(arm_clks: &ArmClocks) -> Option<MdcClkDiv> {
|
||||
let div = arm_clks.cpu_1x_clk().raw().div_ceil(MAX_MDC_SPEED.raw());
|
||||
match div {
|
||||
0..8 => Some(MdcClkDiv::Div8),
|
||||
8..16 => Some(MdcClkDiv::Div16),
|
||||
16..32 => Some(MdcClkDiv::Div32),
|
||||
32..64 => Some(MdcClkDiv::Div64),
|
||||
64..128 => Some(MdcClkDiv::Div128),
|
||||
128..224 => Some(MdcClkDiv::Div224),
|
||||
// MDC clock divisor is too high for the maximum speed.
|
||||
// This is not a valid configuration.
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct EthernetConfig {
|
||||
pub clk_config: ClkConfig,
|
||||
@@ -372,7 +394,10 @@ impl Ethernet {
|
||||
ll.configure_clock(config.clk_config);
|
||||
let mut mdio = mdio::Mdio::new(&ll, true);
|
||||
mdio.configure_clock_div(config.mdc_clk_div);
|
||||
Ethernet { ll, mdio }
|
||||
let eth = Ethernet { ll, mdio }
|
||||
eth.set_rx_buf_descriptor_base_address(0);
|
||||
eth.set_tx_buf_descriptor_base_address(0);
|
||||
eth
|
||||
}
|
||||
|
||||
pub fn new(mut ll: EthernetLowLevel, config: EthernetConfig) -> Self {
|
||||
@@ -405,7 +430,6 @@ impl Ethernet {
|
||||
// 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);
|
||||
@@ -428,10 +452,29 @@ impl Ethernet {
|
||||
&self.ll.regs
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mdio(&mut self) -> &mdio::Mdio {
|
||||
&self.mdio
|
||||
}
|
||||
|
||||
pub fn mdio_mut(&mut self) -> &mut mdio::Mdio {
|
||||
&mut self.mdio
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn regs_mut(&mut self) -> &mut MmioEthernet<'static> {
|
||||
&mut self.ll.regs
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_rx_buf_descriptor_base_address(&mut self, addr: u32) {
|
||||
self.ll.set_rx_buf_descriptor_base_address(addr);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_tx_buf_descriptor_base_address(&mut self, addr: u32) {
|
||||
self.ll.set_rx_buf_descriptor_base_address(addr);
|
||||
}
|
||||
}
|
||||
|
||||
mod shared {
|
||||
|
||||
@@ -48,6 +48,8 @@ pub struct PsPeripherals {
|
||||
pub slcr: slcr::MmioSlcr<'static>,
|
||||
pub ttc_0: ttc::MmioTtc<'static>,
|
||||
pub ttc_1: ttc::MmioTtc<'static>,
|
||||
pub eth_0: eth::MmioEthernet<'static>,
|
||||
pub eth_1: eth::MmioEthernet<'static>
|
||||
}
|
||||
|
||||
impl PsPeripherals {
|
||||
@@ -81,6 +83,8 @@ impl PsPeripherals {
|
||||
i2c_1: i2c::I2c::new_mmio_fixed_1(),
|
||||
ttc_0: ttc::Ttc::new_mmio_fixed_0(),
|
||||
ttc_1: ttc::Ttc::new_mmio_fixed_1(),
|
||||
eth_0: eth::Ethernet::new_mmio_fixed_0(),
|
||||
eth_1: eth::Ethernet::new_mmio_fixed_1(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user