continue with 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:
@@ -52,7 +52,10 @@ impl ClockDivisors {
|
||||
|
||||
/// 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) {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use arbitrary_int::{traits::Integer as _, u3, u6};
|
||||
use zynq7000::{
|
||||
sdio::SdClockDivisor,
|
||||
sdio::{SDIO_BASE_ADDR_0, SDIO_BASE_ADDR_1, SdClockDivisor},
|
||||
slcr::{clocks::SrcSelIo, reset::DualRefAndClockReset},
|
||||
};
|
||||
|
||||
@@ -9,21 +10,26 @@ use crate::gpio::mio::{
|
||||
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
|
||||
};
|
||||
use crate::{
|
||||
clocks::Clocks,
|
||||
gpio::mio::{
|
||||
Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34,
|
||||
Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Pin,
|
||||
clocks::{Clocks, IoClocks},
|
||||
gpio::{
|
||||
IoPeriphPin,
|
||||
mio::{
|
||||
Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33,
|
||||
Mio34, Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, MioPin, MuxConfig, Pin,
|
||||
},
|
||||
},
|
||||
slcr::Slcr,
|
||||
time::Hertz,
|
||||
};
|
||||
|
||||
pub trait Sdio0ClockPin {}
|
||||
pub trait Sdio0CommandPin {}
|
||||
pub trait Sdio0Data0Pin {}
|
||||
pub trait Sdio0Data1Pin {}
|
||||
pub trait Sdio0Data2Pin {}
|
||||
pub trait Sdio0Data3Pin {}
|
||||
pub const MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b100));
|
||||
|
||||
pub trait Sdio0ClockPin: MioPin {}
|
||||
pub trait Sdio0CommandPin: MioPin {}
|
||||
pub trait Sdio0Data0Pin: MioPin {}
|
||||
pub trait Sdio0Data1Pin: MioPin {}
|
||||
pub trait Sdio0Data2Pin: MioPin {}
|
||||
pub trait Sdio0Data3Pin: MioPin {}
|
||||
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0ClockPin for Pin<Mio16> {}
|
||||
@@ -61,12 +67,12 @@ impl Sdio0Data3Pin for Pin<Mio33> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
impl Sdio0Data3Pin for Pin<Mio45> {}
|
||||
|
||||
pub trait Sdio1ClockPin {}
|
||||
pub trait Sdio1CommandPin {}
|
||||
pub trait Sdio1Data0Pin {}
|
||||
pub trait Sdio1Data1Pin {}
|
||||
pub trait Sdio1Data2Pin {}
|
||||
pub trait Sdio1Data3Pin {}
|
||||
pub trait Sdio1ClockPin: MioPin {}
|
||||
pub trait Sdio1CommandPin: MioPin {}
|
||||
pub trait Sdio1Data0Pin: MioPin {}
|
||||
pub trait Sdio1Data1Pin: MioPin {}
|
||||
pub trait Sdio1Data2Pin: MioPin {}
|
||||
pub trait Sdio1Data3Pin: MioPin {}
|
||||
|
||||
impl Sdio1ClockPin for Pin<Mio12> {}
|
||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||
@@ -114,9 +120,44 @@ pub enum SdioId {
|
||||
Sdio1,
|
||||
}
|
||||
|
||||
pub struct Sdio {}
|
||||
impl SdioId {
|
||||
/// Steal the ethernet register block for the given ethernet ID.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Circumvents ownership and safety guarantees of the HAL.
|
||||
pub const unsafe fn steal_regs(&self) -> zynq7000::sdio::MmioRegisters<'static> {
|
||||
unsafe {
|
||||
match self {
|
||||
SdioId::Sdio0 => zynq7000::sdio::Registers::new_mmio_fixed_0(),
|
||||
SdioId::Sdio1 => zynq7000::sdio::Registers::new_mmio_fixed_1(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sdio {}
|
||||
pub trait SdioRegisters {
|
||||
fn reg_block(&self) -> zynq7000::sdio::MmioRegisters<'static>;
|
||||
fn id(&self) -> Option<SdioId>;
|
||||
}
|
||||
|
||||
impl SdioRegisters for zynq7000::sdio::MmioRegisters<'static> {
|
||||
#[inline]
|
||||
fn reg_block(&self) -> zynq7000::sdio::MmioRegisters<'static> {
|
||||
unsafe { self.clone() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn id(&self) -> Option<SdioId> {
|
||||
let base_addr = unsafe { self.ptr() } as usize;
|
||||
if base_addr == SDIO_BASE_ADDR_0 {
|
||||
return Some(SdioId::Sdio0);
|
||||
} else if base_addr == SDIO_BASE_ADDR_1 {
|
||||
return Some(SdioId::Sdio1);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SdioDivisors {
|
||||
/// Divisor which will be used during the initialization phase when ACMD41 is issued.
|
||||
@@ -129,13 +170,9 @@ pub struct SdioDivisors {
|
||||
}
|
||||
|
||||
impl SdioDivisors {
|
||||
pub fn calculate(src_sel: SrcSelIo, clocks: &Clocks, target_speed: Hertz) -> Self {
|
||||
// Calculate the SDIO clock divisors for the given SDIO reference clock and target speed.
|
||||
pub fn calculate(ref_clk: Hertz, target_speed: Hertz) -> Self {
|
||||
const INIT_CLOCK_HZ: u32 = 400_000;
|
||||
let ref_clk = match src_sel {
|
||||
SrcSelIo::IoPll | SrcSelIo::IoPllAlt => clocks.io_clocks().ref_clk(),
|
||||
SrcSelIo::ArmPll => clocks.arm_clocks().ref_clk(),
|
||||
SrcSelIo::DdrPll => clocks.ddr_clocks().ref_clk(),
|
||||
};
|
||||
let divisor_select_from_value = |value: u32| match value {
|
||||
0..=1 => SdClockDivisor::Div1,
|
||||
2 => SdClockDivisor::Div2,
|
||||
@@ -152,31 +189,158 @@ impl SdioDivisors {
|
||||
divisor_normal: divisor_select_from_value(ref_clk.raw().div_ceil(target_speed.raw())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate divisors for a regular clock configuration which configures the IO clock as
|
||||
/// source.
|
||||
pub fn calculate_for_io_clock(io_clocks: &IoClocks, target_speed: Hertz) -> Self {
|
||||
Self::calculate(io_clocks.sdio_clk(), target_speed)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SdioClockConfig {
|
||||
src_sel: SrcSelIo,
|
||||
divisors: SdioDivisors,
|
||||
/// Selects the source clock for the SDIO peripheral reference clock.
|
||||
pub src_sel: SrcSelIo,
|
||||
/// Selects the divisor which divies the source clock to create the SDIO peripheral
|
||||
/// reference clock.
|
||||
pub ref_clock_divisor: u6,
|
||||
/// The SDIO peripheral reference clock is divided again to create the SDIO clock.
|
||||
pub sdio_clock_divisors: SdioDivisors,
|
||||
}
|
||||
|
||||
impl SdioClockConfig {
|
||||
pub fn new(src_sel: SrcSelIo, divisors: SdioDivisors) -> Self {
|
||||
Self { src_sel, divisors }
|
||||
pub fn new(
|
||||
src_sel: SrcSelIo,
|
||||
ref_clock_divisor: u6,
|
||||
sdio_clock_divisors: SdioDivisors,
|
||||
) -> Self {
|
||||
Self {
|
||||
src_sel,
|
||||
ref_clock_divisor,
|
||||
sdio_clock_divisors,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_for_io_clock(clocks: &Clocks, target_speed: Hertz) -> Self {
|
||||
let divisors = SdioDivisors::calculate(SrcSelIo::IoPll, clocks, target_speed);
|
||||
Self {
|
||||
src_sel: SrcSelIo::IoPll,
|
||||
divisors,
|
||||
pub fn calculate_for_io_clock(
|
||||
io_clocks: &IoClocks,
|
||||
target_ref_clock: Hertz,
|
||||
target_sdio_speed: Hertz,
|
||||
) -> Option<Self> {
|
||||
let ref_clk = io_clocks.ref_clk();
|
||||
let io_ref_clock_divisor = ref_clk.raw().div_ceil(target_ref_clock.raw());
|
||||
if io_ref_clock_divisor > u6::MAX.as_u32() {
|
||||
return None;
|
||||
}
|
||||
let target_speed = ref_clk / io_ref_clock_divisor;
|
||||
|
||||
let sdio_clock_divisors = SdioDivisors::calculate(target_speed, target_sdio_speed);
|
||||
Some(Self {
|
||||
src_sel: SrcSelIo::IoPll,
|
||||
ref_clock_divisor: u6::new(io_ref_clock_divisor as u8),
|
||||
sdio_clock_divisors,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the UART peripheral using the SLCR reset register for UART.
|
||||
pub struct Sdio {
|
||||
regs: zynq7000::sdio::MmioRegisters<'static>,
|
||||
}
|
||||
|
||||
impl Sdio {
|
||||
pub fn new_for_sdio_0<
|
||||
Sdio0Clock: Sdio0ClockPin,
|
||||
Sdio0Command: Sdio0CommandPin,
|
||||
Sdio0Data0: Sdio0Data0Pin,
|
||||
Sdio0Data1: Sdio0Data1Pin,
|
||||
Sdio0Data2: Sdio0Data2Pin,
|
||||
Sdio0Data3: Sdio0Data3Pin,
|
||||
>(
|
||||
regs: zynq7000::sdio::MmioRegisters<'static>,
|
||||
clock_config: SdioClockConfig,
|
||||
clock_pin: Sdio0Clock,
|
||||
command_pin: Sdio0Command,
|
||||
data_pins: (Sdio0Data0, Sdio0Data1, Sdio0Data2, Sdio0Data3),
|
||||
) -> Option<Self> {
|
||||
let id = regs.id()?;
|
||||
if id != SdioId::Sdio1 {
|
||||
return None;
|
||||
}
|
||||
Some(Self::new(
|
||||
id,
|
||||
regs,
|
||||
clock_config,
|
||||
clock_pin,
|
||||
command_pin,
|
||||
data_pins,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn new_for_sdio_1<
|
||||
Sdio1Clock: Sdio1ClockPin,
|
||||
Sdio1Command: Sdio1CommandPin,
|
||||
Sdio1Data0: Sdio1Data0Pin,
|
||||
Sdio1Data1: Sdio1Data1Pin,
|
||||
Sdio1Data2: Sdio1Data2Pin,
|
||||
Sdio1Data3: Sdio1Data3Pin,
|
||||
>(
|
||||
regs: zynq7000::sdio::MmioRegisters<'static>,
|
||||
clock_config: SdioClockConfig,
|
||||
clock_pin: Sdio1Clock,
|
||||
command_pin: Sdio1Command,
|
||||
data_pins: (Sdio1Data0, Sdio1Data1, Sdio1Data2, Sdio1Data3),
|
||||
) -> Option<Self> {
|
||||
let id = regs.id()?;
|
||||
if id != SdioId::Sdio1 {
|
||||
return None;
|
||||
}
|
||||
Some(Self::new(
|
||||
id,
|
||||
regs,
|
||||
clock_config,
|
||||
clock_pin,
|
||||
command_pin,
|
||||
data_pins,
|
||||
))
|
||||
}
|
||||
|
||||
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 {
|
||||
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 }
|
||||
}
|
||||
|
||||
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
|
||||
// complete here..
|
||||
unsafe {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn regs(&mut self) -> &mut zynq7000::sdio::MmioRegisters<'static> {
|
||||
&mut self.regs
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset the SDIO peripheral using the SLCR reset register for SDIO.
|
||||
///
|
||||
/// Please note that this function will interfere with an already configured
|
||||
/// UART instance.
|
||||
/// SDIO instance.
|
||||
#[inline]
|
||||
pub fn reset(id: SdioId, cycles: u32) {
|
||||
let assert_reset = match id {
|
||||
|
||||
@@ -431,13 +431,27 @@ pub struct Registers {
|
||||
static_assertions::const_assert_eq!(core::mem::size_of::<Registers>(), 0x100);
|
||||
|
||||
impl Registers {
|
||||
/// Create a new SDIO MMIO instance for SDIO 0 at address [SDIO_BASE_ADDR_0].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub fn new_mmio_fixed_0() -> MmioRegisters<'static> {
|
||||
pub const unsafe fn new_mmio_fixed_0() -> MmioRegisters<'static> {
|
||||
unsafe { Self::new_mmio_at(SDIO_BASE_ADDR_0) }
|
||||
}
|
||||
|
||||
/// Create a new SDIO MMIO instance for SDIO 1 at address [SDIO_BASE_ADDR_1].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This API can be used to potentially create a driver to the same peripheral structure
|
||||
/// from multiple threads. The user must ensure that concurrent accesses are safe and do not
|
||||
/// interfere with each other.
|
||||
#[inline]
|
||||
pub fn new_mmio_fixed_1() -> MmioRegisters<'static> {
|
||||
pub const unsafe fn new_mmio_fixed_1() -> MmioRegisters<'static> {
|
||||
unsafe { Self::new_mmio_at(SDIO_BASE_ADDR_1) }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user