embassy_usb_synopsys_otg/
lib.rs

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