aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb-synopsys-otg
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-11-23 00:23:40 +0100
committerDario Nieuwenhuis <[email protected]>2024-11-24 00:32:26 +0100
commit032af9d512140d8464680a444debc76f36222a31 (patch)
treeb72fb1e078bc047d7d36893048bddb09bf0b6493 /embassy-usb-synopsys-otg
parent4f459bb91846ed9d72a26c0b751e56cfb0098d21 (diff)
otg: fix corruption in CONTROL OUT transfers in stm32f4.
The RM says we have to process STUP (and therefore clear CNAK to start the data stage) in the DOEPINT STUP interrupt. Seems doing it in RXFLVL when we receive the data is too early. This makes it work consistently on all chips, so the quirk is no longer needed. Fixes #3493 Fixes #3459
Diffstat (limited to 'embassy-usb-synopsys-otg')
-rw-r--r--embassy-usb-synopsys-otg/src/lib.rs113
1 files changed, 50 insertions, 63 deletions
diff --git a/embassy-usb-synopsys-otg/src/lib.rs b/embassy-usb-synopsys-otg/src/lib.rs
index bd0ef04b0..615faa2fc 100644
--- a/embassy-usb-synopsys-otg/src/lib.rs
+++ b/embassy-usb-synopsys-otg/src/lib.rs
@@ -9,7 +9,7 @@ mod fmt;
9use core::cell::UnsafeCell; 9use core::cell::UnsafeCell;
10use core::future::poll_fn; 10use core::future::poll_fn;
11use core::marker::PhantomData; 11use core::marker::PhantomData;
12use core::sync::atomic::{AtomicBool, AtomicU16, Ordering}; 12use core::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering};
13use core::task::Poll; 13use core::task::Poll;
14 14
15use embassy_sync::waitqueue::AtomicWaker; 15use embassy_sync::waitqueue::AtomicWaker;
@@ -25,18 +25,17 @@ pub mod otg_v1;
25use otg_v1::{regs, vals, Otg}; 25use otg_v1::{regs, vals, Otg};
26 26
27/// Handle interrupts. 27/// Handle interrupts.
28pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>( 28pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>(r: Otg, state: &State<MAX_EP_COUNT>, ep_count: usize) {
29 r: Otg,
30 state: &State<MAX_EP_COUNT>,
31 ep_count: usize,
32 quirk_setup_late_cnak: bool,
33) {
34 trace!("irq"); 29 trace!("irq");
35 30
36 let ints = r.gintsts().read(); 31 let ints = r.gintsts().read();
37 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() { 32 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
38 // Mask interrupts and notify `Bus` to process them 33 // Mask interrupts and notify `Bus` to process them
39 r.gintmsk().write(|_| {}); 34 r.gintmsk().write(|w| {
35 w.set_iepint(true);
36 w.set_oepint(true);
37 w.set_rxflvlm(true);
38 });
40 state.bus_waker.wake(); 39 state.bus_waker.wake();
41 } 40 }
42 41
@@ -64,19 +63,9 @@ pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>(
64 while r.grstctl().read().txfflsh() {} 63 while r.grstctl().read().txfflsh() {}
65 } 64 }
66 65
67 if state.cp_state.setup_ready.load(Ordering::Relaxed) == false { 66 let data = &state.cp_state.setup_data;
68 // SAFETY: exclusive access ensured by atomic bool 67 data[0].store(r.fifo(0).read().data(), Ordering::Relaxed);
69 let data = unsafe { &mut *state.cp_state.setup_data.get() }; 68 data[1].store(r.fifo(0).read().data(), Ordering::Relaxed);
70 data[0..4].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
71 data[4..8].copy_from_slice(&r.fifo(0).read().0.to_ne_bytes());
72 state.cp_state.setup_ready.store(true, Ordering::Release);
73 state.ep_states[0].out_waker.wake();
74 } else {
75 error!("received SETUP before previous finished processing");
76 // discard FIFO
77 r.fifo(0).read();
78 r.fifo(0).read();
79 }
80 } 69 }
81 vals::Pktstsd::OUT_DATA_RX => { 70 vals::Pktstsd::OUT_DATA_RX => {
82 trace!("OUT_DATA_RX ep={} len={}", ep_num, len); 71 trace!("OUT_DATA_RX ep={} len={}", ep_num, len);
@@ -110,11 +99,6 @@ pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>(
110 } 99 }
111 vals::Pktstsd::SETUP_DATA_DONE => { 100 vals::Pktstsd::SETUP_DATA_DONE => {
112 trace!("SETUP_DATA_DONE ep={}", ep_num); 101 trace!("SETUP_DATA_DONE ep={}", ep_num);
113
114 if quirk_setup_late_cnak {
115 // Clear NAK to indicate we are ready to receive more data
116 r.doepctl(ep_num).modify(|w| w.set_cnak(true));
117 }
118 } 102 }
119 x => trace!("unknown PKTSTS: {}", x.to_bits()), 103 x => trace!("unknown PKTSTS: {}", x.to_bits()),
120 } 104 }
@@ -151,25 +135,30 @@ pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>(
151 } 135 }
152 } 136 }
153 137
154 // not needed? reception handled in rxflvl 138 // out endpoint interrupt
155 // OUT endpoint interrupt 139 if ints.oepint() {
156 // if ints.oepint() { 140 trace!("oepint");
157 // let mut ep_mask = r.daint().read().oepint(); 141 let mut ep_mask = r.daint().read().oepint();
158 // let mut ep_num = 0; 142 let mut ep_num = 0;
159 143
160 // while ep_mask != 0 { 144 // Iterate over endpoints while there are non-zero bits in the mask
161 // if ep_mask & 1 != 0 { 145 while ep_mask != 0 {
162 // let ep_ints = r.doepint(ep_num).read(); 146 if ep_mask & 1 != 0 {
163 // // clear all 147 let ep_ints = r.doepint(ep_num).read();
164 // r.doepint(ep_num).write_value(ep_ints); 148 // clear all
165 // state.ep_out_wakers[ep_num].wake(); 149 r.doepint(ep_num).write_value(ep_ints);
166 // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0); 150
167 // } 151 if ep_ints.stup() {
168 152 state.cp_state.setup_ready.store(true, Ordering::Release);
169 // ep_mask >>= 1; 153 }
170 // ep_num += 1; 154 state.ep_states[ep_num].out_waker.wake();
171 // } 155 trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
172 // } 156 }
157
158 ep_mask >>= 1;
159 ep_num += 1;
160 }
161 }
173} 162}
174 163
175/// USB PHY type 164/// USB PHY type
@@ -236,7 +225,7 @@ unsafe impl Sync for EpState {}
236 225
237struct ControlPipeSetupState { 226struct ControlPipeSetupState {
238 /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true. 227 /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true.
239 setup_data: UnsafeCell<[u8; 8]>, 228 setup_data: [AtomicU32; 2],
240 setup_ready: AtomicBool, 229 setup_ready: AtomicBool,
241} 230}
242 231
@@ -265,7 +254,7 @@ impl<const EP_COUNT: usize> State<EP_COUNT> {
265 254
266 Self { 255 Self {
267 cp_state: ControlPipeSetupState { 256 cp_state: ControlPipeSetupState {
268 setup_data: UnsafeCell::new([0u8; 8]), 257 setup_data: [const { AtomicU32::new(0) }; 2],
269 setup_ready: AtomicBool::new(false), 258 setup_ready: AtomicBool::new(false),
270 }, 259 },
271 ep_states: [NEW_EP_STATE; EP_COUNT], 260 ep_states: [NEW_EP_STATE; EP_COUNT],
@@ -480,7 +469,6 @@ impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d
480 trace!("start"); 469 trace!("start");
481 470
482 let regs = self.instance.regs; 471 let regs = self.instance.regs;
483 let quirk_setup_late_cnak = self.instance.quirk_setup_late_cnak;
484 let cp_setup_state = &self.instance.state.cp_state; 472 let cp_setup_state = &self.instance.state.cp_state;
485 ( 473 (
486 Bus { 474 Bus {
@@ -496,7 +484,6 @@ impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d
496 ep_out, 484 ep_out,
497 ep_in, 485 ep_in,
498 regs, 486 regs,
499 quirk_setup_late_cnak,
500 }, 487 },
501 ) 488 )
502 } 489 }
@@ -632,6 +619,11 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
632 w.set_xfrcm(true); 619 w.set_xfrcm(true);
633 }); 620 });
634 621
622 // Unmask SETUP received EP interrupt
623 r.doepmsk().write(|w| {
624 w.set_stupm(true);
625 });
626
635 // Unmask and clear core interrupts 627 // Unmask and clear core interrupts
636 self.restore_irqs(); 628 self.restore_irqs();
637 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); 629 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
@@ -743,7 +735,7 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
743 regs.doeptsiz(index).modify(|w| { 735 regs.doeptsiz(index).modify(|w| {
744 w.set_xfrsiz(ep.max_packet_size as _); 736 w.set_xfrsiz(ep.max_packet_size as _);
745 if index == 0 { 737 if index == 0 {
746 w.set_rxdpid_stupcnt(1); 738 w.set_rxdpid_stupcnt(3);
747 } else { 739 } else {
748 w.set_pktcnt(1); 740 w.set_pktcnt(1);
749 } 741 }
@@ -755,8 +747,7 @@ impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
755 // Enable IRQs for allocated endpoints 747 // Enable IRQs for allocated endpoints
756 regs.daintmsk().modify(|w| { 748 regs.daintmsk().modify(|w| {
757 w.set_iepm(ep_irq_mask(&self.ep_in)); 749 w.set_iepm(ep_irq_mask(&self.ep_in));
758 // OUT interrupts not used, handled in RXFLVL 750 w.set_oepm(ep_irq_mask(&self.ep_out));
759 // w.set_oepm(ep_irq_mask(&self.ep_out));
760 }); 751 });
761 } 752 }
762 753
@@ -1242,7 +1233,6 @@ pub struct ControlPipe<'d> {
1242 setup_state: &'d ControlPipeSetupState, 1233 setup_state: &'d ControlPipeSetupState,
1243 ep_in: Endpoint<'d, In>, 1234 ep_in: Endpoint<'d, In>,
1244 ep_out: Endpoint<'d, Out>, 1235 ep_out: Endpoint<'d, Out>,
1245 quirk_setup_late_cnak: bool,
1246} 1236}
1247 1237
1248impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> { 1238impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> {
@@ -1255,21 +1245,20 @@ impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> {
1255 self.ep_out.state.out_waker.register(cx.waker()); 1245 self.ep_out.state.out_waker.register(cx.waker());
1256 1246
1257 if self.setup_state.setup_ready.load(Ordering::Relaxed) { 1247 if self.setup_state.setup_ready.load(Ordering::Relaxed) {
1258 let data = unsafe { *self.setup_state.setup_data.get() }; 1248 let mut data = [0; 8];
1249 data[0..4].copy_from_slice(&self.setup_state.setup_data[0].load(Ordering::Relaxed).to_ne_bytes());
1250 data[4..8].copy_from_slice(&self.setup_state.setup_data[1].load(Ordering::Relaxed).to_ne_bytes());
1259 self.setup_state.setup_ready.store(false, Ordering::Release); 1251 self.setup_state.setup_ready.store(false, Ordering::Release);
1260 1252
1261 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section 1253 // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1262 // Receive 1 SETUP packet
1263 self.regs.doeptsiz(self.ep_out.info.addr.index()).modify(|w| { 1254 self.regs.doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
1264 w.set_rxdpid_stupcnt(1); 1255 w.set_rxdpid_stupcnt(3);
1265 }); 1256 });
1266 1257
1267 // Clear NAK to indicate we are ready to receive more data 1258 // Clear NAK to indicate we are ready to receive more data
1268 if !self.quirk_setup_late_cnak { 1259 self.regs
1269 self.regs 1260 .doepctl(self.ep_out.info.addr.index())
1270 .doepctl(self.ep_out.info.addr.index()) 1261 .modify(|w| w.set_cnak(true));
1271 .modify(|w| w.set_cnak(true));
1272 }
1273 1262
1274 trace!("SETUP received: {:?}", Bytes(&data)); 1263 trace!("SETUP received: {:?}", Bytes(&data));
1275 Poll::Ready(data) 1264 Poll::Ready(data)
@@ -1389,8 +1378,6 @@ pub struct OtgInstance<'d, const MAX_EP_COUNT: usize> {
1389 pub phy_type: PhyType, 1378 pub phy_type: PhyType,
1390 /// Extra RX FIFO words needed by some implementations. 1379 /// Extra RX FIFO words needed by some implementations.
1391 pub extra_rx_fifo_words: u16, 1380 pub extra_rx_fifo_words: u16,
1392 /// Whether to set up late cnak
1393 pub quirk_setup_late_cnak: bool,
1394 /// Function to calculate TRDT value based on some internal clock speed. 1381 /// Function to calculate TRDT value based on some internal clock speed.
1395 pub calculate_trdt_fn: fn(speed: vals::Dspd) -> u8, 1382 pub calculate_trdt_fn: fn(speed: vals::Dspd) -> u8,
1396} 1383}