diff options
Diffstat (limited to 'embassy-usb-synopsys-otg')
| -rw-r--r-- | embassy-usb-synopsys-otg/src/lib.rs | 113 |
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; | |||
| 9 | use core::cell::UnsafeCell; | 9 | use core::cell::UnsafeCell; |
| 10 | use core::future::poll_fn; | 10 | use core::future::poll_fn; |
| 11 | use core::marker::PhantomData; | 11 | use core::marker::PhantomData; |
| 12 | use core::sync::atomic::{AtomicBool, AtomicU16, Ordering}; | 12 | use core::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering}; |
| 13 | use core::task::Poll; | 13 | use core::task::Poll; |
| 14 | 14 | ||
| 15 | use embassy_sync::waitqueue::AtomicWaker; | 15 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -25,18 +25,17 @@ pub mod otg_v1; | |||
| 25 | use otg_v1::{regs, vals, Otg}; | 25 | use otg_v1::{regs, vals, Otg}; |
| 26 | 26 | ||
| 27 | /// Handle interrupts. | 27 | /// Handle interrupts. |
| 28 | pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>( | 28 | pub 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 | ||
| 237 | struct ControlPipeSetupState { | 226 | struct 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 | ||
| 1248 | impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> { | 1238 | impl<'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 | } |
