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 _};
|
use super::{EthernetId, PsEthernet as _};
|
||||||
|
|
||||||
pub struct EthernetLowLevel {
|
|
||||||
id: EthernetId,
|
|
||||||
pub regs: zynq7000::eth::MmioRegisters<'static>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Speed {
|
pub enum Speed {
|
||||||
Mbps10,
|
Mbps10,
|
||||||
@@ -177,8 +172,17 @@ impl ClockDivSet {
|
|||||||
/// Ethernet low-level interface.
|
/// Ethernet low-level interface.
|
||||||
///
|
///
|
||||||
/// Basic building block for higher-level abstraction.
|
/// 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 {
|
impl EthernetLowLevel {
|
||||||
/// Creates a new instance of the Ethernet low-level interface.
|
/// 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]
|
#[inline]
|
||||||
pub fn new(regs: zynq7000::eth::MmioRegisters<'static>) -> Option<Self> {
|
pub fn new(regs: zynq7000::eth::MmioRegisters<'static>) -> Option<Self> {
|
||||||
regs.id()?;
|
regs.id()?;
|
||||||
@@ -207,33 +211,7 @@ impl EthernetLowLevel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(&mut self, cycles: usize) {
|
pub fn reset(&mut self, cycles: usize) {
|
||||||
let assert_reset = match self.id {
|
reset(self.id, cycles);
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -386,3 +364,34 @@ impl EthernetLowLevel {
|
|||||||
self.id
|
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);
|
let mut mdio = mdio::Mdio::new(&ll, true);
|
||||||
mdio.configure_clock_div(config.mdc_clk_div);
|
mdio.configure_clock_div(config.mdc_clk_div);
|
||||||
ll.regs.modify_net_ctrl(|mut val| {
|
ll.regs.modify_net_ctrl(|mut val| {
|
||||||
@@ -491,7 +491,7 @@ impl Ethernet {
|
|||||||
|
|
||||||
pub fn new(mut ll: EthernetLowLevel, config: EthernetConfig) -> Self {
|
pub fn new(mut ll: EthernetLowLevel, config: EthernetConfig) -> Self {
|
||||||
Self::common_init(&mut ll, config.mac_address);
|
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);
|
let mut mdio = mdio::Mdio::new(&ll, true);
|
||||||
mdio.configure_clock_div(config.mdc_clk_div);
|
mdio.configure_clock_div(config.mdc_clk_div);
|
||||||
Ethernet {
|
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 {
|
pub struct Sdio {
|
||||||
regs: zynq7000::sdio::MmioRegisters<'static>,
|
ll: SdioLowLevel,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sdio {
|
impl Sdio {
|
||||||
@@ -265,7 +347,6 @@ impl Sdio {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(Self::new(
|
Some(Self::new(
|
||||||
id,
|
|
||||||
regs,
|
regs,
|
||||||
clock_config,
|
clock_config,
|
||||||
clock_pin,
|
clock_pin,
|
||||||
@@ -293,7 +374,6 @@ impl Sdio {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Some(Self::new(
|
Some(Self::new(
|
||||||
id,
|
|
||||||
regs,
|
regs,
|
||||||
clock_config,
|
clock_config,
|
||||||
clock_pin,
|
clock_pin,
|
||||||
@@ -303,37 +383,39 @@ impl Sdio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new(
|
fn new(
|
||||||
id: SdioId,
|
|
||||||
regs: zynq7000::sdio::MmioRegisters<'static>,
|
regs: zynq7000::sdio::MmioRegisters<'static>,
|
||||||
clock_config: SdioClockConfig,
|
clock_config: SdioClockConfig,
|
||||||
clock_pin: impl MioPin,
|
clock_pin: impl MioPin,
|
||||||
command_pin: impl MioPin,
|
command_pin: impl MioPin,
|
||||||
data_pins: (impl MioPin, impl MioPin, impl MioPin, impl MioPin),
|
data_pins: (impl MioPin, impl MioPin, impl MioPin, impl MioPin),
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let mut ll = SdioLowLevel::new(regs).unwrap();
|
||||||
|
Self::initialize(&mut ll, &clock_config);
|
||||||
IoPeriphPin::new(clock_pin, MUX_CONF, None);
|
IoPeriphPin::new(clock_pin, MUX_CONF, None);
|
||||||
IoPeriphPin::new(command_pin, MUX_CONF, None);
|
IoPeriphPin::new(command_pin, MUX_CONF, None);
|
||||||
IoPeriphPin::new(data_pins.0, MUX_CONF, None);
|
IoPeriphPin::new(data_pins.0, MUX_CONF, None);
|
||||||
IoPeriphPin::new(data_pins.1, MUX_CONF, None);
|
IoPeriphPin::new(data_pins.1, MUX_CONF, None);
|
||||||
IoPeriphPin::new(data_pins.2, MUX_CONF, None);
|
IoPeriphPin::new(data_pins.2, MUX_CONF, None);
|
||||||
IoPeriphPin::new(data_pins.3, MUX_CONF, None);
|
IoPeriphPin::new(data_pins.3, MUX_CONF, None);
|
||||||
Self { regs }
|
Self { ll }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(
|
fn initialize(ll: &mut SdioLowLevel, clock_config: &SdioClockConfig) {
|
||||||
id: SdioId,
|
ll.reset(10);
|
||||||
regs: &mut zynq7000::sdio::MmioRegisters<'static>,
|
// TODO: SW reset for all?
|
||||||
clock_config: &SdioClockConfig,
|
// TODO: Internal clock?
|
||||||
) {
|
ll.disable_clock();
|
||||||
reset(id, 10);
|
ll.configure_clock(clock_config);
|
||||||
// TODO: Clock Config
|
ll.enable_clock();
|
||||||
// TODO: There is probably some other configuartion necessary.. the docs really are not
|
|
||||||
|
// TODO: There is probably some other configuration necessary.. the docs really are not
|
||||||
// complete here..
|
// complete here..
|
||||||
unsafe {}
|
unsafe {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn regs(&mut self) -> &mut zynq7000::sdio::MmioRegisters<'static> {
|
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);
|
regs.reset_ctrl().write_sdio(assert_reset);
|
||||||
// Keep it in reset for a few cycle.. not sure if this is necessary.
|
// Keep it in reset for a few cycle.. not sure if this is necessary.
|
||||||
for _ in 0..cycles {
|
for _ in 0..cycles {
|
||||||
cortex_ar::asm::nop();
|
aarch32_cpu::asm::nop();
|
||||||
}
|
}
|
||||||
regs.reset_ctrl().write_sdio(DualRefAndClockReset::DEFAULT);
|
regs.reset_ctrl().write_sdio(DualRefAndClockReset::DEFAULT);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user