continue sdio
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:
@@ -8,11 +8,6 @@ use crate::{clocks::IoClocks, enable_amba_peripheral_clock, slcr::Slcr, time::He
|
||||
|
||||
use super::{EthernetId, PsEthernet as _};
|
||||
|
||||
pub struct EthernetLowLevel {
|
||||
id: EthernetId,
|
||||
pub regs: zynq7000::eth::MmioRegisters<'static>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Speed {
|
||||
Mbps10,
|
||||
@@ -177,8 +172,17 @@ impl ClockDivSet {
|
||||
/// Ethernet low-level interface.
|
||||
///
|
||||
/// Basic building block for higher-level abstraction.
|
||||
pub struct EthernetLowLevel {
|
||||
id: EthernetId,
|
||||
/// Register block. Direct public access is allowed to allow low-level operations.
|
||||
pub regs: zynq7000::eth::MmioRegisters<'static>,
|
||||
}
|
||||
|
||||
impl EthernetLowLevel {
|
||||
/// Creates a new instance of the Ethernet low-level interface.
|
||||
///
|
||||
/// Returns [None] if the given registers block base address does not correspond to a valid
|
||||
/// Ethernet peripheral.
|
||||
#[inline]
|
||||
pub fn new(regs: zynq7000::eth::MmioRegisters<'static>) -> Option<Self> {
|
||||
regs.id()?;
|
||||
@@ -207,33 +211,7 @@ impl EthernetLowLevel {
|
||||
}
|
||||
|
||||
pub fn reset(&mut self, cycles: usize) {
|
||||
let assert_reset = match self.id {
|
||||
EthernetId::Eth0 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(false)
|
||||
.with_gem0_ref_rst(true)
|
||||
.with_gem1_rx_rst(false)
|
||||
.with_gem0_rx_rst(true)
|
||||
.with_gem1_cpu1x_rst(false)
|
||||
.with_gem0_cpu1x_rst(true)
|
||||
.build(),
|
||||
EthernetId::Eth1 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(true)
|
||||
.with_gem0_ref_rst(false)
|
||||
.with_gem1_rx_rst(true)
|
||||
.with_gem0_rx_rst(false)
|
||||
.with_gem1_cpu1x_rst(true)
|
||||
.with_gem0_cpu1x_rst(false)
|
||||
.build(),
|
||||
};
|
||||
unsafe {
|
||||
Slcr::with(|regs| {
|
||||
regs.reset_ctrl().write_eth(assert_reset);
|
||||
for _ in 0..cycles {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl().write_eth(EthernetReset::DEFAULT);
|
||||
});
|
||||
}
|
||||
reset(self.id, cycles);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -386,3 +364,34 @@ impl EthernetLowLevel {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the Ethernet peripheral with the given ID.
|
||||
pub fn reset(id: EthernetId, cycles: usize) {
|
||||
let assert_reset = match id {
|
||||
EthernetId::Eth0 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(false)
|
||||
.with_gem0_ref_rst(true)
|
||||
.with_gem1_rx_rst(false)
|
||||
.with_gem0_rx_rst(true)
|
||||
.with_gem1_cpu1x_rst(false)
|
||||
.with_gem0_cpu1x_rst(true)
|
||||
.build(),
|
||||
EthernetId::Eth1 => EthernetReset::builder()
|
||||
.with_gem1_ref_rst(true)
|
||||
.with_gem0_ref_rst(false)
|
||||
.with_gem1_rx_rst(true)
|
||||
.with_gem0_rx_rst(false)
|
||||
.with_gem1_cpu1x_rst(true)
|
||||
.with_gem0_cpu1x_rst(false)
|
||||
.build(),
|
||||
};
|
||||
unsafe {
|
||||
Slcr::with(|regs| {
|
||||
regs.reset_ctrl().write_eth(assert_reset);
|
||||
for _ in 0..cycles {
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl().write_eth(EthernetReset::DEFAULT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ impl Ethernet {
|
||||
});
|
||||
});
|
||||
}
|
||||
ll.configure_clock(config.clk_config_1000_mbps, true);
|
||||
ll.configure_peripheral_clock(config.clk_config_1000_mbps, true);
|
||||
let mut mdio = mdio::Mdio::new(&ll, true);
|
||||
mdio.configure_clock_div(config.mdc_clk_div);
|
||||
ll.regs.modify_net_ctrl(|mut val| {
|
||||
@@ -491,7 +491,7 @@ 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_1000_mbps, true);
|
||||
ll.configure_peripheral_clock(config.clk_config_1000_mbps, true);
|
||||
let mut mdio = mdio::Mdio::new(&ll, true);
|
||||
mdio.configure_clock_div(config.mdc_clk_div);
|
||||
Ethernet {
|
||||
|
||||
@@ -240,9 +240,91 @@ impl SdioClockConfig {
|
||||
})
|
||||
}
|
||||
}
|
||||
/// SDIO low-level interface.
|
||||
///
|
||||
/// Basic building block for higher-level abstraction.
|
||||
pub struct SdioLowLevel {
|
||||
id: SdioId,
|
||||
/// Register block. Direct public access is allowed to allow low-level operations.
|
||||
pub regs: zynq7000::sdio::MmioRegisters<'static>,
|
||||
}
|
||||
|
||||
impl SdioLowLevel {
|
||||
/// Create a new SDIO low-level interface from the given register block.
|
||||
///
|
||||
/// Returns [None] if the given registers block base address does not correspond to a valid
|
||||
/// Ethernet peripheral.
|
||||
pub fn new(regs: zynq7000::sdio::MmioRegisters<'static>) -> Option<Self> {
|
||||
let id = regs.id()?;
|
||||
Some(Self { id, regs })
|
||||
}
|
||||
|
||||
/// Common SDIO clock configuration routine which should be called once before using the SDIO.
|
||||
///
|
||||
/// This does NOT disable the clock, which should be done before changing the clock
|
||||
/// configuration. It also does NOT enable the clock.
|
||||
///
|
||||
/// It will configure the SDIO peripheral clock as well as initializing the SD clock frequency
|
||||
/// divisor based on the initial phase divider specified in the [SdioDivisors] field of the
|
||||
/// configuration.
|
||||
pub fn configure_clock(&mut self, clock_config: &SdioClockConfig) {
|
||||
unsafe {
|
||||
Slcr::with(|slcr| {
|
||||
slcr.clk_ctrl().modify_sdio_clk_ctrl(|mut val| {
|
||||
val.set_srcsel(clock_config.src_sel);
|
||||
val.set_divisor(clock_config.ref_clock_divisor);
|
||||
if self.id == SdioId::Sdio1 {
|
||||
val.set_clk_1_act(true);
|
||||
} else {
|
||||
val.set_clk_0_act(true);
|
||||
}
|
||||
val
|
||||
});
|
||||
});
|
||||
}
|
||||
self.configure_sd_clock_div_init_phase(&clock_config.sdio_clock_divisors);
|
||||
}
|
||||
|
||||
/// Configure the SD clock divisor for the initialization phase (400 kHz target clock).
|
||||
pub fn configure_sd_clock_div_init_phase(&mut self, divs: &SdioDivisors) {
|
||||
self.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_sdclk_frequency_select(divs.divisor_init_phase);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
||||
/// Configure the SD clock divisor for the normal phase (regular SDIO speed clock).
|
||||
pub fn configure_sd_clock_div_normal_phase(&mut self, divs: &SdioDivisors) {
|
||||
self.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_sdclk_frequency_select(divs.divisor_normal);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn enable_clock(&mut self) {
|
||||
self.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_sd_clock_enable(true);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn disable_clock(&mut self) {
|
||||
self.regs.modify_clock_timeout_sw_reset_control(|mut val| {
|
||||
val.set_sd_clock_enable(false);
|
||||
val
|
||||
});
|
||||
}
|
||||
|
||||
/// Reset the SDIO peripheral using the SLCR reset register for SDIO.
|
||||
pub fn reset(&mut self, cycles: u32) {
|
||||
reset(self.id, cycles);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Sdio {
|
||||
regs: zynq7000::sdio::MmioRegisters<'static>,
|
||||
ll: SdioLowLevel,
|
||||
}
|
||||
|
||||
impl Sdio {
|
||||
@@ -265,7 +347,6 @@ impl Sdio {
|
||||
return None;
|
||||
}
|
||||
Some(Self::new(
|
||||
id,
|
||||
regs,
|
||||
clock_config,
|
||||
clock_pin,
|
||||
@@ -293,7 +374,6 @@ impl Sdio {
|
||||
return None;
|
||||
}
|
||||
Some(Self::new(
|
||||
id,
|
||||
regs,
|
||||
clock_config,
|
||||
clock_pin,
|
||||
@@ -303,37 +383,39 @@ impl Sdio {
|
||||
}
|
||||
|
||||
fn new(
|
||||
id: SdioId,
|
||||
regs: zynq7000::sdio::MmioRegisters<'static>,
|
||||
clock_config: SdioClockConfig,
|
||||
clock_pin: impl MioPin,
|
||||
command_pin: impl MioPin,
|
||||
data_pins: (impl MioPin, impl MioPin, impl MioPin, impl MioPin),
|
||||
) -> Self {
|
||||
let mut ll = SdioLowLevel::new(regs).unwrap();
|
||||
Self::initialize(&mut ll, &clock_config);
|
||||
IoPeriphPin::new(clock_pin, MUX_CONF, None);
|
||||
IoPeriphPin::new(command_pin, MUX_CONF, None);
|
||||
IoPeriphPin::new(data_pins.0, MUX_CONF, None);
|
||||
IoPeriphPin::new(data_pins.1, MUX_CONF, None);
|
||||
IoPeriphPin::new(data_pins.2, MUX_CONF, None);
|
||||
IoPeriphPin::new(data_pins.3, MUX_CONF, None);
|
||||
Self { regs }
|
||||
Self { ll }
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
id: SdioId,
|
||||
regs: &mut zynq7000::sdio::MmioRegisters<'static>,
|
||||
clock_config: &SdioClockConfig,
|
||||
) {
|
||||
reset(id, 10);
|
||||
// TODO: Clock Config
|
||||
// TODO: There is probably some other configuartion necessary.. the docs really are not
|
||||
fn initialize(ll: &mut SdioLowLevel, clock_config: &SdioClockConfig) {
|
||||
ll.reset(10);
|
||||
// TODO: SW reset for all?
|
||||
// TODO: Internal clock?
|
||||
ll.disable_clock();
|
||||
ll.configure_clock(clock_config);
|
||||
ll.enable_clock();
|
||||
|
||||
// TODO: There is probably some other configuration necessary.. the docs really are not
|
||||
// complete here..
|
||||
unsafe {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn regs(&mut self) -> &mut zynq7000::sdio::MmioRegisters<'static> {
|
||||
&mut self.regs
|
||||
&mut self.ll.regs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +444,7 @@ pub fn reset(id: SdioId, cycles: u32) {
|
||||
regs.reset_ctrl().write_sdio(assert_reset);
|
||||
// Keep it in reset for a few cycle.. not sure if this is necessary.
|
||||
for _ in 0..cycles {
|
||||
cortex_ar::asm::nop();
|
||||
aarch32_cpu::asm::nop();
|
||||
}
|
||||
regs.reset_ctrl().write_sdio(DualRefAndClockReset::DEFAULT);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user