support 8 lane data bus

This commit is contained in:
Anton Lazarev 2025-03-26 23:26:11 -07:00
parent b92eb948b5
commit 0a231505d8
No known key found for this signature in database
GPG Key ID: FBD20243E0CD9104

View File

@ -145,6 +145,8 @@ pub enum Error {
Crc,
/// No card inserted.
NoCard,
/// 8-lane buses are not supported for SD cards.
BusWidth,
/// Bad clock supplied to the SDMMC peripheral.
BadClock,
/// Signaling switch failed.
@ -365,6 +367,10 @@ pub struct Sdmmc<'d, T: Instance> {
d1: Option<Peri<'d, AnyPin>>,
d2: Option<Peri<'d, AnyPin>>,
d3: Option<Peri<'d, AnyPin>>,
d4: Option<Peri<'d, AnyPin>>,
d5: Option<Peri<'d, AnyPin>>,
d6: Option<Peri<'d, AnyPin>>,
d7: Option<Peri<'d, AnyPin>>,
config: Config,
/// Current clock to card
@ -413,6 +419,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
None,
None,
None,
None,
None,
None,
None,
config,
)
}
@ -448,6 +458,60 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
Some(d1.into()),
Some(d2.into()),
Some(d3.into()),
None,
None,
None,
None,
config,
)
}
}
#[cfg(sdmmc_v1)]
impl<'d, T: Instance> Sdmmc<'d, T> {
/// Create a new SDMMC driver, with 8 data lanes.
pub fn new_8bit(
sdmmc: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
dma: Peri<'d, impl SdmmcDma<T>>,
clk: Peri<'d, impl CkPin<T>>,
cmd: Peri<'d, impl CmdPin<T>>,
d0: Peri<'d, impl D0Pin<T>>,
d1: Peri<'d, impl D1Pin<T>>,
d2: Peri<'d, impl D2Pin<T>>,
d3: Peri<'d, impl D3Pin<T>>,
d4: Peri<'d, impl D4Pin<T>>,
d5: Peri<'d, impl D5Pin<T>>,
d6: Peri<'d, impl D6Pin<T>>,
d7: Peri<'d, impl D7Pin<T>>,
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
d1.set_as_af(d1.af_num(), DATA_AF);
d2.set_as_af(d2.af_num(), DATA_AF);
d3.set_as_af(d3.af_num(), DATA_AF);
d4.set_as_af(d4.af_num(), DATA_AF);
d5.set_as_af(d5.af_num(), DATA_AF);
d6.set_as_af(d6.af_num(), DATA_AF);
d7.set_as_af(d7.af_num(), DATA_AF);
});
Self::new_inner(
sdmmc,
new_dma_nonopt!(dma),
clk.into(),
cmd.into(),
d0.into(),
Some(d1.into()),
Some(d2.into()),
Some(d3.into()),
Some(d4.into()),
Some(d5.into()),
Some(d6.into()),
Some(d7.into()),
config,
)
}
@ -470,7 +534,20 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
d0.set_as_af(d0.af_num(), DATA_AF);
});
Self::new_inner(sdmmc, clk.into(), cmd.into(), d0.into(), None, None, None, config)
Self::new_inner(
sdmmc,
clk.into(),
cmd.into(),
d0.into(),
None,
None,
None,
None,
None,
None,
None,
config,
)
}
/// Create a new SDMMC driver, with 4 data lanes.
@ -502,6 +579,58 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
Some(d1.into()),
Some(d2.into()),
Some(d3.into()),
None,
None,
None,
None,
config,
)
}
}
#[cfg(sdmmc_v2)]
impl<'d, T: Instance> Sdmmc<'d, T> {
/// Create a new SDMMC driver, with 8 data lanes.
pub fn new_8bit(
sdmmc: Peri<'d, T>,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
clk: Peri<'d, impl CkPin<T>>,
cmd: Peri<'d, impl CmdPin<T>>,
d0: Peri<'d, impl D0Pin<T>>,
d1: Peri<'d, impl D1Pin<T>>,
d2: Peri<'d, impl D2Pin<T>>,
d3: Peri<'d, impl D3Pin<T>>,
d4: Peri<'d, impl D4Pin<T>>,
d5: Peri<'d, impl D5Pin<T>>,
d6: Peri<'d, impl D6Pin<T>>,
d7: Peri<'d, impl D7Pin<T>>,
config: Config,
) -> Self {
critical_section::with(|_| {
clk.set_as_af(clk.af_num(), CLK_AF);
cmd.set_as_af(cmd.af_num(), CMD_AF);
d0.set_as_af(d0.af_num(), DATA_AF);
d1.set_as_af(d1.af_num(), DATA_AF);
d2.set_as_af(d2.af_num(), DATA_AF);
d3.set_as_af(d3.af_num(), DATA_AF);
d4.set_as_af(d4.af_num(), DATA_AF);
d5.set_as_af(d5.af_num(), DATA_AF);
d6.set_as_af(d6.af_num(), DATA_AF);
d7.set_as_af(d7.af_num(), DATA_AF);
});
Self::new_inner(
sdmmc,
clk.into(),
cmd.into(),
d0.into(),
Some(d1.into()),
Some(d2.into()),
Some(d3.into()),
Some(d4.into()),
Some(d5.into()),
Some(d6.into()),
Some(d7.into()),
config,
)
}
@ -517,6 +646,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
d1: Option<Peri<'d, AnyPin>>,
d2: Option<Peri<'d, AnyPin>>,
d3: Option<Peri<'d, AnyPin>>,
d4: Option<Peri<'d, AnyPin>>,
d5: Option<Peri<'d, AnyPin>>,
d6: Option<Peri<'d, AnyPin>>,
d7: Option<Peri<'d, AnyPin>>,
config: Config,
) -> Self {
rcc::enable_and_reset::<T>();
@ -555,6 +688,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
d1,
d2,
d3,
d4,
d5,
d6,
d7,
config,
clock: SD_INIT_FREQ,
@ -1039,6 +1176,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
impl<'d, T: Instance> Sdmmc<'d, T> {
/// Initializes card (if present) and sets the bus at the specified frequency.
pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
if self.d7.is_some() {
return Err(Error::BusWidth);
}
let regs = T::regs();
let ker_ck = T::frequency();
@ -1419,9 +1560,10 @@ impl<'d, T: Instance> Sdmmc<'d, T> {
let regs = T::regs();
let ker_ck = T::frequency();
let bus_width = match self.d3.is_some() {
true => BusWidth::Four,
false => BusWidth::One,
let bus_width = match (self.d3.is_some(), self.d7.is_some()) {
(true, true) => BusWidth::Eight,
(true, false) => BusWidth::Four,
_ => BusWidth::One,
};
// While the SD/SDIO card or eMMC is in identification mode,
@ -1613,6 +1755,18 @@ impl<'d, T: Instance> Drop for Sdmmc<'d, T> {
if let Some(x) = &mut self.d3 {
x.set_as_disconnected();
}
if let Some(x) = &mut self.d4 {
x.set_as_disconnected();
}
if let Some(x) = &mut self.d5 {
x.set_as_disconnected();
}
if let Some(x) = &mut self.d6 {
x.set_as_disconnected();
}
if let Some(x) = &mut self.d7 {
x.set_as_disconnected();
}
});
}
}