not quite done, but getting there
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
use core::{mem::MaybeUninit, panic::PanicInfo};
|
||||
use cortex_ar::asm::nop;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Duration, Ticker};
|
||||
use embassy_time::{Duration, Ticker, WithTimeout};
|
||||
use embedded_hal::digital::StatefulOutputPin;
|
||||
use embedded_io::Write;
|
||||
use log::{error, info};
|
||||
@@ -14,7 +14,7 @@ use zynq7000_hal::{
|
||||
BootMode,
|
||||
clocks::Clocks,
|
||||
configure_level_shifter,
|
||||
eth::{AlignedBuffer, EthernetConfig, EthernetLowLevel},
|
||||
eth::{AlignedBuffer, ClkConfigCollection, EthernetConfig, EthernetLowLevel},
|
||||
gic::{GicConfigurator, GicInterruptHelper, Interrupt},
|
||||
gpio::{GpioPins, Output, PinState},
|
||||
gtc::Gtc,
|
||||
@@ -59,12 +59,21 @@ pub extern "C" fn boot_core(cpu_id: u32) -> ! {
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn net_task(
|
||||
async fn embassy_net_task(
|
||||
mut runner: embassy_net::Runner<'static, zynq7000_hal::eth::embassy_net::Driver>,
|
||||
) -> ! {
|
||||
runner.run().await
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn led_task(mut mio_led: Output) -> ! {
|
||||
let mut ticker = Ticker::every(Duration::from_millis(200));
|
||||
loop {
|
||||
mio_led.toggle().unwrap();
|
||||
ticker.next().await; // Wait for the next cycle of the ticker
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
#[unsafe(export_name = "main")]
|
||||
async fn main(spawner: Spawner) -> ! {
|
||||
@@ -136,17 +145,15 @@ async fn main(spawner: Spawner) -> ! {
|
||||
|
||||
// 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,
|
||||
);
|
||||
let (clk_collection, clk_errors) =
|
||||
ClkConfigCollection::calculate_for_rgmii_and_io_clock(clocks.io_clocks());
|
||||
info!(
|
||||
"Calculated RGMII clock configuration: {:?}, error: {}",
|
||||
clk_config, clk_error
|
||||
"Calculated RGMII clock configuration: {:?}, errors (missmatch from ideal rate in hertz): {:?}",
|
||||
clk_collection, clk_errors
|
||||
);
|
||||
// Unwrap okay, we use a standard clock config, and the clock config should never fail.
|
||||
let eth_cfg = EthernetConfig::new(
|
||||
clk_config,
|
||||
clk_collection.cfg_100_mbps,
|
||||
zynq7000_hal::eth::calculate_mdc_clk_div(clocks.arm_clocks()).unwrap(),
|
||||
MAC_ADDRESS,
|
||||
);
|
||||
@@ -208,19 +215,13 @@ async fn main(spawner: Spawner) -> ! {
|
||||
RESOURCES.init(embassy_net::StackResources::new()),
|
||||
rng.next_u64(),
|
||||
);
|
||||
spawner.spawn(net_task(runner)).unwrap();
|
||||
|
||||
stack.wait_config_up().await;
|
||||
let network_config = stack.config_v4();
|
||||
info!(
|
||||
"Network configuration is up: DHCP config: {:?}!",
|
||||
network_config
|
||||
);
|
||||
|
||||
let mut ticker = Ticker::every(Duration::from_millis(200));
|
||||
spawner.spawn(embassy_net_task(runner)).unwrap();
|
||||
|
||||
let mut mio_led = Output::new_for_mio(gpio_pins.mio.mio7, PinState::Low);
|
||||
let mut emio_leds: [Output; 8] = [
|
||||
|
||||
spawner.spawn(led_task(mio_led)).unwrap();
|
||||
|
||||
let mut _emio_leds: [Output; 8] = [
|
||||
Output::new_for_emio(gpio_pins.emio.take(0).unwrap(), PinState::Low),
|
||||
Output::new_for_emio(gpio_pins.emio.take(1).unwrap(), PinState::Low),
|
||||
Output::new_for_emio(gpio_pins.emio.take(2).unwrap(), PinState::Low),
|
||||
@@ -231,15 +232,34 @@ async fn main(spawner: Spawner) -> ! {
|
||||
Output::new_for_emio(gpio_pins.emio.take(7).unwrap(), PinState::Low),
|
||||
];
|
||||
loop {
|
||||
mio_led.toggle().unwrap();
|
||||
|
||||
// Create a wave pattern for emio_leds
|
||||
for led in emio_leds.iter_mut() {
|
||||
led.toggle().unwrap();
|
||||
ticker.next().await; // Wait for the next ticker for each toggle
|
||||
if !stack.is_link_up() {
|
||||
loop {
|
||||
let config_up_fut = stack.wait_config_up();
|
||||
let status = phy.read_copper_status();
|
||||
// TODO: How is this related to the ethernet stack link state? Should we only
|
||||
// update the link state to up once auto-negotiation is complete and the clock
|
||||
// was configured correctly?
|
||||
if status.auto_negotiation_complete() {
|
||||
let extended_status = phy.read_copper_specific_status_register_1();
|
||||
eth.configure_clock_and_speed_duplex(
|
||||
// If this has the reserved bits, what do we even do? For this example app,
|
||||
// I am going to assume this never happens..
|
||||
extended_status.speed().as_zynq7000_eth_speed().unwrap(),
|
||||
extended_status.duplex().as_zynq7000_eth_duplex(),
|
||||
&clk_collection,
|
||||
);
|
||||
eth.set_tx_rx_enable(true, true);
|
||||
}
|
||||
match config_up_fut.with_timeout(Duration::from_millis(100)).await {
|
||||
Ok(_) => break,
|
||||
Err(e) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ticker.next().await; // Wait for the next cycle of the ticker
|
||||
let network_config = stack.config_v4();
|
||||
info!("Network configuration is up: DHCP config: {network_config:?}!",);
|
||||
//mio_led.toggle().unwrap();
|
||||
//ticker.next().await; // Wait for the next cycle of the ticker
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,12 +104,34 @@ pub enum PhySpeedBits {
|
||||
Mbps10 = 0b00,
|
||||
}
|
||||
|
||||
impl PhySpeedBits {
|
||||
#[inline]
|
||||
pub fn as_zynq7000_eth_speed(&self) -> Option<zynq7000_hal::eth::Speed> {
|
||||
match self {
|
||||
PhySpeedBits::Reserved => None,
|
||||
PhySpeedBits::Mbps1000 => Some(zynq7000_hal::eth::Speed::Mbps1000),
|
||||
PhySpeedBits::Mbps100 => Some(zynq7000_hal::eth::Speed::Mbps100),
|
||||
PhySpeedBits::Mbps10 => Some(zynq7000_hal::eth::Speed::Mbps10),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
pub enum PhyDuplexBit {
|
||||
Full = 1,
|
||||
Half = 0,
|
||||
}
|
||||
|
||||
impl PhyDuplexBit {
|
||||
#[inline]
|
||||
pub fn as_zynq7000_eth_duplex(&self) -> zynq7000_hal::eth::Duplex {
|
||||
match self {
|
||||
PhyDuplexBit::Full => zynq7000_hal::eth::Duplex::Full,
|
||||
PhyDuplexBit::Half => zynq7000_hal::eth::Duplex::Half,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u16)]
|
||||
pub struct CopperSpecificStatusRegister {
|
||||
#[bits(14..=15, r)]
|
||||
|
||||
@@ -4,7 +4,7 @@ use zynq7000::{
|
||||
slcr::reset::EthernetReset,
|
||||
};
|
||||
|
||||
use crate::{enable_amba_peripheral_clock, slcr::Slcr, time::Hertz};
|
||||
use crate::{clocks::IoClocks, enable_amba_peripheral_clock, slcr::Slcr, time::Hertz};
|
||||
|
||||
use super::{EthernetId, PsEthernet as _};
|
||||
|
||||
@@ -13,16 +13,6 @@ pub struct EthernetLowLevel {
|
||||
pub regs: zynq7000::eth::MmioEthernet<'static>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ClkConfig {
|
||||
pub src_sel: zynq7000::slcr::clocks::SrcSelIo,
|
||||
pub use_emio_tx_clk: bool,
|
||||
pub divisor_0: u6,
|
||||
pub divisor_1: u6,
|
||||
/// Enable the clock.
|
||||
pub enable: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Speed {
|
||||
Mbps10,
|
||||
@@ -40,6 +30,22 @@ impl Speed {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Duplex {
|
||||
Half,
|
||||
Full,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ClkConfig {
|
||||
pub src_sel: zynq7000::slcr::clocks::SrcSelIo,
|
||||
pub use_emio_tx_clk: bool,
|
||||
pub divisor_0: u6,
|
||||
pub divisor_1: u6,
|
||||
/// Enable the clock.
|
||||
pub enable: bool,
|
||||
}
|
||||
|
||||
impl ClkConfig {
|
||||
pub const fn new(divisor_0: u6, divisor_1: u6) -> Self {
|
||||
Self {
|
||||
@@ -51,6 +57,12 @@ impl ClkConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls [Self::calculate_for_rgmii], assuming that the IO clock is the reference clock,
|
||||
/// which is the default clock for the Ethernet module.
|
||||
pub fn calculate_for_rgmii_and_io_clock(io_clks: IoClocks, target_speed: Speed) -> (Self, u32) {
|
||||
Self::calculate_for_rgmii(io_clks.ref_clk(), target_speed)
|
||||
}
|
||||
|
||||
/// Calculate the best clock configuration (divisors) for the given reference clock
|
||||
/// and desired target speed when using a RGMII interface.
|
||||
///
|
||||
@@ -83,6 +95,58 @@ impl ClkConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a collection of clock configuration for all relevant speed settings.
|
||||
///
|
||||
/// Generally, the clock need to be re-configured each time the speed settings change, for example
|
||||
/// after a completed auto-negotiation process. The necessary clock configurations for each speed
|
||||
/// setting can be pre-calculated and stored using this data structure.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ClkConfigCollection {
|
||||
pub cfg_10_mbps: ClkConfig,
|
||||
pub cfg_100_mbps: ClkConfig,
|
||||
pub cfg_1000_mbps: ClkConfig,
|
||||
}
|
||||
|
||||
impl ClkConfigCollection {
|
||||
pub const fn new(
|
||||
cfg_10_mbps: ClkConfig,
|
||||
cfg_100_mbps: ClkConfig,
|
||||
cfg_1000_mbps: ClkConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
cfg_10_mbps,
|
||||
cfg_100_mbps,
|
||||
cfg_1000_mbps,
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls [Self::calculate_for_rgmii], assuming that the IO clock is the reference clock,
|
||||
/// which is the default clock for the Ethernet module.
|
||||
pub fn calculate_for_rgmii_and_io_clock(io_clks: &IoClocks) -> (Self, [u32; 3]) {
|
||||
Self::calculate_for_rgmii(io_clks.ref_clk())
|
||||
}
|
||||
|
||||
/// Calculate the best clock configuration (divisors) for the given reference clock
|
||||
/// and desired target speed when using a RGMII interface.
|
||||
///
|
||||
/// Usually, the reference clock will be the IO clock.
|
||||
///
|
||||
/// Returns a tuple where the first entry is the calcualted clock configuration
|
||||
/// and the second entry is the difference between calculated clock speed for the divisors
|
||||
/// and the target speed. Ideally, this difference should be 0.
|
||||
pub fn calculate_for_rgmii(ref_clk: Hertz) -> (Self, [u32; 3]) {
|
||||
let (cfg_10_mbps, error_10_mbps) = ClkConfig::calculate_for_rgmii(ref_clk, Speed::Mbps10);
|
||||
let (cfg_100_mbps, error_100_mbps) =
|
||||
ClkConfig::calculate_for_rgmii(ref_clk, Speed::Mbps100);
|
||||
let (cfg_1000_mbps, error_1000_mbps) =
|
||||
ClkConfig::calculate_for_rgmii(ref_clk, Speed::Mbps1000);
|
||||
(
|
||||
Self::new(cfg_10_mbps, cfg_100_mbps, cfg_1000_mbps),
|
||||
[error_10_mbps, error_100_mbps, error_1000_mbps],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Ethernet low-level interface.
|
||||
impl EthernetLowLevel {
|
||||
/// Creates a new instance of the Ethernet low-level interface.
|
||||
@@ -152,22 +216,54 @@ impl EthernetLowLevel {
|
||||
enable_amba_peripheral_clock(periph_sel);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn configure_clock(&mut self, cfg: ClkConfig) {
|
||||
pub fn configure_clock(&mut self, cfg: ClkConfig, enable_rx_clock: bool) {
|
||||
unsafe {
|
||||
Slcr::with(|regs| {
|
||||
regs.clk_ctrl().modify_gem_0_clk_ctrl(|mut val| {
|
||||
val.set_srcsel(cfg.src_sel);
|
||||
val.set_divisor_0(cfg.divisor_0);
|
||||
val.set_divisor_1(cfg.divisor_1);
|
||||
val.set_use_emio_tx_clk(cfg.use_emio_tx_clk);
|
||||
val.set_clk_act(cfg.enable);
|
||||
val
|
||||
});
|
||||
let (ptr_gig_eth_clk_ctrl, ptr_gig_eth_rclk_ctrl) = self.id().clk_config_regs(regs);
|
||||
let mut gig_eth_clk_ctrl_val = core::ptr::read_volatile(ptr_gig_eth_clk_ctrl);
|
||||
gig_eth_clk_ctrl_val.set_srcsel(cfg.src_sel);
|
||||
gig_eth_clk_ctrl_val.set_divisor_0(cfg.divisor_0);
|
||||
gig_eth_clk_ctrl_val.set_divisor_1(cfg.divisor_1);
|
||||
gig_eth_clk_ctrl_val.set_use_emio_tx_clk(cfg.use_emio_tx_clk);
|
||||
gig_eth_clk_ctrl_val.set_clk_act(cfg.enable);
|
||||
core::ptr::write_volatile(ptr_gig_eth_clk_ctrl, gig_eth_clk_ctrl_val);
|
||||
|
||||
if enable_rx_clock {
|
||||
let mut gig_eth_rclk_ctrl_val = core::ptr::read_volatile(ptr_gig_eth_rclk_ctrl);
|
||||
gig_eth_rclk_ctrl_val.set_clk_enable(true);
|
||||
core::ptr::write_volatile(ptr_gig_eth_rclk_ctrl, gig_eth_rclk_ctrl_val);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Can be used after auto-negotiation to update all relevant speed and duplex
|
||||
/// parameter of the ethernet peripheral.
|
||||
///
|
||||
/// It is probably a good idea to disable the receiver and transmitter while doing this.
|
||||
/// This function calls [Self::configure_clock_for_speed] and [Self::set_speed_and_duplex].
|
||||
pub fn configure_clock_and_speed_duplex(
|
||||
&mut self,
|
||||
speed: Speed,
|
||||
duplex: Duplex,
|
||||
clk_collection: &ClkConfigCollection,
|
||||
) {
|
||||
self.configure_clock_for_speed(speed, clk_collection);
|
||||
self.set_speed_and_duplex(speed, duplex);
|
||||
}
|
||||
|
||||
pub fn configure_clock_for_speed(
|
||||
&mut self,
|
||||
speed: Speed,
|
||||
clk_collection: &ClkConfigCollection,
|
||||
) {
|
||||
match speed {
|
||||
Speed::Mbps10 => self.configure_clock(clk_collection.cfg_10_mbps, false),
|
||||
Speed::Mbps100 => self.configure_clock(clk_collection.cfg_100_mbps, false),
|
||||
Speed::Mbps1000 => self.configure_clock(clk_collection.cfg_1000_mbps, false),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_promiscous_mode(&mut self, enable: bool) {
|
||||
self.regs.modify_net_cfg(|mut val| {
|
||||
@@ -186,10 +282,46 @@ impl EthernetLowLevel {
|
||||
self.regs.write_tx_buf_queue_base_addr(addr);
|
||||
}
|
||||
|
||||
/// This function sets the speed and duplex mode of the Ethernet interface.
|
||||
///
|
||||
/// This should be called after a completed auto-negotiation process with the negotiated
|
||||
/// settings.
|
||||
pub fn set_speed_and_duplex(&mut self, speed: Speed, duplex: Duplex) {
|
||||
self.regs.modify_net_cfg(|mut val| {
|
||||
val.set_full_duplex(duplex == Duplex::Full);
|
||||
match speed {
|
||||
Speed::Mbps10 => {
|
||||
val.set_speed_mode(zynq7000::eth::SpeedMode::Low10Mbps);
|
||||
val.set_gigabit_enable(false);
|
||||
val
|
||||
}
|
||||
Speed::Mbps100 => {
|
||||
val.set_speed_mode(zynq7000::eth::SpeedMode::High100Mbps);
|
||||
val.set_gigabit_enable(false);
|
||||
val
|
||||
}
|
||||
Speed::Mbps1000 => {
|
||||
val.set_gigabit_enable(true);
|
||||
val
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Allows enabling/disabling ethernet receiver and transmitter respectively.
|
||||
#[inline]
|
||||
pub fn set_tx_rx_enable(&mut self, tx_enable: bool, rx_enable: bool) {
|
||||
self.regs.modify_net_ctrl(|mut val| {
|
||||
val.set_rx_enable(rx_enable);
|
||||
val.set_tx_enable(tx_enable);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
||||
/// Performs initialization according to TRM p.541.
|
||||
///
|
||||
/// These steps do not include any resets or clock configuration.
|
||||
pub fn initialize(&mut self) {
|
||||
pub fn initialize(&mut self, reset_rx_tx_queue_base_addr: bool) {
|
||||
let mut ctrl_val = NetworkControl::new_with_raw_value(0);
|
||||
self.regs.write_net_ctrl(ctrl_val);
|
||||
// Now clear statistics.
|
||||
@@ -199,8 +331,10 @@ impl EthernetLowLevel {
|
||||
self.regs.write_rx_status(RxStatus::new_clear_all());
|
||||
self.regs
|
||||
.write_interrupt_disable(InterruptControl::new_clear_all());
|
||||
self.regs.write_rx_buf_queue_base_addr(0);
|
||||
self.regs.write_tx_buf_queue_base_addr(0);
|
||||
if reset_rx_tx_queue_base_addr {
|
||||
self.regs.write_rx_buf_queue_base_addr(0);
|
||||
self.regs.write_tx_buf_queue_base_addr(0);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -5,7 +5,7 @@ use zynq7000::eth::{
|
||||
SpeedMode,
|
||||
};
|
||||
|
||||
pub use ll::{ClkConfig, EthernetLowLevel, Speed};
|
||||
pub use ll::{ClkConfig, ClkConfigCollection, Duplex, EthernetLowLevel, Speed};
|
||||
|
||||
pub mod embassy_net;
|
||||
pub mod ll;
|
||||
@@ -59,6 +59,25 @@ impl EthernetId {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clk_config_regs(
|
||||
&self,
|
||||
slcr: &mut zynq7000::slcr::MmioSlcr<'static>,
|
||||
) -> (
|
||||
*mut zynq7000::slcr::clocks::GigEthClkCtrl,
|
||||
*mut zynq7000::slcr::clocks::GigEthRclkCtrl,
|
||||
) {
|
||||
match self {
|
||||
EthernetId::Eth0 => (
|
||||
slcr.clk_ctrl().pointer_to_gem_0_clk_ctrl(),
|
||||
slcr.clk_ctrl().pointer_to_gem_0_rclk_ctrl(),
|
||||
),
|
||||
EthernetId::Eth1 => (
|
||||
slcr.clk_ctrl().pointer_to_gem_1_clk_ctrl(),
|
||||
slcr.clk_ctrl().pointer_to_gem_1_rclk_ctrl(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PsEthernet {
|
||||
@@ -232,15 +251,15 @@ pub fn calculate_mdc_clk_div(arm_clks: &ArmClocks) -> Option<MdcClkDiv> {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct EthernetConfig {
|
||||
pub clk_config: ClkConfig,
|
||||
pub init_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 {
|
||||
pub fn new(init_clk_config: ClkConfig, mdc_clk_div: MdcClkDiv, mac_address: [u8; 6]) -> Self {
|
||||
Self {
|
||||
clk_config,
|
||||
init_clk_config,
|
||||
mdc_clk_div,
|
||||
mac_address,
|
||||
}
|
||||
@@ -416,7 +435,7 @@ impl Ethernet {
|
||||
});
|
||||
});
|
||||
}
|
||||
ll.configure_clock(config.clk_config);
|
||||
ll.configure_clock(config.init_clk_config, true);
|
||||
let mut mdio = mdio::Mdio::new(&ll, true);
|
||||
mdio.configure_clock_div(config.mdc_clk_div);
|
||||
let mut eth = Ethernet { ll, mdio };
|
||||
@@ -427,18 +446,24 @@ impl Ethernet {
|
||||
|
||||
pub fn new(mut ll: EthernetLowLevel, config: EthernetConfig) -> Self {
|
||||
Self::common_init(&mut ll, config.mac_address);
|
||||
ll.configure_clock(config.clk_config);
|
||||
ll.configure_clock(config.init_clk_config, true);
|
||||
let mut mdio = mdio::Mdio::new(&ll, true);
|
||||
mdio.configure_clock_div(config.mdc_clk_div);
|
||||
Ethernet { ll, mdio }
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.ll.reset(3);
|
||||
// Do not set RX and TX queue base address.
|
||||
self.ll.initialize(false);
|
||||
}
|
||||
|
||||
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.initialize(true);
|
||||
// Set these to sensible values, but these probably need to be set again after
|
||||
// auto-negotiation has completed.
|
||||
ll.regs.modify_net_cfg(|mut net_cfg| {
|
||||
net_cfg.set_full_duplex(true);
|
||||
net_cfg.set_gigabit_enable(true);
|
||||
@@ -501,14 +526,35 @@ impl Ethernet {
|
||||
&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);
|
||||
}
|
||||
delegate::delegate! {
|
||||
to self.ll {
|
||||
#[inline]
|
||||
pub const fn id(&self) -> EthernetId;
|
||||
|
||||
#[inline]
|
||||
pub fn set_tx_buf_descriptor_base_address(&mut self, addr: u32) {
|
||||
self.ll.set_rx_buf_descriptor_base_address(addr);
|
||||
#[inline]
|
||||
pub fn set_rx_buf_descriptor_base_address(&mut self, addr: u32);
|
||||
|
||||
#[inline]
|
||||
pub fn set_tx_buf_descriptor_base_address(&mut self, addr: u32);
|
||||
|
||||
pub fn configure_clock_and_speed_duplex(
|
||||
&mut self,
|
||||
speed: Speed,
|
||||
duplex: Duplex,
|
||||
clk_collection: &ClkConfigCollection
|
||||
);
|
||||
|
||||
pub fn configure_clock_for_speed(
|
||||
&mut self,
|
||||
speed: Speed,
|
||||
clk_collection: &ClkConfigCollection,
|
||||
);
|
||||
|
||||
pub fn set_speed_and_duplex(&mut self, speed: Speed, duplex: Duplex);
|
||||
|
||||
#[inline]
|
||||
pub fn set_tx_rx_enable(&mut self, tx_enable: bool, rx_enable: bool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ pub struct NetworkControl {
|
||||
loopback_local: bool,
|
||||
}
|
||||
|
||||
/// The speed mode selects between 10 Mbps and 100 Mbps if the Gigabit enable bit is cleared.
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum SpeedMode {
|
||||
|
||||
@@ -195,6 +195,23 @@ pub struct GigEthClkCtrl {
|
||||
clk_act: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitenum(u1, exhaustive = true)]
|
||||
#[derive(Debug)]
|
||||
pub enum SrcSelGigEthRclk {
|
||||
Mio = 0,
|
||||
Emio = 1,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct GigEthRclkCtrl {
|
||||
#[bit(4, rw)]
|
||||
srcsel: SrcSelGigEthRclk,
|
||||
// Enable the ethernet controller RX clock.
|
||||
#[bit(0, rw)]
|
||||
clk_enable: bool,
|
||||
}
|
||||
|
||||
#[bitbybit::bitfield(u32)]
|
||||
#[derive(Debug)]
|
||||
pub struct CanClkCtrl {
|
||||
@@ -320,8 +337,8 @@ pub struct ClockControl {
|
||||
aper_clk_ctrl: AperClkCtrl,
|
||||
usb_0_clk_ctrl: u32,
|
||||
usb_1_clk_ctrl: u32,
|
||||
gem_0_rclk_ctrl: u32,
|
||||
gem_1_rclk_ctrl: u32,
|
||||
gem_0_rclk_ctrl: GigEthRclkCtrl,
|
||||
gem_1_rclk_ctrl: GigEthRclkCtrl,
|
||||
gem_0_clk_ctrl: GigEthClkCtrl,
|
||||
gem_1_clk_ctrl: GigEthClkCtrl,
|
||||
smc_clk_ctrl: SingleCommonPeriphIoClkCtrl,
|
||||
|
||||
Reference in New Issue
Block a user