1098: Reset sdmmc clock on card init r=Dirbaio a=chemicstry

Set clock back to 400kHz in `init_card()`, which allows card reinitialization if it was removed

Co-authored-by: chemicstry <chemicstry@gmail.com>
This commit is contained in:
bors[bot] 2022-12-07 15:34:49 +00:00 committed by GitHub
commit 1b8c0733e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -18,6 +18,9 @@ use crate::rcc::RccPeripheral;
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
/// Frequency used for SD Card initialization. Must be no higher than 400 kHz.
const SD_INIT_FREQ: Hertz = Hertz(400_000);
/// The signalling scheme used on the SDMMC bus /// The signalling scheme used on the SDMMC bus
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -295,7 +298,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
T::reset(); T::reset();
let inner = T::inner(); let inner = T::inner();
let clock = unsafe { inner.new_inner(T::frequency()) }; unsafe { inner.new_inner() };
irq.set_handler(Self::on_interrupt); irq.set_handler(Self::on_interrupt);
irq.unpend(); irq.unpend();
@ -314,7 +317,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
d3, d3,
config, config,
clock, clock: SD_INIT_FREQ,
signalling: Default::default(), signalling: Default::default(),
card: None, card: None,
} }
@ -415,7 +418,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
T::reset(); T::reset();
let inner = T::inner(); let inner = T::inner();
let clock = unsafe { inner.new_inner(T::frequency()) }; unsafe { inner.new_inner() };
irq.set_handler(Self::on_interrupt); irq.set_handler(Self::on_interrupt);
irq.unpend(); irq.unpend();
@ -434,7 +437,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
d3, d3,
config, config,
clock, clock: SD_INIT_FREQ,
signalling: Default::default(), signalling: Default::default(),
card: None, card: None,
} }
@ -561,16 +564,10 @@ impl SdmmcInner {
/// # Safety /// # Safety
/// ///
/// Access to `regs` registers should be exclusive /// Access to `regs` registers should be exclusive
unsafe fn new_inner(&self, kernel_clk: Hertz) -> Hertz { unsafe fn new_inner(&self) {
let regs = self.0; let regs = self.0;
// While the SD/SDIO card or eMMC is in identification mode,
// the SDMMC_CK frequency must be less than 400 kHz.
let (clkdiv, clock) = unwrap!(clk_div(kernel_clk, 400_000));
regs.clkcr().write(|w| { regs.clkcr().write(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
w.set_pwrsav(false); w.set_pwrsav(false);
w.set_negedge(false); w.set_negedge(false);
w.set_hwfc_en(true); w.set_hwfc_en(true);
@ -582,8 +579,6 @@ impl SdmmcInner {
// Power off, writen 00: Clock to the card is stopped; // Power off, writen 00: Clock to the card is stopped;
// D[7:0], CMD, and CK are driven high. // D[7:0], CMD, and CK are driven high.
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8)); regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
clock
} }
/// Initializes card (if present) and sets the bus at the /// Initializes card (if present) and sets the bus at the
@ -605,6 +600,19 @@ impl SdmmcInner {
// NOTE(unsafe) We have exclusive access to the peripheral // NOTE(unsafe) We have exclusive access to the peripheral
unsafe { unsafe {
// While the SD/SDIO card or eMMC is in identification mode,
// the SDMMC_CK frequency must be no more than 400 kHz.
let (clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
*clock = init_clock;
// CPSMACT and DPSMACT must be 0 to set WIDBUS
self.wait_idle();
regs.clkcr().modify(|w| {
w.set_widbus(0);
w.set_clkdiv(clkdiv);
});
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8)); regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
self.cmd(Cmd::idle(), false)?; self.cmd(Cmd::idle(), false)?;