stm32: update stm32-metapac.
This commit is contained in:
@ -28,17 +28,14 @@ pub struct InterruptHandler<T: Instance> {
|
||||
impl<T: Instance> InterruptHandler<T> {
|
||||
fn data_interrupts(enable: bool) {
|
||||
let regs = T::regs();
|
||||
// NOTE(unsafe) Atomic write
|
||||
unsafe {
|
||||
regs.maskr().write(|w| {
|
||||
w.set_dcrcfailie(enable);
|
||||
w.set_dtimeoutie(enable);
|
||||
w.set_dataendie(enable);
|
||||
regs.maskr().write(|w| {
|
||||
w.set_dcrcfailie(enable);
|
||||
w.set_dtimeoutie(enable);
|
||||
w.set_dataendie(enable);
|
||||
|
||||
#[cfg(sdmmc_v2)]
|
||||
w.set_dabortie(enable);
|
||||
});
|
||||
}
|
||||
#[cfg(sdmmc_v2)]
|
||||
w.set_dabortie(enable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +282,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
|
||||
) -> Self {
|
||||
into_ref!(clk, cmd, d0);
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
@ -322,7 +319,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
|
||||
) -> Self {
|
||||
into_ref!(clk, cmd, d0, d1, d2, d3);
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
@ -364,7 +361,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
|
||||
) -> Self {
|
||||
into_ref!(clk, cmd, d0);
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
@ -400,7 +397,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
|
||||
) -> Self {
|
||||
into_ref!(clk, cmd, d0, d1, d2, d3);
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
clk.set_as_af_pull(clk.af_num(), AFType::OutputPushPull, Pull::None);
|
||||
cmd.set_as_af_pull(cmd.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||
@ -451,26 +448,24 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
let regs = T::regs();
|
||||
unsafe {
|
||||
regs.clkcr().write(|w| {
|
||||
w.set_pwrsav(false);
|
||||
w.set_negedge(false);
|
||||
regs.clkcr().write(|w| {
|
||||
w.set_pwrsav(false);
|
||||
w.set_negedge(false);
|
||||
|
||||
// Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
|
||||
// See chip erratas for more details.
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_hwfc_en(false);
|
||||
#[cfg(sdmmc_v2)]
|
||||
w.set_hwfc_en(true);
|
||||
// Hardware flow control is broken on SDIOv1 and causes clock glitches, which result in CRC errors.
|
||||
// See chip erratas for more details.
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_hwfc_en(false);
|
||||
#[cfg(sdmmc_v2)]
|
||||
w.set_hwfc_en(true);
|
||||
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_clken(true);
|
||||
});
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_clken(true);
|
||||
});
|
||||
|
||||
// Power off, writen 00: Clock to the card is stopped;
|
||||
// D[7:0], CMD, and CK are driven high.
|
||||
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
|
||||
}
|
||||
// Power off, writen 00: Clock to the card is stopped;
|
||||
// D[7:0], CMD, and CK are driven high.
|
||||
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::Off as u8));
|
||||
|
||||
Self {
|
||||
_peri: sdmmc,
|
||||
@ -495,14 +490,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
fn data_active() -> bool {
|
||||
let regs = T::regs();
|
||||
|
||||
// NOTE(unsafe) Atomic read with no side-effects
|
||||
unsafe {
|
||||
let status = regs.star().read();
|
||||
#[cfg(sdmmc_v1)]
|
||||
return status.rxact() || status.txact();
|
||||
#[cfg(sdmmc_v2)]
|
||||
return status.dpsmact();
|
||||
}
|
||||
let status = regs.star().read();
|
||||
#[cfg(sdmmc_v1)]
|
||||
return status.rxact() || status.txact();
|
||||
#[cfg(sdmmc_v2)]
|
||||
return status.dpsmact();
|
||||
}
|
||||
|
||||
/// Coammand transfer is in progress
|
||||
@ -510,14 +502,11 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
fn cmd_active() -> bool {
|
||||
let regs = T::regs();
|
||||
|
||||
// NOTE(unsafe) Atomic read with no side-effects
|
||||
unsafe {
|
||||
let status = regs.star().read();
|
||||
#[cfg(sdmmc_v1)]
|
||||
return status.cmdact();
|
||||
#[cfg(sdmmc_v2)]
|
||||
return status.cpsmact();
|
||||
}
|
||||
let status = regs.star().read();
|
||||
#[cfg(sdmmc_v1)]
|
||||
return status.cmdact();
|
||||
#[cfg(sdmmc_v2)]
|
||||
return status.cpsmact();
|
||||
}
|
||||
|
||||
/// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
|
||||
@ -542,44 +531,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Self::wait_idle();
|
||||
Self::clear_interrupt_flags();
|
||||
|
||||
// NOTE(unsafe) We have exclusive access to the regisers
|
||||
unsafe {
|
||||
regs.dtimer()
|
||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||
regs.dtimer()
|
||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||
|
||||
#[cfg(sdmmc_v1)]
|
||||
let transfer = unsafe {
|
||||
let request = self.dma.request();
|
||||
Transfer::new_read(
|
||||
&mut self.dma,
|
||||
request,
|
||||
regs.fifor().as_ptr() as *mut u32,
|
||||
buffer,
|
||||
DMA_TRANSFER_OPTIONS,
|
||||
)
|
||||
};
|
||||
#[cfg(sdmmc_v2)]
|
||||
let transfer = {
|
||||
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
|
||||
regs.idmactrlr().modify(|w| w.set_idmaen(true));
|
||||
Transfer {
|
||||
_dummy: core::marker::PhantomData,
|
||||
}
|
||||
};
|
||||
|
||||
regs.dctrl().modify(|w| {
|
||||
w.set_dblocksize(block_size);
|
||||
w.set_dtdir(true);
|
||||
#[cfg(sdmmc_v1)]
|
||||
let transfer = {
|
||||
let request = self.dma.request();
|
||||
Transfer::new_read(
|
||||
&mut self.dma,
|
||||
request,
|
||||
regs.fifor().ptr() as *mut u32,
|
||||
buffer,
|
||||
DMA_TRANSFER_OPTIONS,
|
||||
)
|
||||
};
|
||||
#[cfg(sdmmc_v2)]
|
||||
let transfer = {
|
||||
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_mut_ptr() as u32));
|
||||
regs.idmactrlr().modify(|w| w.set_idmaen(true));
|
||||
Transfer {
|
||||
_dummy: core::marker::PhantomData,
|
||||
}
|
||||
};
|
||||
{
|
||||
w.set_dmaen(true);
|
||||
w.set_dten(true);
|
||||
}
|
||||
});
|
||||
|
||||
regs.dctrl().modify(|w| {
|
||||
w.set_dblocksize(block_size);
|
||||
w.set_dtdir(true);
|
||||
#[cfg(sdmmc_v1)]
|
||||
{
|
||||
w.set_dmaen(true);
|
||||
w.set_dten(true);
|
||||
}
|
||||
});
|
||||
|
||||
transfer
|
||||
}
|
||||
transfer
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
@ -598,59 +584,54 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Self::wait_idle();
|
||||
Self::clear_interrupt_flags();
|
||||
|
||||
// NOTE(unsafe) We have exclusive access to the regisers
|
||||
unsafe {
|
||||
regs.dtimer()
|
||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||
regs.dtimer()
|
||||
.write(|w| w.set_datatime(self.config.data_transfer_timeout));
|
||||
regs.dlenr().write(|w| w.set_datalength(length_bytes));
|
||||
|
||||
#[cfg(sdmmc_v1)]
|
||||
let transfer = unsafe {
|
||||
let request = self.dma.request();
|
||||
Transfer::new_write(
|
||||
&mut self.dma,
|
||||
request,
|
||||
buffer,
|
||||
regs.fifor().as_ptr() as *mut u32,
|
||||
DMA_TRANSFER_OPTIONS,
|
||||
)
|
||||
};
|
||||
#[cfg(sdmmc_v2)]
|
||||
let transfer = {
|
||||
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
|
||||
regs.idmactrlr().modify(|w| w.set_idmaen(true));
|
||||
Transfer {
|
||||
_dummy: core::marker::PhantomData,
|
||||
}
|
||||
};
|
||||
|
||||
regs.dctrl().modify(|w| {
|
||||
w.set_dblocksize(block_size);
|
||||
w.set_dtdir(false);
|
||||
#[cfg(sdmmc_v1)]
|
||||
let transfer = {
|
||||
let request = self.dma.request();
|
||||
Transfer::new_write(
|
||||
&mut self.dma,
|
||||
request,
|
||||
buffer,
|
||||
regs.fifor().ptr() as *mut u32,
|
||||
DMA_TRANSFER_OPTIONS,
|
||||
)
|
||||
};
|
||||
#[cfg(sdmmc_v2)]
|
||||
let transfer = {
|
||||
regs.idmabase0r().write(|w| w.set_idmabase0(buffer.as_ptr() as u32));
|
||||
regs.idmactrlr().modify(|w| w.set_idmaen(true));
|
||||
Transfer {
|
||||
_dummy: core::marker::PhantomData,
|
||||
}
|
||||
};
|
||||
{
|
||||
w.set_dmaen(true);
|
||||
w.set_dten(true);
|
||||
}
|
||||
});
|
||||
|
||||
regs.dctrl().modify(|w| {
|
||||
w.set_dblocksize(block_size);
|
||||
w.set_dtdir(false);
|
||||
#[cfg(sdmmc_v1)]
|
||||
{
|
||||
w.set_dmaen(true);
|
||||
w.set_dten(true);
|
||||
}
|
||||
});
|
||||
|
||||
transfer
|
||||
}
|
||||
transfer
|
||||
}
|
||||
|
||||
/// Stops the DMA datapath
|
||||
fn stop_datapath() {
|
||||
let regs = T::regs();
|
||||
|
||||
unsafe {
|
||||
#[cfg(sdmmc_v1)]
|
||||
regs.dctrl().modify(|w| {
|
||||
w.set_dmaen(false);
|
||||
w.set_dten(false);
|
||||
});
|
||||
#[cfg(sdmmc_v2)]
|
||||
regs.idmactrlr().modify(|w| w.set_idmaen(false));
|
||||
}
|
||||
#[cfg(sdmmc_v1)]
|
||||
regs.dctrl().modify(|w| {
|
||||
w.set_dmaen(false);
|
||||
w.set_dten(false);
|
||||
});
|
||||
#[cfg(sdmmc_v2)]
|
||||
regs.idmactrlr().modify(|w| w.set_idmaen(false));
|
||||
}
|
||||
|
||||
/// Sets the CLKDIV field in CLKCR. Updates clock field in self
|
||||
@ -673,16 +654,13 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
assert!(ker_ck.0 > 3 * sdmmc_bus_bandwidth / 32);
|
||||
self.clock = new_clock;
|
||||
|
||||
// NOTE(unsafe) We have exclusive access to the regblock
|
||||
unsafe {
|
||||
// CPSMACT and DPSMACT must be 0 to set CLKDIV
|
||||
Self::wait_idle();
|
||||
regs.clkcr().modify(|w| {
|
||||
w.set_clkdiv(clkdiv);
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_bypass(_bypass);
|
||||
});
|
||||
}
|
||||
// CPSMACT and DPSMACT must be 0 to set CLKDIV
|
||||
Self::wait_idle();
|
||||
regs.clkcr().modify(|w| {
|
||||
w.set_clkdiv(clkdiv);
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_bypass(_bypass);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -710,7 +688,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
@ -718,7 +696,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
let res = poll_fn(|cx| {
|
||||
T::state().register(cx.waker());
|
||||
let status = unsafe { regs.star().read() };
|
||||
let status = regs.star().read();
|
||||
|
||||
if status.dcrcfail() {
|
||||
return Poll::Ready(Err(Error::Crc));
|
||||
@ -769,8 +747,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
Self::cmd(Cmd::card_status(rca << 16), false)?; // CMD13
|
||||
|
||||
// NOTE(unsafe) Atomic read with no side-effects
|
||||
let r1 = unsafe { regs.respr(0).read().cardstatus() };
|
||||
let r1 = regs.respr(0).read().cardstatus();
|
||||
Ok(r1.into())
|
||||
}
|
||||
|
||||
@ -786,7 +763,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
@ -794,7 +771,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
let res = poll_fn(|cx| {
|
||||
T::state().register(cx.waker());
|
||||
let status = unsafe { regs.star().read() };
|
||||
let status = regs.star().read();
|
||||
|
||||
if status.dcrcfail() {
|
||||
return Poll::Ready(Err(Error::Crc));
|
||||
@ -840,35 +817,32 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
#[inline(always)]
|
||||
fn clear_interrupt_flags() {
|
||||
let regs = T::regs();
|
||||
// NOTE(unsafe) Atomic write
|
||||
unsafe {
|
||||
regs.icr().write(|w| {
|
||||
w.set_ccrcfailc(true);
|
||||
w.set_dcrcfailc(true);
|
||||
w.set_ctimeoutc(true);
|
||||
w.set_dtimeoutc(true);
|
||||
w.set_txunderrc(true);
|
||||
w.set_rxoverrc(true);
|
||||
w.set_cmdrendc(true);
|
||||
w.set_cmdsentc(true);
|
||||
w.set_dataendc(true);
|
||||
w.set_dbckendc(true);
|
||||
w.set_sdioitc(true);
|
||||
regs.icr().write(|w| {
|
||||
w.set_ccrcfailc(true);
|
||||
w.set_dcrcfailc(true);
|
||||
w.set_ctimeoutc(true);
|
||||
w.set_dtimeoutc(true);
|
||||
w.set_txunderrc(true);
|
||||
w.set_rxoverrc(true);
|
||||
w.set_cmdrendc(true);
|
||||
w.set_cmdsentc(true);
|
||||
w.set_dataendc(true);
|
||||
w.set_dbckendc(true);
|
||||
w.set_sdioitc(true);
|
||||
|
||||
#[cfg(sdmmc_v2)]
|
||||
{
|
||||
w.set_dholdc(true);
|
||||
w.set_dabortc(true);
|
||||
w.set_busyd0endc(true);
|
||||
w.set_ackfailc(true);
|
||||
w.set_acktimeoutc(true);
|
||||
w.set_vswendc(true);
|
||||
w.set_ckstopc(true);
|
||||
w.set_idmatec(true);
|
||||
w.set_idmabtcc(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
#[cfg(sdmmc_v2)]
|
||||
{
|
||||
w.set_dholdc(true);
|
||||
w.set_dabortc(true);
|
||||
w.set_busyd0endc(true);
|
||||
w.set_ackfailc(true);
|
||||
w.set_acktimeoutc(true);
|
||||
w.set_vswendc(true);
|
||||
w.set_ckstopc(true);
|
||||
w.set_idmatec(true);
|
||||
w.set_idmabtcc(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
|
||||
@ -880,7 +854,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
// Arm `OnDrop` after the buffer, so it will be dropped first
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
@ -888,7 +862,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
let res = poll_fn(|cx| {
|
||||
T::state().register(cx.waker());
|
||||
let status = unsafe { regs.star().read() };
|
||||
let status = regs.star().read();
|
||||
|
||||
if status.dcrcfail() {
|
||||
return Poll::Ready(Err(Error::Crc));
|
||||
@ -921,59 +895,53 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
let regs = T::regs();
|
||||
|
||||
Self::clear_interrupt_flags();
|
||||
// NOTE(safety) Atomic operations
|
||||
unsafe {
|
||||
// CP state machine must be idle
|
||||
while Self::cmd_active() {}
|
||||
// CP state machine must be idle
|
||||
while Self::cmd_active() {}
|
||||
|
||||
// Command arg
|
||||
regs.argr().write(|w| w.set_cmdarg(cmd.arg));
|
||||
// Command arg
|
||||
regs.argr().write(|w| w.set_cmdarg(cmd.arg));
|
||||
|
||||
// Command index and start CP State Machine
|
||||
regs.cmdr().write(|w| {
|
||||
w.set_waitint(false);
|
||||
w.set_waitresp(cmd.resp as u8);
|
||||
w.set_cmdindex(cmd.cmd);
|
||||
w.set_cpsmen(true);
|
||||
// Command index and start CP State Machine
|
||||
regs.cmdr().write(|w| {
|
||||
w.set_waitint(false);
|
||||
w.set_waitresp(cmd.resp as u8);
|
||||
w.set_cmdindex(cmd.cmd);
|
||||
w.set_cpsmen(true);
|
||||
|
||||
#[cfg(sdmmc_v2)]
|
||||
{
|
||||
// Special mode in CP State Machine
|
||||
// CMD12: Stop Transmission
|
||||
let cpsm_stop_transmission = cmd.cmd == 12;
|
||||
w.set_cmdstop(cpsm_stop_transmission);
|
||||
w.set_cmdtrans(data);
|
||||
}
|
||||
});
|
||||
|
||||
let mut status;
|
||||
if cmd.resp == Response::None {
|
||||
// Wait for CMDSENT or a timeout
|
||||
while {
|
||||
status = regs.star().read();
|
||||
!(status.ctimeout() || status.cmdsent())
|
||||
} {}
|
||||
} else {
|
||||
// Wait for CMDREND or CCRCFAIL or a timeout
|
||||
while {
|
||||
status = regs.star().read();
|
||||
!(status.ctimeout() || status.cmdrend() || status.ccrcfail())
|
||||
} {}
|
||||
#[cfg(sdmmc_v2)]
|
||||
{
|
||||
// Special mode in CP State Machine
|
||||
// CMD12: Stop Transmission
|
||||
let cpsm_stop_transmission = cmd.cmd == 12;
|
||||
w.set_cmdstop(cpsm_stop_transmission);
|
||||
w.set_cmdtrans(data);
|
||||
}
|
||||
});
|
||||
|
||||
if status.ctimeout() {
|
||||
return Err(Error::Timeout);
|
||||
} else if status.ccrcfail() {
|
||||
return Err(Error::Crc);
|
||||
}
|
||||
Ok(())
|
||||
let mut status;
|
||||
if cmd.resp == Response::None {
|
||||
// Wait for CMDSENT or a timeout
|
||||
while {
|
||||
status = regs.star().read();
|
||||
!(status.ctimeout() || status.cmdsent())
|
||||
} {}
|
||||
} else {
|
||||
// Wait for CMDREND or CCRCFAIL or a timeout
|
||||
while {
|
||||
status = regs.star().read();
|
||||
!(status.ctimeout() || status.cmdrend() || status.ccrcfail())
|
||||
} {}
|
||||
}
|
||||
|
||||
if status.ctimeout() {
|
||||
return Err(Error::Timeout);
|
||||
} else if status.ccrcfail() {
|
||||
return Err(Error::Crc);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Ensure that `regs` has exclusive access to the regblocks
|
||||
unsafe fn on_drop() {
|
||||
fn on_drop() {
|
||||
let regs = T::regs();
|
||||
if Self::data_active() {
|
||||
Self::clear_interrupt_flags();
|
||||
@ -1017,141 +985,138 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
false => BusWidth::One,
|
||||
};
|
||||
|
||||
// NOTE(unsafe) We have exclusive access to the peripheral
|
||||
unsafe {
|
||||
// While the SD/SDIO card or eMMC is in identification mode,
|
||||
// the SDMMC_CK frequency must be no more than 400 kHz.
|
||||
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
|
||||
self.clock = init_clock;
|
||||
// While the SD/SDIO card or eMMC is in identification mode,
|
||||
// the SDMMC_CK frequency must be no more than 400 kHz.
|
||||
let (_bypass, clkdiv, init_clock) = unwrap!(clk_div(ker_ck, SD_INIT_FREQ.0));
|
||||
self.clock = init_clock;
|
||||
|
||||
// CPSMACT and DPSMACT must be 0 to set WIDBUS
|
||||
Self::wait_idle();
|
||||
// CPSMACT and DPSMACT must be 0 to set WIDBUS
|
||||
Self::wait_idle();
|
||||
|
||||
regs.clkcr().modify(|w| {
|
||||
w.set_widbus(0);
|
||||
w.set_clkdiv(clkdiv);
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_bypass(_bypass);
|
||||
});
|
||||
regs.clkcr().modify(|w| {
|
||||
w.set_widbus(0);
|
||||
w.set_clkdiv(clkdiv);
|
||||
#[cfg(sdmmc_v1)]
|
||||
w.set_bypass(_bypass);
|
||||
});
|
||||
|
||||
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
|
||||
Self::cmd(Cmd::idle(), false)?;
|
||||
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
|
||||
Self::cmd(Cmd::idle(), false)?;
|
||||
|
||||
// Check if cards supports CMD8 (with pattern)
|
||||
Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
|
||||
let r1 = regs.respr(0).read().cardstatus();
|
||||
// Check if cards supports CMD8 (with pattern)
|
||||
Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
|
||||
let r1 = regs.respr(0).read().cardstatus();
|
||||
|
||||
let mut card = if r1 == 0x1AA {
|
||||
// Card echoed back the pattern. Must be at least v2
|
||||
Card::default()
|
||||
} else {
|
||||
return Err(Error::UnsupportedCardVersion);
|
||||
};
|
||||
let mut card = if r1 == 0x1AA {
|
||||
// Card echoed back the pattern. Must be at least v2
|
||||
Card::default()
|
||||
} else {
|
||||
return Err(Error::UnsupportedCardVersion);
|
||||
};
|
||||
|
||||
let ocr = loop {
|
||||
// Signal that next command is a app command
|
||||
Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
|
||||
let ocr = loop {
|
||||
// Signal that next command is a app command
|
||||
Self::cmd(Cmd::app_cmd(0), false)?; // CMD55
|
||||
|
||||
let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
|
||||
| CmdAppOper::HIGH_CAPACITY as u32
|
||||
| CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
|
||||
let arg = CmdAppOper::VOLTAGE_WINDOW_SD as u32
|
||||
| CmdAppOper::HIGH_CAPACITY as u32
|
||||
| CmdAppOper::SD_SWITCH_1_8V_CAPACITY as u32;
|
||||
|
||||
// Initialize card
|
||||
match Self::cmd(Cmd::app_op_cmd(arg), false) {
|
||||
// ACMD41
|
||||
Ok(_) => (),
|
||||
Err(Error::Crc) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
let ocr: OCR = regs.respr(0).read().cardstatus().into();
|
||||
if !ocr.is_busy() {
|
||||
// Power up done
|
||||
break ocr;
|
||||
}
|
||||
};
|
||||
|
||||
if ocr.high_capacity() {
|
||||
// Card is SDHC or SDXC or SDUC
|
||||
card.card_type = CardCapacity::SDHC;
|
||||
} else {
|
||||
card.card_type = CardCapacity::SDSC;
|
||||
// Initialize card
|
||||
match Self::cmd(Cmd::app_op_cmd(arg), false) {
|
||||
// ACMD41
|
||||
Ok(_) => (),
|
||||
Err(Error::Crc) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
card.ocr = ocr;
|
||||
|
||||
Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
|
||||
let cid0 = regs.respr(0).read().cardstatus() as u128;
|
||||
let cid1 = regs.respr(1).read().cardstatus() as u128;
|
||||
let cid2 = regs.respr(2).read().cardstatus() as u128;
|
||||
let cid3 = regs.respr(3).read().cardstatus() as u128;
|
||||
let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
|
||||
card.cid = cid.into();
|
||||
|
||||
Self::cmd(Cmd::send_rel_addr(), false)?;
|
||||
card.rca = regs.respr(0).read().cardstatus() >> 16;
|
||||
|
||||
Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
|
||||
let csd0 = regs.respr(0).read().cardstatus() as u128;
|
||||
let csd1 = regs.respr(1).read().cardstatus() as u128;
|
||||
let csd2 = regs.respr(2).read().cardstatus() as u128;
|
||||
let csd3 = regs.respr(3).read().cardstatus() as u128;
|
||||
let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
|
||||
card.csd = csd.into();
|
||||
|
||||
self.select_card(Some(&card))?;
|
||||
|
||||
self.get_scr(&mut card).await?;
|
||||
|
||||
// Set bus width
|
||||
let (width, acmd_arg) = match bus_width {
|
||||
BusWidth::Eight => unimplemented!(),
|
||||
BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
|
||||
_ => (BusWidth::One, 0),
|
||||
};
|
||||
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
|
||||
Self::cmd(Cmd::cmd6(acmd_arg), false)?;
|
||||
|
||||
// CPSMACT and DPSMACT must be 0 to set WIDBUS
|
||||
Self::wait_idle();
|
||||
|
||||
regs.clkcr().modify(|w| {
|
||||
w.set_widbus(match width {
|
||||
BusWidth::One => 0,
|
||||
BusWidth::Four => 1,
|
||||
BusWidth::Eight => 2,
|
||||
_ => panic!("Invalid Bus Width"),
|
||||
})
|
||||
});
|
||||
|
||||
// Set Clock
|
||||
if freq.0 <= 25_000_000 {
|
||||
// Final clock frequency
|
||||
self.clkcr_set_clkdiv(freq.0, width)?;
|
||||
} else {
|
||||
// Switch to max clock for SDR12
|
||||
self.clkcr_set_clkdiv(25_000_000, width)?;
|
||||
let ocr: OCR = regs.respr(0).read().cardstatus().into();
|
||||
if !ocr.is_busy() {
|
||||
// Power up done
|
||||
break ocr;
|
||||
}
|
||||
};
|
||||
|
||||
self.card = Some(card);
|
||||
|
||||
// Read status
|
||||
self.read_sd_status().await?;
|
||||
|
||||
if freq.0 > 25_000_000 {
|
||||
// Switch to SDR25
|
||||
self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
|
||||
|
||||
if self.signalling == Signalling::SDR25 {
|
||||
// Set final clock frequency
|
||||
self.clkcr_set_clkdiv(freq.0, width)?;
|
||||
|
||||
if self.read_status(&card)?.state() != CurrentState::Transfer {
|
||||
return Err(Error::SignalingSwitchFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Read status after signalling change
|
||||
self.read_sd_status().await?;
|
||||
if ocr.high_capacity() {
|
||||
// Card is SDHC or SDXC or SDUC
|
||||
card.card_type = CardCapacity::SDHC;
|
||||
} else {
|
||||
card.card_type = CardCapacity::SDSC;
|
||||
}
|
||||
card.ocr = ocr;
|
||||
|
||||
Self::cmd(Cmd::all_send_cid(), false)?; // CMD2
|
||||
let cid0 = regs.respr(0).read().cardstatus() as u128;
|
||||
let cid1 = regs.respr(1).read().cardstatus() as u128;
|
||||
let cid2 = regs.respr(2).read().cardstatus() as u128;
|
||||
let cid3 = regs.respr(3).read().cardstatus() as u128;
|
||||
let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
|
||||
card.cid = cid.into();
|
||||
|
||||
Self::cmd(Cmd::send_rel_addr(), false)?;
|
||||
card.rca = regs.respr(0).read().cardstatus() >> 16;
|
||||
|
||||
Self::cmd(Cmd::send_csd(card.rca << 16), false)?;
|
||||
let csd0 = regs.respr(0).read().cardstatus() as u128;
|
||||
let csd1 = regs.respr(1).read().cardstatus() as u128;
|
||||
let csd2 = regs.respr(2).read().cardstatus() as u128;
|
||||
let csd3 = regs.respr(3).read().cardstatus() as u128;
|
||||
let csd = (csd0 << 96) | (csd1 << 64) | (csd2 << 32) | (csd3);
|
||||
card.csd = csd.into();
|
||||
|
||||
self.select_card(Some(&card))?;
|
||||
|
||||
self.get_scr(&mut card).await?;
|
||||
|
||||
// Set bus width
|
||||
let (width, acmd_arg) = match bus_width {
|
||||
BusWidth::Eight => unimplemented!(),
|
||||
BusWidth::Four if card.scr.bus_width_four() => (BusWidth::Four, 2),
|
||||
_ => (BusWidth::One, 0),
|
||||
};
|
||||
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
|
||||
Self::cmd(Cmd::cmd6(acmd_arg), false)?;
|
||||
|
||||
// CPSMACT and DPSMACT must be 0 to set WIDBUS
|
||||
Self::wait_idle();
|
||||
|
||||
regs.clkcr().modify(|w| {
|
||||
w.set_widbus(match width {
|
||||
BusWidth::One => 0,
|
||||
BusWidth::Four => 1,
|
||||
BusWidth::Eight => 2,
|
||||
_ => panic!("Invalid Bus Width"),
|
||||
})
|
||||
});
|
||||
|
||||
// Set Clock
|
||||
if freq.0 <= 25_000_000 {
|
||||
// Final clock frequency
|
||||
self.clkcr_set_clkdiv(freq.0, width)?;
|
||||
} else {
|
||||
// Switch to max clock for SDR12
|
||||
self.clkcr_set_clkdiv(25_000_000, width)?;
|
||||
}
|
||||
|
||||
self.card = Some(card);
|
||||
|
||||
// Read status
|
||||
self.read_sd_status().await?;
|
||||
|
||||
if freq.0 > 25_000_000 {
|
||||
// Switch to SDR25
|
||||
self.signalling = self.switch_signalling_mode(Signalling::SDR25).await?;
|
||||
|
||||
if self.signalling == Signalling::SDR25 {
|
||||
// Set final clock frequency
|
||||
self.clkcr_set_clkdiv(freq.0, width)?;
|
||||
|
||||
if self.read_status(&card)?.state() != CurrentState::Transfer {
|
||||
return Err(Error::SignalingSwitchFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Read status after signalling change
|
||||
self.read_sd_status().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1172,7 +1137,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
|
||||
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
let transfer = self.prepare_datapath_read(buffer, 512, 9);
|
||||
InterruptHandler::<T>::data_interrupts(true);
|
||||
@ -1180,7 +1145,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
let res = poll_fn(|cx| {
|
||||
T::state().register(cx.waker());
|
||||
let status = unsafe { regs.star().read() };
|
||||
let status = regs.star().read();
|
||||
|
||||
if status.dcrcfail() {
|
||||
return Poll::Ready(Err(Error::Crc));
|
||||
@ -1217,7 +1182,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
|
||||
|
||||
let regs = T::regs();
|
||||
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
|
||||
let on_drop = OnDrop::new(|| Self::on_drop());
|
||||
|
||||
// sdmmc_v1 uses different cmd/dma order than v2, but only for writes
|
||||
#[cfg(sdmmc_v1)]
|
||||
@ -1231,7 +1196,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
|
||||
let res = poll_fn(|cx| {
|
||||
T::state().register(cx.waker());
|
||||
let status = unsafe { regs.star().read() };
|
||||
let status = regs.star().read();
|
||||
|
||||
if status.dcrcfail() {
|
||||
return Poll::Ready(Err(Error::Crc));
|
||||
@ -1289,9 +1254,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Drop for Sdmmc<'d, T, Dma> {
|
||||
fn drop(&mut self) {
|
||||
T::Interrupt::disable();
|
||||
unsafe { Self::on_drop() };
|
||||
Self::on_drop();
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
self.clk.set_as_disconnected();
|
||||
self.cmd.set_as_disconnected();
|
||||
self.d0.set_as_disconnected();
|
||||
|
Reference in New Issue
Block a user