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