stm32/dma: refactor.

This commit is contained in:
Dario Nieuwenhuis
2023-04-17 00:04:54 +02:00
parent 46227bec1e
commit 173c65b543
14 changed files with 1025 additions and 1092 deletions

View File

@ -185,6 +185,21 @@ fn clk_div(ker_ck: Hertz, sdmmc_ck: u32) -> Result<(bool, u16, Hertz), Error> {
}
}
#[cfg(sdmmc_v1)]
type Transfer<'a, C> = crate::dma::Transfer<'a, C>;
#[cfg(sdmmc_v2)]
type Transfer<'a, C> = core::marker::PhantomData<&'a mut C>;
#[cfg(all(sdmmc_v1, dma))]
const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
pburst: crate::dma::Burst::Incr4,
mburst: crate::dma::Burst::Incr4,
flow_ctrl: crate::dma::FlowControl::Peripheral,
fifo_threshold: Some(crate::dma::FifoThreshold::Full),
};
#[cfg(all(sdmmc_v1, not(dma)))]
const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {};
/// SDMMC configuration
///
/// Default values:
@ -490,7 +505,12 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
/// # Safety
///
/// `buffer` must be valid for the whole transfer and word aligned
unsafe fn prepare_datapath_read(&mut self, buffer: *mut [u32], length_bytes: u32, block_size: u8) {
fn prepare_datapath_read<'a>(
&'a mut self,
buffer: &'a mut [u32],
length_bytes: u32,
block_size: u8,
) -> Transfer<'a, Dma> {
assert!(block_size <= 14, "Block size up to 2^14 bytes");
let regs = T::regs();
@ -499,48 +519,52 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
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 request = self.dma.request();
self.dma.start_read(
request,
regs.fifor().ptr() as *const u32,
buffer,
crate::dma::TransferOptions {
pburst: crate::dma::Burst::Incr4,
mburst: crate::dma::Burst::Incr4,
flow_ctrl: crate::dma::FlowControl::Peripheral,
fifo_threshold: Some(crate::dma::FifoThreshold::Full),
..Default::default()
},
);
}
#[cfg(sdmmc_v2)]
{
regs.idmabase0r().write(|w| w.set_idmabase0(buffer as *mut u32 as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(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);
}
});
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));
core::marker::PhantomData
};
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
}
}
/// # Safety
///
/// `buffer` must be valid for the whole transfer and word aligned
unsafe fn prepare_datapath_write(&mut self, buffer: *const [u32], length_bytes: u32, block_size: u8) {
fn prepare_datapath_write<'a>(
&'a mut self,
buffer: &'a [u32],
length_bytes: u32,
block_size: u8,
) -> Transfer<'a, Dma> {
assert!(block_size <= 14, "Block size up to 2^14 bytes");
let regs = T::regs();
@ -549,43 +573,41 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
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 request = self.dma.request();
self.dma.start_write(
request,
buffer,
regs.fifor().ptr() as *mut u32,
crate::dma::TransferOptions {
pburst: crate::dma::Burst::Incr4,
mburst: crate::dma::Burst::Incr4,
flow_ctrl: crate::dma::FlowControl::Peripheral,
fifo_threshold: Some(crate::dma::FifoThreshold::Full),
..Default::default()
},
);
}
#[cfg(sdmmc_v2)]
{
regs.idmabase0r()
.write(|w| w.set_idmabase0(buffer as *const u32 as u32));
regs.idmactrlr().modify(|w| w.set_idmaen(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);
}
});
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));
core::marker::PhantomData
};
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
}
}
/// Stops the DMA datapath
@ -662,11 +684,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
unsafe {
self.prepare_datapath_read(&mut status, 64, 6);
Self::data_interrupts(true);
}
self.cmd(Cmd::cmd6(set_function), true)?; // CMD6
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
Self::data_interrupts(true);
Self::cmd(Cmd::cmd6(set_function), true)?; // CMD6
let res = poll_fn(|cx| {
T::state().register(cx.waker());
@ -696,6 +716,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Ok(_) => {
on_drop.defuse();
Self::stop_datapath();
drop(transfer);
// Function Selection of Function Group 1
let selection = (u32::from_be(status[4]) >> 24) & 0xF;
@ -718,7 +739,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let regs = T::regs();
let rca = card.rca;
self.cmd(Cmd::card_status(rca << 16), false)?; // CMD13
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() };
@ -730,8 +751,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let card = self.card.as_mut().ok_or(Error::NoCard)?;
let rca = card.rca;
self.cmd(Cmd::set_block_length(64), false)?; // CMD16
self.cmd(Cmd::app_cmd(rca << 16), false)?; // APP
Self::cmd(Cmd::set_block_length(64), false)?; // CMD16
Self::cmd(Cmd::app_cmd(rca << 16), false)?; // APP
let mut status = [0u32; 16];
@ -739,11 +760,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
unsafe {
self.prepare_datapath_read(&mut status, 64, 6);
Self::data_interrupts(true);
}
self.cmd(Cmd::card_status(0), true)?;
let transfer = self.prepare_datapath_read(&mut status, 64, 6);
Self::data_interrupts(true);
Self::cmd(Cmd::card_status(0), true)?;
let res = poll_fn(|cx| {
T::state().register(cx.waker());
@ -764,6 +783,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if res.is_ok() {
on_drop.defuse();
Self::stop_datapath();
drop(transfer);
for byte in status.iter_mut() {
*byte = u32::from_be(*byte);
@ -781,7 +801,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
// Determine Relative Card Address (RCA) of given card
let rca = card.map(|c| c.rca << 16).unwrap_or(0);
let r = self.cmd(Cmd::sel_desel_card(rca), false);
let r = Self::cmd(Cmd::sel_desel_card(rca), false);
match (r, rca) {
(Err(Error::Timeout), 0) => Ok(()),
_ => r,
@ -842,8 +862,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
async fn get_scr(&mut self, card: &mut Card) -> Result<(), Error> {
// Read the the 64-bit SCR register
self.cmd(Cmd::set_block_length(8), false)?; // CMD16
self.cmd(Cmd::app_cmd(card.rca << 16), false)?;
Self::cmd(Cmd::set_block_length(8), false)?; // CMD16
Self::cmd(Cmd::app_cmd(card.rca << 16), false)?;
let mut scr = [0u32; 2];
@ -851,11 +871,9 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
unsafe {
self.prepare_datapath_read(&mut scr[..], 8, 3);
Self::data_interrupts(true);
}
self.cmd(Cmd::cmd51(), true)?;
let transfer = self.prepare_datapath_read(&mut scr[..], 8, 3);
Self::data_interrupts(true);
Self::cmd(Cmd::cmd51(), true)?;
let res = poll_fn(|cx| {
T::state().register(cx.waker());
@ -876,6 +894,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if res.is_ok() {
on_drop.defuse();
Self::stop_datapath();
drop(transfer);
unsafe {
let scr_bytes = &*(&scr as *const [u32; 2] as *const [u8; 8]);
@ -887,7 +906,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
/// Send command to card
#[allow(unused_variables)]
fn cmd(&self, cmd: Cmd, data: bool) -> Result<(), Error> {
fn cmd(cmd: Cmd, data: bool) -> Result<(), Error> {
let regs = T::regs();
Self::clear_interrupt_flags();
@ -1005,10 +1024,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
});
regs.power().modify(|w| w.set_pwrctrl(PowerCtrl::On as u8));
self.cmd(Cmd::idle(), false)?;
Self::cmd(Cmd::idle(), false)?;
// Check if cards supports CMD8 (with pattern)
self.cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
Self::cmd(Cmd::hs_send_ext_csd(0x1AA), false)?;
let r1 = regs.respr(0).read().cardstatus();
let mut card = if r1 == 0x1AA {
@ -1020,14 +1039,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let ocr = loop {
// Signal that next command is a app command
self.cmd(Cmd::app_cmd(0), false)?; // CMD55
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;
// Initialize card
match self.cmd(Cmd::app_op_cmd(arg), false) {
match Self::cmd(Cmd::app_op_cmd(arg), false) {
// ACMD41
Ok(_) => (),
Err(Error::Crc) => (),
@ -1048,7 +1067,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
}
card.ocr = ocr;
self.cmd(Cmd::all_send_cid(), false)?; // CMD2
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;
@ -1056,10 +1075,10 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
let cid = (cid0 << 96) | (cid1 << 64) | (cid2 << 32) | (cid3);
card.cid = cid.into();
self.cmd(Cmd::send_rel_addr(), false)?;
Self::cmd(Cmd::send_rel_addr(), false)?;
card.rca = regs.respr(0).read().cardstatus() >> 16;
self.cmd(Cmd::send_csd(card.rca << 16), false)?;
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;
@ -1077,8 +1096,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
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)?;
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();
@ -1139,16 +1158,14 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
CardCapacity::SDSC => block_idx * 512,
_ => block_idx,
};
self.cmd(Cmd::set_block_length(512), false)?; // CMD16
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
unsafe {
self.prepare_datapath_read(buffer, 512, 9);
Self::data_interrupts(true);
}
self.cmd(Cmd::read_single_block(address), true)?;
let transfer = self.prepare_datapath_read(buffer, 512, 9);
Self::data_interrupts(true);
Self::cmd(Cmd::read_single_block(address), true)?;
let res = poll_fn(|cx| {
T::state().register(cx.waker());
@ -1169,6 +1186,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
if res.is_ok() {
on_drop.defuse();
Self::stop_datapath();
drop(transfer);
}
res
}
@ -1185,22 +1203,20 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
CardCapacity::SDSC => block_idx * 512,
_ => block_idx,
};
self.cmd(Cmd::set_block_length(512), false)?; // CMD16
Self::cmd(Cmd::set_block_length(512), false)?; // CMD16
let regs = T::regs();
let on_drop = OnDrop::new(|| unsafe { Self::on_drop() });
// sdmmc_v1 uses different cmd/dma order than v2, but only for writes
#[cfg(sdmmc_v1)]
self.cmd(Cmd::write_single_block(address), true)?;
Self::cmd(Cmd::write_single_block(address), true)?;
unsafe {
self.prepare_datapath_write(buffer as *const [u32; 128], 512, 9);
Self::data_interrupts(true);
}
let transfer = self.prepare_datapath_write(buffer, 512, 9);
Self::data_interrupts(true);
#[cfg(sdmmc_v2)]
self.cmd(Cmd::write_single_block(address), true)?;
Self::cmd(Cmd::write_single_block(address), true)?;
let res = poll_fn(|cx| {
T::state().register(cx.waker());
@ -1222,6 +1238,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Ok(_) => {
on_drop.defuse();
Self::stop_datapath();
drop(transfer);
// TODO: Make this configurable
let mut timeout: u32 = 0x00FF_FFFF;