Merge pull request #2823 from jamesmunns/james/usb-otg-errata

Add critical sections to avoid USB OTG Errata
This commit is contained in:
Dario Nieuwenhuis 2024-04-16 11:41:59 +00:00 committed by GitHub
commit ca139b9177
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -672,45 +672,51 @@ impl<'d, T: Instance> Bus<'d, T> {
let r = T::regs(); let r = T::regs();
// Configure RX fifo size. All endpoints share the same FIFO area. // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out); // handler COULD interrupt us here and do FIFO operations, so ensure
trace!("configuring rx fifo size={}", rx_fifo_size_words); // the interrupt does not occur.
critical_section::with(|_| {
// Configure RX fifo size. All endpoints share the same FIFO area.
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
trace!("configuring rx fifo size={}", rx_fifo_size_words);
r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words)); r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
// Configure TX (USB in direction) fifo size for each endpoint // Configure TX (USB in direction) fifo size for each endpoint
let mut fifo_top = rx_fifo_size_words; let mut fifo_top = rx_fifo_size_words;
for i in 0..T::ENDPOINT_COUNT { for i in 0..T::ENDPOINT_COUNT {
if let Some(ep) = self.ep_in[i] { if let Some(ep) = self.ep_in[i] {
trace!( trace!(
"configuring tx fifo ep={}, offset={}, size={}", "configuring tx fifo ep={}, offset={}, size={}",
i, i,
fifo_top, fifo_top,
ep.fifo_size_words ep.fifo_size_words
); );
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) }; let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
dieptxf.write(|w| { dieptxf.write(|w| {
w.set_fd(ep.fifo_size_words); w.set_fd(ep.fifo_size_words);
w.set_sa(fifo_top); w.set_sa(fifo_top);
}); });
fifo_top += ep.fifo_size_words; fifo_top += ep.fifo_size_words;
}
} }
}
assert!( assert!(
fifo_top <= T::FIFO_DEPTH_WORDS, fifo_top <= T::FIFO_DEPTH_WORDS,
"FIFO allocations exceeded maximum capacity" "FIFO allocations exceeded maximum capacity"
); );
// Flush fifos // Flush fifos
r.grstctl().write(|w| { r.grstctl().write(|w| {
w.set_rxfflsh(true); w.set_rxfflsh(true);
w.set_txfflsh(true); w.set_txfflsh(true);
w.set_txfnum(0x10); w.set_txfnum(0x10);
});
}); });
loop { loop {
let x = r.grstctl().read(); let x = r.grstctl().read();
if !x.rxfflsh() && !x.txfflsh() { if !x.rxfflsh() && !x.txfflsh() {
@ -1208,27 +1214,31 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
.await .await
} }
// Setup transfer size // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with
r.dieptsiz(index).write(|w| { // accesses to certain OTG_FS registers.
w.set_mcnt(1); //
w.set_pktcnt(1); // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs.
w.set_xfrsiz(buf.len() as _);
});
critical_section::with(|_| { critical_section::with(|_| {
// Setup transfer size
r.dieptsiz(index).write(|w| {
w.set_mcnt(1);
w.set_pktcnt(1);
w.set_xfrsiz(buf.len() as _);
});
// Enable endpoint // Enable endpoint
r.diepctl(index).modify(|w| { r.diepctl(index).modify(|w| {
w.set_cnak(true); w.set_cnak(true);
w.set_epena(true); w.set_epena(true);
}); });
});
// Write data to FIFO // Write data to FIFO
for chunk in buf.chunks(4) { for chunk in buf.chunks(4) {
let mut tmp = [0u8; 4]; let mut tmp = [0u8; 4];
tmp[0..chunk.len()].copy_from_slice(chunk); tmp[0..chunk.len()].copy_from_slice(chunk);
r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))); r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp)));
} }
});
trace!("write done ep={:?}", self.info.addr); trace!("write done ep={:?}", self.info.addr);