1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! A USB driver for i.MX RT processors
//!
//! `imxrt-usbd` provides a [`usb-device`] USB bus implementation, allowing you
//! to add USB device features to your embedded Rust program. See each module
//! for usage and examples.
//!
//! To interface the library, you must define a safe implementation of [`Peripherals`].
//! See the trait documentation for more information.
//!
//! # General guidance
//!
//! The driver does not configure any of the CCM or CCM_ANALOG registers. You are
//! responsible for configuring these peripherals for proper USB functionality. See
//! the `imxrt-usbd` hardware examples to see different ways of configuring PLLs and
//! clocks.
//!
//! [`usb-device`]: https://crates.io/crates/usb-device

#![no_std]

#[macro_use]
mod log;

mod buffer;
mod cache;
mod qh;
mod ral;
mod td;
mod vcell;

pub mod full_speed;

/// Eight endpoints, two directions
const QH_COUNT: usize = 8 * 2;

/// A type that owns all USB register blocks
///
/// An implementation of `Peripherals` is expected to own the USB1
/// or USB2 registers. This includes
///
/// - USB core registers
/// - USB PHY registers
/// - USB non-core registers
/// - USB analog registers
///
/// When an instance of `Peripherals` exists, you must make sure that
/// nothing else, other than the owner of the `Peripherals` object,
/// accesses those registers.
///
/// # Safety
///
/// `Peripherals` should only be implemented on a type that
/// owns the various register blocks required for all USB
/// operation. Incorrect usage, or failure to ensure exclusive
/// ownership, could lead to data races and incorrect USB functionality.
///
/// By implementing this trait, you ensure that the [`Instance`]
/// identifier is valid for your chip. Not all i.MX RT peripherals
/// have a USB2 peripheral instance, so you must ensure that the
/// implementation is correct for your chip.
///
/// # Example
///
/// A safe implementation of `Peripherals` that works with the
/// `imxrt-ral` register access layer. Assume that `ral` is
/// shorthand for `imxrt_ral`, like
///
/// ```
/// use imxrt_ral as ral;
/// ```
///
/// ```no_run
/// # mod ral {
/// #   use core::ops::Deref; pub struct Instance; impl Deref for Instance { type Target = u32; fn deref(&self) -> &u32 { unsafe { &*(0x402e0200 as *const u32)} } }
/// #   pub fn take() -> Result<Instance, ()> { Ok(Instance) }
/// #   pub mod usb { pub use super::Instance; pub mod USB1 { pub use super::super::take; } }
/// #   pub mod usbphy { pub use super::Instance; pub mod USBPHY1 { pub use super::super::take; } }
/// #   pub mod usbnc { pub use super::Instance; pub mod USBNC1 { pub use super::super::take; } }
/// #   pub mod usb_analog { pub use super::Instance; pub mod USB_ANALOG { pub use super::super::take; } }
/// # }
/// use ral::usb;
///
/// struct Peripherals {
///     _usb: ral::usb::Instance,
///     _phy: ral::usbphy::Instance,
///     _nc: ral::usbnc::Instance,
///     _analog: ral::usb_analog::Instance,
/// }
///
/// impl Peripherals {
///     /// Panics if the instances are already taken
///     fn usb1() -> Peripherals {
///         Self {
///             _usb: ral::usb::USB1::take().unwrap(),
///             _phy: ral::usbphy::USBPHY1::take().unwrap(),
///             _nc: ral::usbnc::USBNC1::take().unwrap(),
///             _analog: ral::usb_analog::USB_ANALOG::take().unwrap(),
///         }
///     }
/// }
///
/// // This implementation is safe, because a `Peripherals` object
/// // owns the four imxrt-ral instances, which are
/// // guaranteed to be singletons. Given this approach, no one else
/// // can safely access the USB registers.
/// unsafe impl imxrt_usbd::Peripherals for Peripherals {
///     fn instance(&self) -> imxrt_usbd::Instance {
///         imxrt_usbd::Instance::USB1
///     }
/// }
///
/// let peripherals = Peripherals::usb1();
/// let bus = imxrt_usbd::full_speed::BusAdapter::new(
///     peripherals,
///     // Rest of setup...
///     # unsafe { static mut M: [u8; 1] = [0; 1]; &mut M }
/// );
/// ```
pub unsafe trait Peripherals {
    /// Returns the instance identifier for the core registers
    ///
    /// **Warning**: some i.MX RT peripherals have only one USB peripheral,
    /// USB1. The behavior is undefined if you return `Instance::USB2` on
    /// one of these systems.
    fn instance(&self) -> Instance;
}

/// USB instance identifiers
///
/// These are *not* USB standards or speeds. They indicate if this
/// is the USB1 register instance, or the USB2 register instance.
///
/// Note that some i.MX RT processors only have one USB instance (USB1).
/// On those systems, it is invalid to ever indicate the USB2 instance.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Instance {
    /// The first USB register instance
    USB1,
    /// The second USB register instance
    USB2,
}