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