Skip to main content

embassy_usb_synopsys_otg/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
4#![doc = include_str!("../README.md")]
5#![warn(missing_docs)]
6
7// This must go FIRST so that all the other modules see its macros.
8mod fmt;
9
10use core::cell::UnsafeCell;
11use core::future::poll_fn;
12use core::marker::PhantomData;
13use core::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering};
14use core::task::Poll;
15
16use embassy_sync::waitqueue::AtomicWaker;
17use embassy_usb_driver::{
18    Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut,
19    EndpointType, Event, Unsupported,
20};
21
22use crate::fmt::Bytes;
23
24pub mod otg_v1;
25
26#[cfg(feature = "host")]
27pub mod host;
28
29use otg_v1::{Otg, regs, vals};
30
31/// Handle interrupts.
32pub unsafe fn on_interrupt(r: Otg, state: &State<'_>) {
33    trace!("irq");
34    let ep_count = state.endpoint_count();
35
36    let ints = r.gintsts().read();
37    if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
38        // Mask interrupts and notify `Bus` to process them
39        r.gintmsk().write(|w| {
40            w.set_iepint(true);
41            w.set_oepint(true);
42            w.set_rxflvlm(true);
43        });
44        state.bus_waker.wake();
45    }
46
47    // Handle RX
48    while r.gintsts().read().rxflvl() {
49        let status = r.grxstsp().read();
50        trace!("=== status {:08x}", status.0);
51        let ep_num = status.epnum() as usize;
52        let len = status.bcnt() as usize;
53
54        assert!(ep_num < ep_count);
55
56        match status.pktstsd() {
57            vals::Pktstsd::SETUP_DATA_RX => {
58                trace!("SETUP_DATA_RX");
59                assert!(len == 8, "invalid SETUP packet length={}", len);
60                assert!(ep_num == 0, "invalid SETUP packet endpoint={}", ep_num);
61
62                // flushing TX if something stuck in control endpoint
63                if r.dieptsiz(ep_num).read().pktcnt() != 0 {
64                    r.grstctl().modify(|w| {
65                        w.set_txfnum(ep_num as _);
66                        w.set_txfflsh(true);
67                    });
68                    while r.grstctl().read().txfflsh() {}
69                }
70
71                let data = &state.cp_state.setup_data;
72                data[0].store(r.fifo(0).read().data(), Ordering::Relaxed);
73                data[1].store(r.fifo(0).read().data(), Ordering::Relaxed);
74            }
75            vals::Pktstsd::OUT_DATA_RX => {
76                trace!("OUT_DATA_RX ep={} len={}", ep_num, len);
77
78                if state.ep_states[ep_num].out_size.load(Ordering::Acquire) == EP_OUT_BUFFER_EMPTY {
79                    // SAFETY: Buffer size is allocated to be equal to endpoint's maximum packet size
80                    // We trust the peripheral to not exceed its configured MPSIZ
81                    let buf =
82                        unsafe { core::slice::from_raw_parts_mut(*state.ep_states[ep_num].out_buffer.get(), len) };
83
84                    let mut chunks = buf.chunks_exact_mut(4);
85                    for chunk in &mut chunks {
86                        // RX FIFO is shared so always read from fifo(0)
87                        let data = r.fifo(0).read().0;
88                        chunk.copy_from_slice(&data.to_ne_bytes());
89                    }
90                    let rem = chunks.into_remainder();
91                    if !rem.is_empty() {
92                        let data = r.fifo(0).read().0;
93                        rem.copy_from_slice(&data.to_ne_bytes()[0..rem.len()]);
94                    }
95
96                    state.ep_states[ep_num].out_size.store(len as u16, Ordering::Release);
97                    state.ep_states[ep_num].out_waker.wake();
98                } else {
99                    error!("ep_out buffer overflow index={}", ep_num);
100
101                    // discard FIFO data
102                    let len_words = (len + 3) / 4;
103                    for _ in 0..len_words {
104                        r.fifo(0).read().data();
105                    }
106                }
107            }
108            vals::Pktstsd::OUT_DATA_DONE => {
109                trace!("OUT_DATA_DONE ep={}", ep_num);
110            }
111            vals::Pktstsd::SETUP_DATA_DONE => {
112                trace!("SETUP_DATA_DONE ep={}", ep_num);
113            }
114            x => trace!("unknown PKTSTS: {}", x.to_bits()),
115        }
116    }
117
118    // IN endpoint interrupt
119    if ints.iepint() {
120        let mut ep_mask = r.daint().read().iepint();
121        let mut ep_num = 0;
122
123        // Iterate over endpoints while there are non-zero bits in the mask
124        while ep_mask != 0 {
125            if ep_mask & 1 != 0 {
126                let ep_ints = r.diepint(ep_num).read();
127
128                // clear all
129                r.diepint(ep_num).write_value(ep_ints);
130
131                // TXFE is cleared in DIEPEMPMSK
132                if ep_ints.txfe() {
133                    critical_section::with(|_| {
134                        r.diepempmsk().modify(|w| {
135                            w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
136                        });
137                    });
138                }
139
140                state.ep_states[ep_num].in_waker.wake();
141                trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
142            }
143
144            ep_mask >>= 1;
145            ep_num += 1;
146        }
147    }
148
149    // out endpoint interrupt
150    if ints.oepint() {
151        trace!("oepint");
152        let mut ep_mask = r.daint().read().oepint();
153        let mut ep_num = 0;
154
155        // Iterate over endpoints while there are non-zero bits in the mask
156        while ep_mask != 0 {
157            if ep_mask & 1 != 0 {
158                let ep_ints = r.doepint(ep_num).read();
159                // clear all
160                r.doepint(ep_num).write_value(ep_ints);
161
162                if ep_ints.stup() {
163                    state.cp_state.setup_ready.store(true, Ordering::Release);
164                }
165                state.ep_states[ep_num].out_waker.wake();
166                trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
167            }
168
169            ep_mask >>= 1;
170            ep_num += 1;
171        }
172    }
173
174    if ints.eopf() {
175        let frame_number = r.dsts().read().fnsof();
176        let frame_is_odd = frame_number & 0x01 == 1;
177
178        // If an isochronous endpoint has an IN message waiting in its FIFO, but the host didn't poll for it before eof,
179        // switch the packet polarity, in the hope that it will be polled for in the next frame.
180        for ep_num in (0..ep_count).into_iter().filter(|ep_num| {
181            let diepctl = r.diepctl(*ep_num).read();
182            // Find iso endpoints
183            diepctl.eptyp() == vals::Eptyp::ISOCHRONOUS
184                // That have and unsent IN message
185                && diepctl.epena()
186                // Where the frame polarity matches the current frame
187                && diepctl.eonum_dpid() == frame_is_odd
188        }) {
189            trace!("Unsent message at EOF for ep: {}, frame: {}", ep_num, frame_number);
190
191            let ep_diepctl = r.diepctl(ep_num);
192            let ep_diepint = r.diepint(ep_num);
193
194            // Set NAK
195            ep_diepctl.modify(|m| m.set_snak(true));
196            while !ep_diepint.read().inepne() {}
197
198            // Disable the endpoint
199            ep_diepctl.modify(|m| {
200                m.set_snak(true);
201                m.set_epdis(true);
202            });
203            while !ep_diepint.read().epdisd() {}
204            ep_diepint.modify(|m| m.set_epdisd(true));
205
206            // Switch the packet polarity
207            ep_diepctl.modify(|r| {
208                if frame_is_odd {
209                    r.set_sd0pid_sevnfrm(true);
210                } else {
211                    r.set_soddfrm_sd1pid(true);
212                }
213            });
214
215            // Enable the endpoint again
216            ep_diepctl.modify(|w| {
217                w.set_cnak(true);
218                w.set_epena(true);
219            });
220        }
221    }
222}
223
224/// USB PHY type
225#[derive(Copy, Clone, Debug, Eq, PartialEq)]
226pub enum PhyType {
227    /// Internal Full-Speed PHY
228    ///
229    /// Available on most High-Speed peripherals.
230    InternalFullSpeed,
231    /// Internal High-Speed PHY
232    ///
233    /// Available on a few STM32 chips.
234    InternalHighSpeed,
235    /// External ULPI Full-Speed PHY (or High-Speed PHY in Full-Speed mode)
236    ExternalFullSpeed,
237    /// External ULPI High-Speed PHY
238    ExternalHighSpeed,
239}
240
241impl PhyType {
242    /// Get whether this PHY is any of the internal types.
243    pub fn internal(&self) -> bool {
244        match self {
245            PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
246            PhyType::ExternalHighSpeed | PhyType::ExternalFullSpeed => false,
247        }
248    }
249
250    /// Get whether this PHY is any of the high-speed types.
251    pub fn high_speed(&self) -> bool {
252        match self {
253            PhyType::InternalFullSpeed | PhyType::ExternalFullSpeed => false,
254            PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true,
255        }
256    }
257
258    fn to_dspd(&self) -> vals::Dspd {
259        match self {
260            PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
261            PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
262            PhyType::ExternalFullSpeed => vals::Dspd::FULL_SPEED_EXTERNAL,
263            PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED,
264        }
265    }
266}
267
268/// Indicates that [State::ep_out_buffers] is empty.
269const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
270
271struct EpState {
272    in_waker: AtomicWaker,
273    out_waker: AtomicWaker,
274    /// RX FIFO is shared so extra buffers are needed to dequeue all data without waiting on each endpoint.
275    /// Buffers are ready when associated [State::ep_out_size] != [EP_OUT_BUFFER_EMPTY].
276    out_buffer: UnsafeCell<*mut u8>,
277    out_size: AtomicU16,
278    // Written once during endpoint allocation (before Driver::start), read-only afterward.
279    in_alloc: UnsafeCell<Option<EndpointData>>,
280    out_alloc: UnsafeCell<Option<EndpointData>>,
281}
282
283// SAFETY: `out_buffer` access is synchronized via `out_size`. `in_alloc`/`out_alloc` are written
284// only during endpoint allocation before the USB stack starts; afterward they are read-only.
285unsafe impl Send for EpState {}
286unsafe impl Sync for EpState {}
287
288struct ControlPipeSetupState {
289    /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true.
290    setup_data: [AtomicU32; 2],
291    setup_ready: AtomicBool,
292}
293
294#[derive(Debug, Clone, Copy)]
295struct EndpointData {
296    ep_type: EndpointType,
297    max_packet_size: u16,
298    fifo_size_words: u16,
299}
300
301/// Type-erased borrow of [`State`] passed to [`OtgInstance`], [`Driver`](crate::Driver), [`Bus`](crate::Bus),
302/// and [`on_interrupt`].
303///
304/// Build from [`State::as_state`].
305#[derive(Clone, Copy)]
306pub struct State<'d> {
307    cp_state: &'d ControlPipeSetupState,
308    ep_states: &'d [EpState],
309    bus_waker: &'d AtomicWaker,
310}
311
312impl State<'_> {
313    /// Returns the number of device endpoints supported by this state.
314    pub fn endpoint_count(&self) -> usize {
315        self.ep_states.len()
316    }
317}
318
319impl<'d> State<'d> {
320    pub(crate) fn ep_alloc_get(&self, dir: Direction, index: usize) -> Option<&EndpointData> {
321        unsafe {
322            match dir {
323                Direction::In => (*self.ep_states[index].in_alloc.get()).as_ref(),
324                Direction::Out => (*self.ep_states[index].out_alloc.get()).as_ref(),
325            }
326        }
327    }
328
329    pub(crate) fn ep_fifo_size_in(&self) -> u16 {
330        (0..self.endpoint_count())
331            .filter_map(|i| self.ep_alloc_get(Direction::In, i))
332            .map(|ep| ep.fifo_size_words)
333            .sum()
334    }
335
336    pub(crate) fn ep_fifo_size_out(&self) -> u16 {
337        (0..self.endpoint_count())
338            .filter_map(|i| self.ep_alloc_get(Direction::Out, i))
339            .map(|ep| ep.fifo_size_words)
340            .sum()
341    }
342
343    pub(crate) fn ep_irq_mask_in(&self) -> u16 {
344        (0..self.endpoint_count()).fold(0, |mask, i| {
345            if self.ep_alloc_get(Direction::In, i).is_some() {
346                mask | (1 << i)
347            } else {
348                mask
349            }
350        })
351    }
352
353    pub(crate) fn ep_irq_mask_out(&self) -> u16 {
354        (0..self.endpoint_count()).fold(0, |mask, i| {
355            if self.ep_alloc_get(Direction::Out, i).is_some() {
356                mask | (1 << i)
357            } else {
358                mask
359            }
360        })
361    }
362
363    /// # Safety
364    ///
365    /// Call only from [`Driver::alloc_endpoint`](crate::Driver::alloc_endpoint) before [`embassy_usb_driver::Driver::start`].
366    pub(crate) unsafe fn alloc_slot_write(&self, dir: Direction, index: usize, data: EndpointData) {
367        match dir {
368            Direction::In => *self.ep_states[index].in_alloc.get() = Some(data),
369            Direction::Out => *self.ep_states[index].out_alloc.get() = Some(data),
370        }
371    }
372}
373
374/// Storage object for USB OTG driver state.
375pub struct StateStorage<const EP_COUNT: usize> {
376    cp_state: ControlPipeSetupState,
377    ep_states: [EpState; EP_COUNT],
378    bus_waker: AtomicWaker,
379}
380
381impl<const EP_COUNT: usize> StateStorage<EP_COUNT> {
382    /// Create a new StateStorage.
383    pub const fn new() -> Self {
384        Self {
385            cp_state: ControlPipeSetupState {
386                setup_data: [const { AtomicU32::new(0) }; 2],
387                setup_ready: AtomicBool::new(false),
388            },
389            ep_states: [const {
390                EpState {
391                    in_waker: AtomicWaker::new(),
392                    out_waker: AtomicWaker::new(),
393                    out_buffer: UnsafeCell::new(0 as _),
394                    out_size: AtomicU16::new(EP_OUT_BUFFER_EMPTY),
395                    in_alloc: UnsafeCell::new(None),
396                    out_alloc: UnsafeCell::new(None),
397                }
398            }; EP_COUNT],
399            bus_waker: AtomicWaker::new(),
400        }
401    }
402
403    /// Borrow this [`StateStorage`] as a [`State`] for [`OtgInstance`] and the Synopsys [`Driver`](crate::Driver).
404    pub fn as_state(&self) -> State<'_> {
405        State {
406            cp_state: &self.cp_state,
407            ep_states: self.ep_states.as_slice(),
408            bus_waker: &self.bus_waker,
409        }
410    }
411}
412
413/// USB driver config.
414#[non_exhaustive]
415#[derive(Clone, Copy, PartialEq, Eq, Debug)]
416pub struct Config {
417    /// Enable VBUS detection.
418    ///
419    /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
420    /// This is done by checking whether there is 5V on the VBUS pin or not.
421    ///
422    /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
423    /// (If there's no power in VBUS your device would be off anyway, so it's fine to always assume
424    /// there's power in VBUS, i.e. the USB cable is always plugged in.)
425    ///
426    /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
427    /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
428    ///
429    /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
430    /// voltage divider. See ST application note AN4879 and the reference manual for more details.
431    pub vbus_detection: bool,
432
433    /// Enable transceiver delay.
434    ///
435    /// Some ULPI PHYs like the Microchip USB334x series require a delay between the ULPI register write that initiates
436    /// the HS Chirp and the subsequent transmit command, otherwise the HS Chirp does not get executed and the deivce
437    /// enumerates in FS mode. Some USB Link IP like those in the STM32H7 series support adding this delay to work with
438    /// the affected PHYs.
439    pub xcvrdly: bool,
440}
441
442impl Default for Config {
443    fn default() -> Self {
444        Self {
445            vbus_detection: false,
446            xcvrdly: false,
447        }
448    }
449}
450
451/// USB OTG driver.
452pub struct Driver<'d> {
453    config: Config,
454    ep_out_buffer: &'d mut [u8],
455    ep_out_buffer_offset: usize,
456    instance: OtgInstance<'d>,
457}
458
459impl<'d> Driver<'d> {
460    /// Initializes the USB OTG peripheral.
461    ///
462    /// # Arguments
463    ///
464    /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
465    /// Must be large enough to fit all OUT endpoint max packet sizes.
466    /// Endpoint allocation will fail if it is too small.
467    /// * `instance` - The USB OTG peripheral instance and its configuration.
468    /// * `config` - The USB driver configuration.
469    pub fn new(ep_out_buffer: &'d mut [u8], instance: OtgInstance<'d>, config: Config) -> Self {
470        Self {
471            config,
472            ep_out_buffer,
473            ep_out_buffer_offset: 0,
474            instance,
475        }
476    }
477
478    /// Returns the total amount of words (u32) allocated in dedicated FIFO.
479    fn allocated_fifo_words(&self) -> u16 {
480        let st = self.instance.state;
481        self.instance.extra_rx_fifo_words + st.ep_fifo_size_out() + st.ep_fifo_size_in()
482    }
483
484    /// Creates an [`Endpoint`] with the given parameters.
485    fn alloc_endpoint<D: Dir>(
486        &mut self,
487        ep_type: EndpointType,
488        ep_addr: Option<EndpointAddress>,
489        max_packet_size: u16,
490        interval_ms: u8,
491    ) -> Result<Endpoint<'d, D>, EndpointAllocError> {
492        trace!(
493            "allocating type={:?} mps={:?} interval_ms={}, dir={:?}",
494            ep_type,
495            max_packet_size,
496            interval_ms,
497            D::dir()
498        );
499
500        if D::dir() == Direction::Out {
501            if self.ep_out_buffer_offset + max_packet_size as usize > self.ep_out_buffer.len() {
502                error!("Not enough endpoint out buffer capacity");
503                return Err(EndpointAllocError);
504            }
505        };
506
507        let fifo_size_words = match D::dir() {
508            Direction::Out => (max_packet_size + 3) / 4,
509            // INEPTXFD requires minimum size of 16 words
510            Direction::In => u16::max((max_packet_size + 3) / 4, 16),
511        };
512
513        if fifo_size_words + self.allocated_fifo_words() > self.instance.fifo_depth_words {
514            error!("Not enough FIFO capacity");
515            return Err(EndpointAllocError);
516        }
517
518        let dir = D::dir();
519        let st = self.instance.state;
520        let endpoint_count = st.endpoint_count();
521
522        // Find endpoint slot
523        let index = if let Some(addr) = ep_addr {
524            // Use the specified endpoint address
525            let requested_index = addr.index();
526            if requested_index >= endpoint_count {
527                return Err(EndpointAllocError);
528            }
529            if requested_index == 0 && ep_type != EndpointType::Control {
530                return Err(EndpointAllocError); // EP0 is reserved for control
531            }
532            if st.ep_alloc_get(dir, requested_index).is_some() {
533                return Err(EndpointAllocError); // Already allocated
534            }
535            requested_index
536        } else {
537            // Find any free endpoint slot
538            let found = (0..endpoint_count).find(|&i| {
539                if i == 0 && ep_type != EndpointType::Control {
540                    // reserved for control pipe
541                    false
542                } else {
543                    st.ep_alloc_get(dir, i).is_none()
544                }
545            });
546            match found {
547                Some(i) => i,
548                None => {
549                    error!("No free endpoints available");
550                    return Err(EndpointAllocError);
551                }
552            }
553        };
554
555        unsafe {
556            st.alloc_slot_write(
557                dir,
558                index,
559                EndpointData {
560                    ep_type,
561                    max_packet_size,
562                    fifo_size_words,
563                },
564            );
565        };
566
567        trace!("  index={}", index);
568
569        let ep_state = &self.instance.state.ep_states[index];
570        if D::dir() == Direction::Out {
571            // Buffer capacity check was done above, now allocation cannot fail
572            unsafe {
573                *ep_state.out_buffer.get() = self.ep_out_buffer.as_mut_ptr().offset(self.ep_out_buffer_offset as _);
574            }
575            self.ep_out_buffer_offset += max_packet_size as usize;
576        }
577
578        Ok(Endpoint {
579            _phantom: PhantomData,
580            regs: self.instance.regs,
581            state: ep_state,
582            info: EndpointInfo {
583                addr: EndpointAddress::from_parts(index, D::dir()),
584                ep_type,
585                max_packet_size,
586                interval_ms,
587            },
588        })
589    }
590}
591
592impl<'d> embassy_usb_driver::Driver<'d> for Driver<'d> {
593    type EndpointOut = Endpoint<'d, Out>;
594    type EndpointIn = Endpoint<'d, In>;
595    type ControlPipe = ControlPipe<'d>;
596    type Bus = Bus<'d>;
597
598    fn alloc_endpoint_in(
599        &mut self,
600        ep_type: EndpointType,
601        ep_addr: Option<EndpointAddress>,
602        max_packet_size: u16,
603        interval_ms: u8,
604    ) -> Result<Self::EndpointIn, EndpointAllocError> {
605        self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
606    }
607
608    fn alloc_endpoint_out(
609        &mut self,
610        ep_type: EndpointType,
611        ep_addr: Option<EndpointAddress>,
612        max_packet_size: u16,
613        interval_ms: u8,
614    ) -> Result<Self::EndpointOut, EndpointAllocError> {
615        self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
616    }
617
618    fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
619        let ep_out = self
620            .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
621            .unwrap();
622        let ep_in = self
623            .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
624            .unwrap();
625        assert_eq!(ep_out.info.addr.index(), 0);
626        assert_eq!(ep_in.info.addr.index(), 0);
627
628        trace!("start");
629
630        let regs = self.instance.regs;
631        let setup_state = self.instance.state.cp_state;
632        (
633            Bus {
634                config: self.config,
635                inited: false,
636                instance: self.instance,
637            },
638            ControlPipe {
639                max_packet_size: control_max_packet_size,
640                setup_state,
641                ep_out,
642                ep_in,
643                regs,
644            },
645        )
646    }
647}
648
649/// USB bus.
650pub struct Bus<'d> {
651    config: Config,
652    instance: OtgInstance<'d>,
653    inited: bool,
654}
655
656impl<'d> Bus<'d> {
657    fn restore_irqs(&mut self) {
658        self.instance.regs.gintmsk().write(|w| {
659            w.set_usbrst(true);
660            w.set_enumdnem(true);
661            w.set_usbsuspm(true);
662            w.set_wuim(true);
663            w.set_iepint(true);
664            w.set_oepint(true);
665            w.set_rxflvlm(true);
666            w.set_srqim(true);
667            w.set_otgint(true);
668        });
669    }
670
671    /// Returns the PHY type.
672    pub fn phy_type(&self) -> PhyType {
673        self.instance.phy_type
674    }
675
676    /// Applies a DWC2 core soft reset.
677    pub fn core_soft_reset(&mut self) {
678        let r = self.instance.regs;
679
680        // Wait for AHB idle
681        while !r.grstctl().read().ahbidl() {}
682
683        r.grstctl().write(|w| {
684            w.set_csrst(true);
685        });
686
687        // Wait until the reset done
688        loop {
689            let grstctl = r.grstctl().read();
690            if !grstctl.csrst() || grstctl.csrstdone() {
691                break;
692            }
693        }
694
695        // On synchronous-reset cores, CSRSTDONE is W1C. Preserve it in the writeback so it gets cleared.
696        r.grstctl().modify(|w| {
697            w.set_csrst(false);
698        });
699    }
700
701    /// Configures the PHY as a device.
702    pub fn configure_as_device(&mut self) {
703        let r = self.instance.regs;
704        let phy_type = self.instance.phy_type;
705
706        // Read PHY data width from GHWCFG4:
707        // 0 = 8-bit only, 1 = 16-bit only, 2 = software selectable (default to 8-bit)
708        let hw_width = r.hwcfg4().read().utmi_phy_data_width();
709        r.gusbcfg().write(|w| {
710            // Force device mode
711            w.set_fdmod(true);
712
713            match phy_type {
714                PhyType::InternalFullSpeed => {
715                    // Select embedded FS PHY
716                    w.set_physel(true);
717                    w.set_ulpi_utmi_sel(false);
718                    w.set_phyif(false);
719                }
720                PhyType::InternalHighSpeed => {
721                    // Select UTMI+ PHY, determine data width from hardware
722                    w.set_physel(false);
723                    w.set_ulpi_utmi_sel(false);
724                    w.set_phyif(hw_width == 1);
725                    // Disable ULPI-specific settings
726                    w.set_ulpievbusd(false);
727                    w.set_ulpievbusi(false);
728                    w.set_ulpifsls(false);
729                    w.set_ulpicsm(false);
730                }
731                PhyType::ExternalFullSpeed | PhyType::ExternalHighSpeed => {
732                    // Select ULPI external PHY, single data rate
733                    w.set_physel(false);
734                    w.set_ulpi_utmi_sel(true);
735                    w.set_phyif(false);
736                    w.set_ddr_sel(false);
737                    // Disable external VBUS source
738                    w.set_ulpievbusd(false);
739                    w.set_ulpievbusi(false);
740                    // Disable ULPI FS/LS mode
741                    w.set_ulpifsls(false);
742                    w.set_ulpicsm(false);
743                }
744            }
745        });
746
747        // Wait for device mode ready
748        while r.gintsts().read().cmod() {}
749    }
750
751    /// Applies configuration specific to
752    /// Core ID 0x0000_1100 and 0x0000_1200
753    pub fn config_v1(&mut self) {
754        let r = self.instance.regs;
755        let phy_type = self.instance.phy_type;
756        assert!(phy_type != PhyType::InternalHighSpeed);
757
758        r.gccfg_v1().modify(|w| {
759            // Enable internal full-speed PHY, logic is inverted
760            w.set_pwrdwn(phy_type.internal());
761        });
762
763        // F429-like chips have the GCCFG.NOVBUSSENS bit
764        r.gccfg_v1().modify(|w| {
765            w.set_novbussens(!self.config.vbus_detection);
766            w.set_vbusasen(false);
767            w.set_vbusbsen(self.config.vbus_detection);
768            w.set_sofouten(false);
769        });
770    }
771
772    /// Applies configuration specific to
773    /// Core ID 0x0000_2000, 0x0000_2100, 0x0000_2300, 0x0000_3000 and 0x0000_3100
774    pub fn config_v2v3(&mut self) {
775        let r = self.instance.regs;
776        let phy_type = self.instance.phy_type;
777
778        // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
779        r.gccfg_v2().modify(|w| {
780            // Enable internal full-speed PHY, logic is inverted
781            w.set_pwrdwn(phy_type.internal() && !phy_type.high_speed());
782            w.set_phyhsen(phy_type.internal() && phy_type.high_speed());
783        });
784
785        r.gccfg_v2().modify(|w| {
786            w.set_vbden(self.config.vbus_detection);
787        });
788
789        // Force B-peripheral session
790        r.gotgctl().modify(|w| {
791            w.set_bvaloen(!self.config.vbus_detection);
792            w.set_bvaloval(true);
793        });
794    }
795
796    /// Applies configuration specific to
797    /// Core ID 0x0000_5000
798    pub fn config_v5(&mut self) {
799        let r = self.instance.regs;
800        let phy_type = self.instance.phy_type;
801
802        if phy_type == PhyType::InternalHighSpeed {
803            r.gccfg_v3().modify(|w| {
804                w.set_vbvaloven(!self.config.vbus_detection);
805                w.set_vbvaloval(!self.config.vbus_detection);
806                w.set_vbden(self.config.vbus_detection);
807            });
808        } else {
809            r.gotgctl().modify(|w| {
810                w.set_bvaloen(!self.config.vbus_detection);
811                w.set_bvaloval(!self.config.vbus_detection);
812            });
813            r.gccfg_v3().modify(|w| {
814                w.set_vbden(self.config.vbus_detection);
815            });
816        }
817    }
818
819    fn init(&mut self) {
820        let r = self.instance.regs;
821        let phy_type = self.instance.phy_type;
822
823        // Soft disconnect.
824        r.dctl().write(|w| w.set_sdis(true));
825
826        // Set speed.
827        r.dcfg().write(|w| {
828            w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
829            w.set_dspd(phy_type.to_dspd());
830            if self.config.xcvrdly {
831                w.set_xcvrdly(true);
832            }
833        });
834
835        // Unmask transfer complete EP interrupt
836        r.diepmsk().write(|w| {
837            w.set_xfrcm(true);
838        });
839
840        // Unmask SETUP received EP interrupt
841        r.doepmsk().write(|w| {
842            w.set_stupm(true);
843        });
844
845        // Unmask and clear core interrupts
846        self.restore_irqs();
847        r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
848
849        // Unmask global interrupt
850        r.gahbcfg().write(|w| {
851            w.set_gint(true); // unmask global interrupt
852        });
853
854        // Connect
855        r.dctl().write(|w| w.set_sdis(false));
856    }
857
858    fn init_fifo(&mut self) {
859        trace!("init_fifo");
860
861        let regs = self.instance.regs;
862        // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt
863        // handler COULD interrupt us here and do FIFO operations, so ensure
864        // the interrupt does not occur.
865        critical_section::with(|_| {
866            // Configure RX fifo size. All endpoints share the same FIFO area.
867            let st = self.instance.state;
868            let rx_fifo_size_words = self.instance.extra_rx_fifo_words + st.ep_fifo_size_out();
869            trace!("configuring rx fifo size={}", rx_fifo_size_words);
870
871            regs.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
872
873            // Configure TX (USB in direction) fifo size for each endpoint
874            let mut fifo_top = rx_fifo_size_words;
875            for i in 0..st.endpoint_count() {
876                if let Some(ep) = st.ep_alloc_get(Direction::In, i) {
877                    trace!(
878                        "configuring tx fifo ep={}, offset={}, size={}",
879                        i, fifo_top, ep.fifo_size_words
880                    );
881
882                    let dieptxf = if i == 0 { regs.dieptxf0() } else { regs.dieptxf(i - 1) };
883
884                    dieptxf.write(|w| {
885                        w.set_fd(ep.fifo_size_words);
886                        w.set_sa(fifo_top);
887                    });
888
889                    fifo_top += ep.fifo_size_words;
890                }
891            }
892
893            assert!(
894                fifo_top <= self.instance.fifo_depth_words,
895                "FIFO allocations exceeded maximum capacity"
896            );
897
898            // Flush fifos, separately
899            regs.grstctl().write(|w| {
900                w.set_txfflsh(true);
901                w.set_txfnum(0x10);
902            });
903            while regs.grstctl().read().txfflsh() {}
904            regs.grstctl().write(|w| {
905                w.set_rxfflsh(true);
906            });
907            while regs.grstctl().read().rxfflsh() {}
908        });
909    }
910
911    fn configure_endpoints(&mut self) {
912        trace!("configure_endpoints");
913
914        let regs = self.instance.regs;
915        let st = self.instance.state;
916
917        // Configure IN endpoints
918        for index in 0..st.endpoint_count() {
919            if let Some(ep) = st.ep_alloc_get(Direction::In, index) {
920                critical_section::with(|_| {
921                    regs.diepctl(index).write(|w| {
922                        if index == 0 {
923                            w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
924                        } else {
925                            w.set_mpsiz(ep.max_packet_size);
926                            w.set_eptyp(to_eptyp(ep.ep_type));
927                            w.set_sd0pid_sevnfrm(true);
928                            w.set_txfnum(index as _);
929                            w.set_snak(true);
930                        }
931                    });
932                });
933            }
934        }
935
936        // Configure OUT endpoints
937        for index in 0..st.endpoint_count() {
938            if let Some(ep) = st.ep_alloc_get(Direction::Out, index) {
939                critical_section::with(|_| {
940                    regs.doepctl(index).write(|w| {
941                        if index == 0 {
942                            w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
943                        } else {
944                            w.set_mpsiz(ep.max_packet_size);
945                            w.set_eptyp(to_eptyp(ep.ep_type));
946                            w.set_sd0pid_sevnfrm(true);
947                        }
948                    });
949
950                    regs.doeptsiz(index).modify(|w| {
951                        w.set_xfrsiz(ep.max_packet_size as _);
952                        if index == 0 {
953                            w.set_rxdpid_stupcnt(3);
954                        } else {
955                            w.set_pktcnt(1);
956                        }
957                    });
958
959                    if index == 0 {
960                        regs.doepctl(index).modify(|w| {
961                            w.set_epena(true);
962                            w.set_cnak(true);
963                        });
964                    }
965                });
966            }
967        }
968
969        // Enable IRQs for allocated endpoints
970        regs.daintmsk().modify(|w| {
971            w.set_iepm(st.ep_irq_mask_in());
972            w.set_oepm(st.ep_irq_mask_out());
973        });
974    }
975
976    fn disable_all_endpoints(&mut self) {
977        let st = self.instance.state;
978        for i in 0..st.endpoint_count() {
979            self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
980            self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
981        }
982    }
983
984    /// Initialize the device core once before polling for events.
985    pub fn init_device(&mut self) {
986        if !self.inited {
987            self.init();
988            self.inited = true;
989        }
990    }
991
992    /// Deinitialize the device
993    pub fn deinit_device(&mut self) {
994        if self.inited {
995            self.inited = false;
996        }
997    }
998}
999
1000impl<'d> embassy_usb_driver::Bus for Bus<'d> {
1001    async fn poll(&mut self) -> Event {
1002        poll_fn(move |cx| {
1003            if !self.inited {
1004                self.init_device();
1005                // If no vbus detection, just return a single PowerDetected event at startup.
1006                if !self.config.vbus_detection {
1007                    return Poll::Ready(Event::PowerDetected);
1008                }
1009            }
1010
1011            let regs = self.instance.regs;
1012            self.instance.state.bus_waker.register(cx.waker());
1013
1014            let ints = regs.gintsts().read();
1015
1016            if ints.srqint() {
1017                trace!("vbus detected");
1018
1019                regs.gintsts().write(|w| w.set_srqint(true)); // clear
1020                self.restore_irqs();
1021
1022                if self.config.vbus_detection {
1023                    return Poll::Ready(Event::PowerDetected);
1024                }
1025            }
1026
1027            if ints.otgint() {
1028                let otgints = regs.gotgint().read();
1029                regs.gotgint().write_value(otgints); // clear all
1030                self.restore_irqs();
1031
1032                if otgints.sedet() {
1033                    trace!("vbus removed");
1034                    if self.config.vbus_detection {
1035                        self.disable_all_endpoints();
1036                        return Poll::Ready(Event::PowerRemoved);
1037                    }
1038                }
1039            }
1040
1041            if ints.usbrst() {
1042                trace!("reset");
1043
1044                self.init_fifo();
1045                self.configure_endpoints();
1046
1047                // Reset address
1048                critical_section::with(|_| {
1049                    regs.dcfg().modify(|w| {
1050                        w.set_dad(0);
1051                    });
1052                });
1053
1054                regs.gintsts().write(|w| w.set_usbrst(true)); // clear
1055                self.restore_irqs();
1056            }
1057
1058            if ints.enumdne() {
1059                trace!("enumdne");
1060
1061                let speed = regs.dsts().read().enumspd();
1062                let trdt = (self.instance.calculate_trdt_fn)(speed);
1063                trace!("  speed={} trdt={}", speed.to_bits(), trdt);
1064                regs.gusbcfg().modify(|w| w.set_trdt(trdt));
1065
1066                regs.gintsts().write(|w| w.set_enumdne(true)); // clear
1067                self.restore_irqs();
1068
1069                return Poll::Ready(Event::Reset);
1070            }
1071
1072            if ints.usbsusp() {
1073                trace!("suspend");
1074                regs.gintsts().write(|w| w.set_usbsusp(true)); // clear
1075                self.restore_irqs();
1076                return Poll::Ready(Event::Suspend);
1077            }
1078
1079            if ints.wkupint() {
1080                trace!("resume");
1081                regs.gintsts().write(|w| w.set_wkupint(true)); // clear
1082                self.restore_irqs();
1083                return Poll::Ready(Event::Resume);
1084            }
1085
1086            Poll::Pending
1087        })
1088        .await
1089    }
1090
1091    fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
1092        trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled);
1093
1094        let regs = self.instance.regs;
1095        let st = &self.instance.state;
1096
1097        assert!(
1098            ep_addr.index() < st.endpoint_count(),
1099            "endpoint_set_stalled index {} out of range",
1100            ep_addr.index()
1101        );
1102
1103        match ep_addr.direction() {
1104            Direction::Out => {
1105                critical_section::with(|_| {
1106                    regs.doepctl(ep_addr.index()).modify(|w| {
1107                        w.set_stall(stalled);
1108                    });
1109                });
1110
1111                st.ep_states[ep_addr.index()].out_waker.wake();
1112            }
1113            Direction::In => {
1114                critical_section::with(|_| {
1115                    regs.diepctl(ep_addr.index()).modify(|w| {
1116                        w.set_stall(stalled);
1117                    });
1118                });
1119
1120                st.ep_states[ep_addr.index()].in_waker.wake();
1121            }
1122        }
1123    }
1124
1125    fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
1126        assert!(
1127            ep_addr.index() < self.instance.state.endpoint_count(),
1128            "endpoint_is_stalled index {} out of range",
1129            ep_addr.index()
1130        );
1131
1132        let regs = self.instance.regs;
1133        match ep_addr.direction() {
1134            Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
1135            Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
1136        }
1137    }
1138
1139    fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
1140        trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled);
1141
1142        assert!(
1143            ep_addr.index() < self.instance.state.endpoint_count(),
1144            "endpoint_set_enabled index {} out of range",
1145            ep_addr.index()
1146        );
1147
1148        let regs = self.instance.regs;
1149        let st = self.instance.state;
1150        match ep_addr.direction() {
1151            Direction::Out => {
1152                critical_section::with(|_| {
1153                    // cancel transfer if active
1154                    if !enabled && regs.doepctl(ep_addr.index()).read().epena() {
1155                        regs.doepctl(ep_addr.index()).modify(|w| {
1156                            w.set_snak(true);
1157                            w.set_epdis(true);
1158                        })
1159                    }
1160
1161                    regs.doepctl(ep_addr.index()).modify(|w| {
1162                        w.set_usbaep(enabled);
1163                    });
1164
1165                    // When re-enabling a non-EP0 OUT endpoint, prime it to receive a packet.
1166                    // Without this, the endpoint stays idle after reconnect and silently drops data.
1167                    if enabled && ep_addr.index() != 0 {
1168                        if let Some(ep) = st.ep_alloc_get(Direction::Out, ep_addr.index()) {
1169                            regs.doeptsiz(ep_addr.index()).modify(|w| {
1170                                w.set_xfrsiz(ep.max_packet_size as _);
1171                                w.set_pktcnt(1);
1172                            });
1173                            regs.doepctl(ep_addr.index()).modify(|w| {
1174                                w.set_cnak(true);
1175                                w.set_epena(true);
1176                            });
1177                        }
1178                    }
1179                });
1180
1181                // Wake `Endpoint::wait_enabled()`
1182                st.ep_states[ep_addr.index()].out_waker.wake();
1183            }
1184            Direction::In => {
1185                critical_section::with(|_| {
1186                    // cancel transfer if active
1187                    if !enabled && regs.diepctl(ep_addr.index()).read().epena() {
1188                        regs.diepctl(ep_addr.index()).modify(|w| {
1189                            w.set_snak(true); // set NAK
1190                            w.set_epdis(true);
1191                        })
1192                    }
1193
1194                    regs.diepctl(ep_addr.index()).modify(|w| {
1195                        w.set_usbaep(enabled);
1196                        // Set NAK on enable so the endpoint NAKs IN tokens until the
1197                        // application queues a transfer. Clearing NAK prematurely causes
1198                        // the host to see unexpected empty packets.
1199                        if enabled {
1200                            w.set_snak(true);
1201                        }
1202                    });
1203
1204                    // Flush tx fifo
1205                    regs.grstctl().write(|w| {
1206                        w.set_txfflsh(true);
1207                        w.set_txfnum(ep_addr.index() as _);
1208                    });
1209                    loop {
1210                        let x = regs.grstctl().read();
1211                        if !x.txfflsh() {
1212                            break;
1213                        }
1214                    }
1215                });
1216
1217                // Wake `Endpoint::wait_enabled()`
1218                st.ep_states[ep_addr.index()].in_waker.wake();
1219            }
1220        }
1221    }
1222
1223    async fn enable(&mut self) {
1224        trace!("enable");
1225        // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
1226    }
1227
1228    async fn disable(&mut self) {
1229        trace!("disable");
1230
1231        // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
1232        //Bus::disable(self);
1233    }
1234
1235    async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
1236        let r = self.instance.regs;
1237
1238        // Re-enable PHY clock gated during suspend.
1239        // See RM0368 §22.8 "OTG low-power modes" (STPPCLK / GATEHCLK).
1240        r.pcgcctl().modify(|w| {
1241            w.set_stppclk(false);
1242            // GATEHCLK is only present on HS cores.
1243            if self.instance.phy_type.high_speed() {
1244                w.set_gatehclk(false);
1245            }
1246        });
1247
1248        // Assert resume K-state on D+/D-.
1249        // USB 2.0 spec §7.1.7.7: TDRSMUP requires 1–15 ms of resume signaling.
1250        r.dctl().modify(|w| w.set_rwusig(true));
1251        embassy_time::Timer::after_millis(10).await;
1252        r.dctl().modify(|w| w.set_rwusig(false));
1253
1254        Ok(())
1255    }
1256}
1257
1258/// USB endpoint direction.
1259trait Dir {
1260    /// Returns the direction value.
1261    fn dir() -> Direction;
1262}
1263
1264/// Marker type for the "IN" direction.
1265pub enum In {}
1266impl Dir for In {
1267    fn dir() -> Direction {
1268        Direction::In
1269    }
1270}
1271
1272/// Marker type for the "OUT" direction.
1273pub enum Out {}
1274impl Dir for Out {
1275    fn dir() -> Direction {
1276        Direction::Out
1277    }
1278}
1279
1280/// USB endpoint.
1281pub struct Endpoint<'d, D> {
1282    _phantom: PhantomData<D>,
1283    regs: Otg,
1284    info: EndpointInfo,
1285    state: &'d EpState,
1286}
1287
1288impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, In> {
1289    fn info(&self) -> &EndpointInfo {
1290        &self.info
1291    }
1292
1293    async fn wait_enabled(&mut self) {
1294        poll_fn(|cx| {
1295            let ep_index = self.info.addr.index();
1296
1297            self.state.in_waker.register(cx.waker());
1298
1299            if self.regs.diepctl(ep_index).read().usbaep() {
1300                Poll::Ready(())
1301            } else {
1302                Poll::Pending
1303            }
1304        })
1305        .await
1306    }
1307}
1308
1309impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, Out> {
1310    fn info(&self) -> &EndpointInfo {
1311        &self.info
1312    }
1313
1314    async fn wait_enabled(&mut self) {
1315        poll_fn(|cx| {
1316            let ep_index = self.info.addr.index();
1317
1318            self.state.out_waker.register(cx.waker());
1319
1320            if self.regs.doepctl(ep_index).read().usbaep() {
1321                Poll::Ready(())
1322            } else {
1323                Poll::Pending
1324            }
1325        })
1326        .await
1327    }
1328}
1329
1330impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> {
1331    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
1332        trace!("read start len={}", buf.len());
1333
1334        poll_fn(|cx| {
1335            let index = self.info.addr.index();
1336            self.state.out_waker.register(cx.waker());
1337
1338            let doepctl = self.regs.doepctl(index).read();
1339            trace!("read ep={:?}: doepctl {:08x}", self.info.addr, doepctl.0,);
1340            if !doepctl.usbaep() {
1341                trace!("read ep={:?} error disabled", self.info.addr);
1342                return Poll::Ready(Err(EndpointError::Disabled));
1343            }
1344
1345            let len = self.state.out_size.load(Ordering::Acquire);
1346            if len != EP_OUT_BUFFER_EMPTY {
1347                trace!("read ep={:?} done len={}", self.info.addr, len);
1348
1349                if len as usize > buf.len() {
1350                    return Poll::Ready(Err(EndpointError::BufferOverflow));
1351                }
1352
1353                // SAFETY: exclusive access ensured by `out_size` atomic variable
1354                let data = unsafe { core::slice::from_raw_parts(*self.state.out_buffer.get(), len as usize) };
1355                buf[..len as usize].copy_from_slice(data);
1356
1357                // Release buffer
1358                self.state.out_size.store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
1359
1360                critical_section::with(|_| {
1361                    // Receive 1 packet
1362                    self.regs.doeptsiz(index).modify(|w| {
1363                        w.set_xfrsiz(self.info.max_packet_size as _);
1364                        w.set_pktcnt(1);
1365                    });
1366
1367                    if self.info.ep_type == EndpointType::Isochronous {
1368                        // Isochronous endpoints must set the correct even/odd frame bit to
1369                        // correspond with the next frame's number.
1370                        let frame_number = self.regs.dsts().read().fnsof();
1371                        let frame_is_odd = frame_number & 0x01 == 1;
1372
1373                        self.regs.doepctl(index).modify(|r| {
1374                            if frame_is_odd {
1375                                r.set_sd0pid_sevnfrm(true);
1376                            } else {
1377                                r.set_soddfrm(true);
1378                            }
1379                        });
1380                    }
1381
1382                    // Clear NAK to indicate we are ready to receive more data
1383                    self.regs.doepctl(index).modify(|w| {
1384                        w.set_cnak(true);
1385                    });
1386                });
1387
1388                Poll::Ready(Ok(len as usize))
1389            } else {
1390                Poll::Pending
1391            }
1392        })
1393        .await
1394    }
1395}
1396
1397impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> {
1398    async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
1399        trace!("write ep={:?} data={:?}", self.info.addr, Bytes(buf));
1400
1401        if buf.len() > self.info.max_packet_size as usize {
1402            return Err(EndpointError::BufferOverflow);
1403        }
1404
1405        let index = self.info.addr.index();
1406        // Wait for previous transfer to complete and check if endpoint is disabled
1407        poll_fn(|cx| {
1408            self.state.in_waker.register(cx.waker());
1409
1410            let diepctl = self.regs.diepctl(index).read();
1411            let dtxfsts = self.regs.dtxfsts(index).read();
1412            trace!(
1413                "write ep={:?}: diepctl {:08x} ftxfsts {:08x}",
1414                self.info.addr, diepctl.0, dtxfsts.0
1415            );
1416            if !diepctl.usbaep() {
1417                trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
1418                Poll::Ready(Err(EndpointError::Disabled))
1419            } else if !diepctl.epena() {
1420                trace!("write ep={:?} wait for prev: ready", self.info.addr);
1421                Poll::Ready(Ok(()))
1422            } else {
1423                trace!("write ep={:?} wait for prev: pending", self.info.addr);
1424                Poll::Pending
1425            }
1426        })
1427        .await?;
1428
1429        if buf.len() > 0 {
1430            poll_fn(|cx| {
1431                self.state.in_waker.register(cx.waker());
1432
1433                let size_words = (buf.len() + 3) / 4;
1434
1435                let fifo_space = self.regs.dtxfsts(index).read().ineptfsav() as usize;
1436                if size_words > fifo_space {
1437                    // Not enough space in fifo, enable tx fifo empty interrupt
1438                    critical_section::with(|_| {
1439                        self.regs.diepempmsk().modify(|w| {
1440                            w.set_ineptxfem(w.ineptxfem() | (1 << index));
1441                        });
1442                    });
1443
1444                    trace!("tx fifo for ep={} full, waiting for txfe", index);
1445
1446                    Poll::Pending
1447                } else {
1448                    trace!("write ep={:?} wait for fifo: ready", self.info.addr);
1449                    Poll::Ready(())
1450                }
1451            })
1452            .await
1453        }
1454
1455        // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with
1456        // accesses to certain OTG_FS registers.
1457        //
1458        // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs.
1459        critical_section::with(|_| {
1460            // Setup transfer size
1461            self.regs.dieptsiz(index).write(|w| {
1462                w.set_mcnt(1);
1463                w.set_pktcnt(1);
1464                w.set_xfrsiz(buf.len() as _);
1465            });
1466
1467            if self.info.ep_type == EndpointType::Isochronous {
1468                // Isochronous endpoints must set the correct even/odd frame bit to
1469                // correspond with the next frame's number.
1470                let frame_number = self.regs.dsts().read().fnsof();
1471                let frame_is_odd = frame_number & 0x01 == 1;
1472
1473                self.regs.diepctl(index).modify(|r| {
1474                    if frame_is_odd {
1475                        r.set_sd0pid_sevnfrm(true);
1476                    } else {
1477                        r.set_soddfrm_sd1pid(true);
1478                    }
1479                });
1480            }
1481
1482            // Enable endpoint
1483            self.regs.diepctl(index).modify(|w| {
1484                w.set_cnak(true);
1485                w.set_epena(true);
1486            });
1487
1488            // Write data to FIFO
1489            let fifo = self.regs.fifo(index);
1490            let mut chunks = buf.chunks_exact(4);
1491            for chunk in &mut chunks {
1492                let val = u32::from_ne_bytes(chunk.try_into().unwrap());
1493                fifo.write_value(regs::Fifo(val));
1494            }
1495            // Write any last chunk
1496            let rem = chunks.remainder();
1497            if !rem.is_empty() {
1498                let mut tmp = [0u8; 4];
1499                tmp[0..rem.len()].copy_from_slice(rem);
1500                let tmp = u32::from_ne_bytes(tmp);
1501                fifo.write_value(regs::Fifo(tmp));
1502            }
1503        });
1504
1505        trace!("write done ep={:?}", self.info.addr);
1506
1507        Ok(())
1508    }
1509}
1510
1511/// USB control pipe.
1512pub struct ControlPipe<'d> {
1513    max_packet_size: u16,
1514    regs: Otg,
1515    setup_state: &'d ControlPipeSetupState,
1516    ep_in: Endpoint<'d, In>,
1517    ep_out: Endpoint<'d, Out>,
1518}
1519
1520impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> {
1521    fn max_packet_size(&self) -> usize {
1522        usize::from(self.max_packet_size)
1523    }
1524
1525    async fn setup(&mut self) -> [u8; 8] {
1526        poll_fn(|cx| {
1527            self.ep_out.state.out_waker.register(cx.waker());
1528
1529            if self.setup_state.setup_ready.load(Ordering::Acquire) {
1530                let mut data = [0; 8];
1531                data[0..4].copy_from_slice(&self.setup_state.setup_data[0].load(Ordering::Relaxed).to_ne_bytes());
1532                data[4..8].copy_from_slice(&self.setup_state.setup_data[1].load(Ordering::Relaxed).to_ne_bytes());
1533                self.setup_state.setup_ready.store(false, Ordering::Release);
1534
1535                // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1536                self.regs.doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
1537                    w.set_rxdpid_stupcnt(3);
1538                });
1539
1540                // Clear NAK to indicate we are ready to receive more data
1541                self.regs
1542                    .doepctl(self.ep_out.info.addr.index())
1543                    .modify(|w| w.set_cnak(true));
1544
1545                trace!("SETUP received: {:?}", Bytes(&data));
1546                Poll::Ready(data)
1547            } else {
1548                trace!("SETUP waiting");
1549                Poll::Pending
1550            }
1551        })
1552        .await
1553    }
1554
1555    async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> {
1556        trace!("control: data_out");
1557        let len = self.ep_out.read(buf).await?;
1558        trace!("control: data_out read: {:?}", Bytes(&buf[..len]));
1559        Ok(len)
1560    }
1561
1562    async fn data_in(&mut self, data: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> {
1563        trace!("control: data_in write: {:?}", Bytes(data));
1564        self.ep_in.write(data).await?;
1565
1566        // wait for status response from host after sending the last packet
1567        if last {
1568            trace!("control: data_in waiting for status");
1569            self.ep_out.read(&mut []).await?;
1570            trace!("control: complete");
1571        }
1572
1573        Ok(())
1574    }
1575
1576    async fn accept(&mut self) {
1577        trace!("control: accept");
1578
1579        self.ep_in.write(&[]).await.ok();
1580
1581        trace!("control: accept OK");
1582    }
1583
1584    async fn reject(&mut self) {
1585        trace!("control: reject");
1586
1587        // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1588        self.regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
1589            w.set_stall(true);
1590        });
1591        self.regs.doepctl(self.ep_out.info.addr.index()).modify(|w| {
1592            w.set_stall(true);
1593        });
1594    }
1595
1596    async fn accept_set_address(&mut self, addr: u8) {
1597        trace!("setting addr: {}", addr);
1598        critical_section::with(|_| {
1599            self.regs.dcfg().modify(|w| {
1600                w.set_dad(addr);
1601            });
1602        });
1603
1604        // synopsys driver requires accept to be sent after changing address
1605        self.accept().await
1606    }
1607}
1608
1609/// Translates HAL [EndpointType] into PAC [vals::Eptyp]
1610fn to_eptyp(ep_type: EndpointType) -> vals::Eptyp {
1611    match ep_type {
1612        EndpointType::Control => vals::Eptyp::CONTROL,
1613        EndpointType::Isochronous => vals::Eptyp::ISOCHRONOUS,
1614        EndpointType::Bulk => vals::Eptyp::BULK,
1615        EndpointType::Interrupt => vals::Eptyp::INTERRUPT,
1616    }
1617}
1618
1619/// Calculates MPSIZ value for EP0, which uses special values.
1620fn ep0_mpsiz(max_packet_size: u16) -> u16 {
1621    match max_packet_size {
1622        8 => 0b11,
1623        16 => 0b10,
1624        32 => 0b01,
1625        64 => 0b00,
1626        other => panic!("Unsupported EP0 size: {}", other),
1627    }
1628}
1629
1630/// Hardware-dependent USB IP configuration.
1631#[derive(Copy, Clone)]
1632pub struct OtgInstance<'d> {
1633    /// The USB peripheral.
1634    pub regs: Otg,
1635    /// Shared driver/interrupt state from [`State::as_state`].
1636    pub state: State<'d>,
1637    /// FIFO depth in words.
1638    pub fifo_depth_words: u16,
1639    /// The PHY type.
1640    pub phy_type: PhyType,
1641    /// Extra RX FIFO words needed by some implementations.
1642    pub extra_rx_fifo_words: u16,
1643    /// Function to calculate TRDT value based on some internal clock speed.
1644    pub calculate_trdt_fn: fn(speed: vals::Dspd) -> u8,
1645}