continue with SDIO
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,
|
/// Calls [Self::calculate_for_rgmii], assuming that the IO clock is the reference clock,
|
||||||
/// which is the default clock for the Ethernet module.
|
/// 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)
|
Self::calculate_for_rgmii(io_clks.ref_clk(), target_speed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
use arbitrary_int::{traits::Integer as _, u3, u6};
|
||||||
use zynq7000::{
|
use zynq7000::{
|
||||||
sdio::SdClockDivisor,
|
sdio::{SDIO_BASE_ADDR_0, SDIO_BASE_ADDR_1, SdClockDivisor},
|
||||||
slcr::{clocks::SrcSelIo, reset::DualRefAndClockReset},
|
slcr::{clocks::SrcSelIo, reset::DualRefAndClockReset},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -9,21 +10,26 @@ use crate::gpio::mio::{
|
|||||||
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
|
Mio41, Mio42, Mio43, Mio44, Mio45, Mio46, Mio47, Mio50, Mio51,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
clocks::Clocks,
|
clocks::{Clocks, IoClocks},
|
||||||
gpio::mio::{
|
gpio::{
|
||||||
Mio10, Mio11, Mio12, Mio13, Mio14, Mio15, Mio28, Mio29, Mio30, Mio31, Mio32, Mio33, Mio34,
|
IoPeriphPin,
|
||||||
Mio35, Mio36, Mio37, Mio38, Mio39, Mio48, Mio49, Pin,
|
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,
|
slcr::Slcr,
|
||||||
time::Hertz,
|
time::Hertz,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait Sdio0ClockPin {}
|
pub const MUX_CONF: MuxConfig = MuxConfig::new_with_l3(u3::new(0b100));
|
||||||
pub trait Sdio0CommandPin {}
|
|
||||||
pub trait Sdio0Data0Pin {}
|
pub trait Sdio0ClockPin: MioPin {}
|
||||||
pub trait Sdio0Data1Pin {}
|
pub trait Sdio0CommandPin: MioPin {}
|
||||||
pub trait Sdio0Data2Pin {}
|
pub trait Sdio0Data0Pin: MioPin {}
|
||||||
pub trait Sdio0Data3Pin {}
|
pub trait Sdio0Data1Pin: MioPin {}
|
||||||
|
pub trait Sdio0Data2Pin: MioPin {}
|
||||||
|
pub trait Sdio0Data3Pin: MioPin {}
|
||||||
|
|
||||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||||
impl Sdio0ClockPin for Pin<Mio16> {}
|
impl Sdio0ClockPin for Pin<Mio16> {}
|
||||||
@@ -61,12 +67,12 @@ impl Sdio0Data3Pin for Pin<Mio33> {}
|
|||||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||||
impl Sdio0Data3Pin for Pin<Mio45> {}
|
impl Sdio0Data3Pin for Pin<Mio45> {}
|
||||||
|
|
||||||
pub trait Sdio1ClockPin {}
|
pub trait Sdio1ClockPin: MioPin {}
|
||||||
pub trait Sdio1CommandPin {}
|
pub trait Sdio1CommandPin: MioPin {}
|
||||||
pub trait Sdio1Data0Pin {}
|
pub trait Sdio1Data0Pin: MioPin {}
|
||||||
pub trait Sdio1Data1Pin {}
|
pub trait Sdio1Data1Pin: MioPin {}
|
||||||
pub trait Sdio1Data2Pin {}
|
pub trait Sdio1Data2Pin: MioPin {}
|
||||||
pub trait Sdio1Data3Pin {}
|
pub trait Sdio1Data3Pin: MioPin {}
|
||||||
|
|
||||||
impl Sdio1ClockPin for Pin<Mio12> {}
|
impl Sdio1ClockPin for Pin<Mio12> {}
|
||||||
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
#[cfg(not(feature = "7z010-7z007s-clg225"))]
|
||||||
@@ -114,9 +120,44 @@ pub enum SdioId {
|
|||||||
Sdio1,
|
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 {
|
pub struct SdioDivisors {
|
||||||
/// Divisor which will be used during the initialization phase when ACMD41 is issued.
|
/// Divisor which will be used during the initialization phase when ACMD41 is issued.
|
||||||
@@ -129,13 +170,9 @@ pub struct SdioDivisors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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;
|
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 {
|
let divisor_select_from_value = |value: u32| match value {
|
||||||
0..=1 => SdClockDivisor::Div1,
|
0..=1 => SdClockDivisor::Div1,
|
||||||
2 => SdClockDivisor::Div2,
|
2 => SdClockDivisor::Div2,
|
||||||
@@ -152,31 +189,158 @@ impl SdioDivisors {
|
|||||||
divisor_normal: divisor_select_from_value(ref_clk.raw().div_ceil(target_speed.raw())),
|
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 {
|
pub struct SdioClockConfig {
|
||||||
src_sel: SrcSelIo,
|
/// Selects the source clock for the SDIO peripheral reference clock.
|
||||||
divisors: SdioDivisors,
|
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 {
|
impl SdioClockConfig {
|
||||||
pub fn new(src_sel: SrcSelIo, divisors: SdioDivisors) -> Self {
|
pub fn new(
|
||||||
Self { src_sel, divisors }
|
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 {
|
pub fn calculate_for_io_clock(
|
||||||
let divisors = SdioDivisors::calculate(SrcSelIo::IoPll, clocks, target_speed);
|
io_clocks: &IoClocks,
|
||||||
Self {
|
target_ref_clock: Hertz,
|
||||||
src_sel: SrcSelIo::IoPll,
|
target_sdio_speed: Hertz,
|
||||||
divisors,
|
) -> 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
|
/// Please note that this function will interfere with an already configured
|
||||||
/// UART instance.
|
/// SDIO instance.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset(id: SdioId, cycles: u32) {
|
pub fn reset(id: SdioId, cycles: u32) {
|
||||||
let assert_reset = match id {
|
let assert_reset = match id {
|
||||||
|
|||||||
@@ -431,13 +431,27 @@ pub struct Registers {
|
|||||||
static_assertions::const_assert_eq!(core::mem::size_of::<Registers>(), 0x100);
|
static_assertions::const_assert_eq!(core::mem::size_of::<Registers>(), 0x100);
|
||||||
|
|
||||||
impl Registers {
|
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]
|
#[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) }
|
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]
|
#[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) }
|
unsafe { Self::new_mmio_at(SDIO_BASE_ADDR_1) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user