#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub mod asynch;
#[cfg(feature = "async")]
pub use asynch::on_irq;
use core::cell::Cell;
use crate::cache::{clean_range, invalidate_range, MIN_CACHE_LINE};
use crate::pac::{USB_OTG_GLOBAL, USB_OTG_HOST, USB_OTG_PWRCLK};
use crate::timer::Timer;
fn to_vc_bus_address(physical_address: u32) -> u32 {
(physical_address & 0x3FFF_FFFF) | 0xC000_0000
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DataPid {
Data0,
Data1,
Setup,
}
impl DataPid {
fn bits(self) -> u8 {
match self {
DataPid::Data0 => 0b00,
DataPid::Data1 => 0b10,
DataPid::Setup => 0b11,
}
}
fn toggled(self) -> DataPid {
match self {
DataPid::Data0 => DataPid::Data1,
DataPid::Data1 => DataPid::Data0,
DataPid::Setup => DataPid::Setup,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum EndpointType {
Control,
Interrupt,
Bulk,
}
impl EndpointType {
fn bits(self) -> u8 {
match self {
EndpointType::Control => 0b00,
EndpointType::Bulk => 0b10,
EndpointType::Interrupt => 0b11,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TransferError {
Stall,
TransactionError,
Babble,
Nak,
NakTimeout,
FrameOverrun,
DataToggleError,
Halted,
Timeout,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SplitTarget {
pub hub_address: u8,
pub port: u8,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ControlEndpoint {
pub address: u8,
pub low_speed: bool,
pub max_packet_size: u16,
pub split: Option<SplitTarget>,
}
#[derive(Clone, Copy)]
struct Transaction {
endpoint_number: u8,
endpoint_type: EndpointType,
direction_in: bool,
pid: DataPid,
transfer_size: u32,
dma_address: u32,
}
const DMA_BUFFER_LEN: usize = 256;
pub const MAX_TRANSFER_LEN: usize = DMA_BUFFER_LEN;
#[repr(C, align(64))]
struct DmaBuffer([u8; DMA_BUFFER_LEN]);
const MAX_CHANNELS: usize = 12;
const HCINT_XFRC: u32 = 1 << 0;
const HCINT_CHH: u32 = 1 << 1;
const HCINT_STALL: u32 = 1 << 3;
const HCINT_NAK: u32 = 1 << 4;
const HCINT_ACK: u32 = 1 << 5;
const HCINT_NYET: u32 = 1 << 6;
const HCINT_TXERR: u32 = 1 << 7;
const HCINT_BBERR: u32 = 1 << 8;
const HCINT_FRMOR: u32 = 1 << 9;
const HCINT_DTERR: u32 = 1 << 10;
const MAX_CSPLIT_POLLS: u32 = 8;
const CSPLIT_RETRY_DELAY_US: u32 = 5 * 125;
pub struct Dwc2Host {
global: USB_OTG_GLOBAL,
host: USB_OTG_HOST,
allocated: Cell<u16>,
num_channels: u8,
}
impl Dwc2Host {
pub fn init(
global: USB_OTG_GLOBAL,
host: USB_OTG_HOST,
pwrclk: USB_OTG_PWRCLK,
timer: &Timer,
) -> Self {
while global.grstctl().read().ahbidl().bit_is_clear() {}
global.grstctl().modify(|_, w| w.csrst().set_bit());
while global.grstctl().read().csrst().bit_is_set() {}
timer.delay_ms(3);
pwrclk.pcgcctl().write(|w| unsafe { w.bits(0) });
unsafe {
global.grxfsiz().write(|w| w.rxfd().bits(0x400));
global.gnptxfsiz_host().write(|w| {
w.nptxfsa().bits(0x400);
w.nptxfd().bits(0x400)
});
global.hptxfsiz().write(|w| {
w.ptxsa().bits(0x800);
w.ptxfd().bits(0x400)
});
}
global.grstctl().modify(|_, w| w.rxfflsh().set_bit());
while global.grstctl().read().rxfflsh().bit_is_set() {}
unsafe {
global
.grstctl()
.modify(|_, w| w.txfnum().bits(0x10).txfflsh().set_bit());
}
while global.grstctl().read().txfflsh().bit_is_set() {}
global.gusbcfg().modify(|_, w| w.fhmod().set_bit());
timer.delay_ms(25);
global
.gahbcfg()
.modify(|_, w| w.dmaen().set_bit().axi_wait().set_bit().gint().set_bit());
global.gintmsk().modify(|_, w| w.sofm().clear_bit());
unsafe {
global
.gintmsk()
.modify(|r, w| w.bits(r.bits() | (1 << 24) | (1 << 25)));
}
global
.gusbcfg()
.modify(|_, w| w.hnpcap().clear_bit().srpcap().clear_bit());
host.hprt().write(|w| w.ppwr().set_bit());
let num_channels =
(global.hw_config0().read().host_channel_count().bits() + 1).min(MAX_CHANNELS as u8);
Self {
global,
host,
allocated: Cell::new(0),
num_channels,
}
}
pub fn num_channels(&self) -> usize {
self.num_channels as usize
}
pub fn alloc_channel(&self) -> Option<Channel<'_>> {
let allocated = self.allocated.get();
let index = (0..self.num_channels as usize).find(|i| allocated & (1 << i) == 0)?;
self.allocated.set(allocated | (1 << index));
Some(Channel {
owner: self,
index,
dma_buffer: DmaBuffer([0; DMA_BUFFER_LEN]),
last_hcint: Cell::new(0),
})
}
pub fn port_connected(&self) -> bool {
self.host.hprt().read().pcsts().bit_is_set()
}
pub fn reset_port(&self, timer: &Timer) {
self.host
.hprt()
.write(|w| w.ppwr().set_bit().prst().set_bit());
timer.delay_ms(50);
self.host.hprt().write(|w| w.ppwr().set_bit());
timer.delay_ms(10);
self.host.hprt().write(|w| {
w.ppwr().set_bit();
w.pcdet().set_bit();
w.penchng().set_bit();
w.pocchng().set_bit()
});
if self.port_speed() != 0 {
unsafe {
self.host.hcfg().modify(|_, w| w.fslspcs().bits(1));
self.host.hfir().write(|w| w.frivl().bits(48_000));
}
}
}
pub fn port_enabled(&self) -> bool {
self.host.hprt().read().pena().bit_is_set()
}
pub fn port_speed(&self) -> u8 {
self.host.hprt().read().pspd().bits()
}
pub fn global(&self) -> &USB_OTG_GLOBAL {
&self.global
}
pub fn host(&self) -> &USB_OTG_HOST {
&self.host
}
fn free_channel(&self, index: usize) {
self.allocated.set(self.allocated.get() & !(1 << index));
}
}
pub struct Channel<'a> {
owner: &'a Dwc2Host,
index: usize,
dma_buffer: DmaBuffer,
last_hcint: Cell<u32>,
}
impl Drop for Channel<'_> {
fn drop(&mut self) {
self.owner.free_channel(self.index);
}
}
impl Channel<'_> {
pub fn index(&self) -> usize {
self.index
}
pub fn last_interrupt(&self) -> u32 {
self.last_hcint.get()
}
fn regs(&self) -> &USB_OTG_HOST {
&self.owner.host
}
fn ch(&self) -> &crate::pac::usb_otg_host::HOST_CHANNEL {
self.owner.host.host_channel(self.index)
}
pub fn control_setup(
&mut self,
endpoint: ControlEndpoint,
setup: &[u8; 8],
timer: &Timer,
) -> Result<(), TransferError> {
self.dma_buffer.0[..8].copy_from_slice(setup);
let address = self.dma_buffer.0.as_ptr() as u32;
clean_range(address, 8);
let txn = Transaction {
endpoint_number: 0,
endpoint_type: EndpointType::Control,
direction_in: false,
pid: DataPid::Setup,
transfer_size: 8,
dma_address: address,
};
self.run_transaction(endpoint, &txn, timer)?;
Ok(())
}
pub fn control_data_in(
&mut self,
endpoint: ControlEndpoint,
buf: &mut [u8],
timer: &Timer,
) -> Result<usize, TransferError> {
debug_assert!(buf.len() <= DMA_BUFFER_LEN);
let address = self.dma_buffer.0.as_ptr() as u32;
let txn = Transaction {
endpoint_number: 0,
endpoint_type: EndpointType::Control,
direction_in: true,
pid: DataPid::Data1,
transfer_size: buf.len() as u32,
dma_address: address,
};
let received = self.run_transaction(endpoint, &txn, timer)?;
invalidate_range(address, buf.len());
buf[..received].copy_from_slice(&self.dma_buffer.0[..received]);
Ok(received)
}
pub fn control_status_out(
&mut self,
endpoint: ControlEndpoint,
timer: &Timer,
) -> Result<(), TransferError> {
let address = self.dma_buffer.0.as_ptr() as u32;
let txn = Transaction {
endpoint_number: 0,
endpoint_type: EndpointType::Control,
direction_in: false,
pid: DataPid::Data1,
transfer_size: 0,
dma_address: address,
};
self.run_transaction(endpoint, &txn, timer)?;
Ok(())
}
pub fn control_status_in(
&mut self,
endpoint: ControlEndpoint,
timer: &Timer,
) -> Result<(), TransferError> {
let address = self.dma_buffer.0.as_ptr() as u32;
let txn = Transaction {
endpoint_number: 0,
endpoint_type: EndpointType::Control,
direction_in: true,
pid: DataPid::Data1,
transfer_size: 0,
dma_address: address,
};
self.run_transaction(endpoint, &txn, timer)?;
Ok(())
}
pub fn control_data_out(
&mut self,
endpoint: ControlEndpoint,
data: &[u8],
timer: &Timer,
) -> Result<(), TransferError> {
debug_assert!(data.len() <= DMA_BUFFER_LEN);
self.dma_buffer.0[..data.len()].copy_from_slice(data);
let address = self.dma_buffer.0.as_ptr() as u32;
clean_range(address, data.len());
let txn = Transaction {
endpoint_number: 0,
endpoint_type: EndpointType::Control,
direction_in: false,
pid: DataPid::Data1,
transfer_size: data.len() as u32,
dma_address: address,
};
self.run_transaction(endpoint, &txn, timer)?;
Ok(())
}
pub fn interrupt_in(
&mut self,
endpoint: ControlEndpoint,
endpoint_number: u8,
data_toggle: &mut bool,
buf: &mut [u8],
timer: &Timer,
) -> Result<usize, TransferError> {
debug_assert!(buf.len() <= DMA_BUFFER_LEN);
let address = self.dma_buffer.0.as_ptr() as u32;
let txn = Transaction {
endpoint_number,
endpoint_type: EndpointType::Interrupt,
direction_in: true,
pid: if *data_toggle {
DataPid::Data1
} else {
DataPid::Data0
},
transfer_size: buf.len() as u32,
dma_address: address,
};
let received = self.run_transaction(endpoint, &txn, timer)?;
*data_toggle = !*data_toggle;
invalidate_range(address, buf.len());
buf[..received].copy_from_slice(&self.dma_buffer.0[..received]);
Ok(received)
}
pub fn bulk_out(
&mut self,
endpoint: ControlEndpoint,
endpoint_number: u8,
data_toggle: &mut bool,
buf: &[u8],
timer: &Timer,
) -> Result<usize, TransferError> {
let address = buf.as_ptr() as u32;
clean_range(address, buf.len());
let txn = Transaction {
endpoint_number,
endpoint_type: EndpointType::Bulk,
direction_in: false,
pid: Self::toggle_pid(*data_toggle),
transfer_size: buf.len() as u32,
dma_address: address,
};
let sent = self.run_transaction(endpoint, &txn, timer)?;
*data_toggle = self.next_toggle();
Ok(sent)
}
pub fn bulk_in(
&mut self,
endpoint: ControlEndpoint,
endpoint_number: u8,
data_toggle: &mut bool,
buf: &mut [u8],
timer: &Timer,
) -> Result<usize, TransferError> {
let address = buf.as_mut_ptr() as u32;
debug_assert!(
address.is_multiple_of(MIN_CACHE_LINE),
"bulk IN buffer must be cache-line aligned"
);
let max_packet_size = endpoint.max_packet_size.max(1) as u32;
let transfer_size = buf.len() as u32 / max_packet_size * max_packet_size;
let txn = Transaction {
endpoint_number,
endpoint_type: EndpointType::Bulk,
direction_in: true,
pid: Self::toggle_pid(*data_toggle),
transfer_size,
dma_address: address,
};
let received = self.run_transaction(endpoint, &txn, timer)?;
*data_toggle = self.next_toggle();
invalidate_range(address, buf.len());
Ok(received)
}
fn toggle_pid(data_toggle: bool) -> DataPid {
if data_toggle {
DataPid::Data1
} else {
DataPid::Data0
}
}
fn next_toggle(&self) -> bool {
self.ch().hctsiz().read().dpid().bits() == DataPid::Data1.bits()
}
fn start_channel(
&self,
endpoint: ControlEndpoint,
txn: &Transaction,
complete_split: bool,
odd_frame: Option<bool>,
) {
let ch = self.ch();
unsafe {
ch.hcint().write(|w| w.bits(0xffff_ffff));
}
unsafe {
ch.hcintmsk().write(|w| w.bits(HCINT_CHH));
}
unsafe {
match endpoint.split {
Some(split) => ch.hcsplt().write(|w| {
w.hubaddr().bits(split.hub_address);
w.prtaddr().bits(split.port);
w.xactpos().bits(0b11);
w.complsplt().bit(complete_split);
w.spliten().set_bit()
}),
None => ch.hcsplt().write(|w| w.bits(0)),
}
}
unsafe {
ch.hcdma()
.write(|w| w.dmaaddr().bits(to_vc_bus_address(txn.dma_address)));
}
let max_packet_size = endpoint.max_packet_size.max(1) as u32;
let packet_count = txn.transfer_size.div_ceil(max_packet_size).max(1);
unsafe {
ch.hctsiz().write(|w| {
w.xfrsiz().bits(txn.transfer_size);
w.pktcnt().bits(packet_count as u16);
w.dpid().bits(txn.pid.bits())
});
}
let odd_frame = match odd_frame {
Some(odd) => odd,
None if endpoint.split.is_some() => false,
None => self.regs().hfnum().read().frnum().bits() & 1 == 1,
};
unsafe {
ch.hcchar().write(|w| {
w.mpsiz().bits(endpoint.max_packet_size);
w.epnum().bits(txn.endpoint_number);
w.epdir().bit(txn.direction_in);
w.lsdev().bit(endpoint.low_speed);
w.eptyp().bits(txn.endpoint_type.bits());
w.mc().bits(1);
w.dad().bits(endpoint.address);
w.oddfrm().bit(odd_frame);
w.chena().set_bit()
});
}
}
fn ack_hcint(&self) {
unsafe {
self.ch().hcint().write(|w| w.bits(0xffff_ffff));
}
}
fn abort_channel(&self, timer: &Timer) {
const ABORT_TIMEOUT_US: u64 = 10_000;
let ch = self.ch();
ch.hcchar()
.modify(|_, w| w.chdis().set_bit().chena().set_bit());
let start = timer.now_micros();
while ch.hcint().read().chh().bit_is_clear() {
if timer.now_micros() - start > ABORT_TIMEOUT_US {
break;
}
}
self.ack_hcint();
}
fn wait_for_halt(&self, timer: &Timer) -> Result<u32, TransferError> {
const TIMEOUT_US: u64 = 50_000;
let ch = self.ch();
let start = timer.now_micros();
loop {
let hcint = ch.hcint().read().bits();
if hcint & HCINT_CHH != 0 {
self.last_hcint.set(hcint);
self.ack_hcint();
return Ok(hcint);
}
if timer.now_micros() - start > TIMEOUT_US {
self.last_hcint.set(hcint);
self.abort_channel(timer);
return Err(TransferError::Timeout);
}
}
}
fn interpret_halt(&self, hcint: u32, requested: usize) -> Result<usize, TransferError> {
if hcint & HCINT_XFRC != 0 {
let remaining = self.ch().hctsiz().read().xfrsiz().bits() as usize;
Ok(requested - remaining)
} else if hcint & HCINT_STALL != 0 {
Err(TransferError::Stall)
} else if hcint & HCINT_TXERR != 0 {
Err(TransferError::TransactionError)
} else if hcint & HCINT_BBERR != 0 {
Err(TransferError::Babble)
} else if hcint & HCINT_FRMOR != 0 {
Err(TransferError::FrameOverrun)
} else if hcint & HCINT_DTERR != 0 {
Err(TransferError::DataToggleError)
} else if hcint & HCINT_NAK != 0 {
Err(TransferError::Nak)
} else {
Err(TransferError::Halted)
}
}
fn run_channel(&self, timer: &Timer) -> Result<usize, TransferError> {
let requested = self.ch().hctsiz().read().xfrsiz().bits() as usize;
let hcint = self.wait_for_halt(timer)?;
self.interpret_halt(hcint, requested)
}
fn run_transaction(
&self,
endpoint: ControlEndpoint,
txn: &Transaction,
timer: &Timer,
) -> Result<usize, TransferError> {
if endpoint.split.is_none() {
self.start_channel(endpoint, txn, false, None);
return self.run_channel(timer);
}
let periodic = txn.endpoint_type == EndpointType::Interrupt;
let max_packet_size = endpoint.max_packet_size.max(1) as u32;
let mut offset = 0;
let mut pid = txn.pid;
loop {
let this_packet = (txn.transfer_size - offset).min(max_packet_size);
let packet = Transaction {
transfer_size: this_packet,
dma_address: txn.dma_address + offset,
pid,
..*txn
};
let received = if periodic {
self.run_periodic_split_packet(endpoint, &packet, timer)? as u32
} else {
self.run_split_packet(endpoint, &packet, timer)? as u32
};
offset += received;
pid = pid.toggled();
if received < this_packet || offset >= txn.transfer_size {
break;
}
}
Ok(offset as usize)
}
fn run_split_packet(
&self,
endpoint: ControlEndpoint,
packet: &Transaction,
timer: &Timer,
) -> Result<usize, TransferError> {
let requested = packet.transfer_size as usize;
self.start_channel(endpoint, packet, false, None);
let hcint = self.wait_for_halt(timer)?;
if hcint & HCINT_ACK == 0 {
return self.interpret_halt(hcint, requested);
}
let mut hcint = 0;
for attempt in 0..MAX_CSPLIT_POLLS {
if attempt > 0 {
timer.delay_us(CSPLIT_RETRY_DELAY_US);
}
self.start_channel(endpoint, packet, true, None);
hcint = self.wait_for_halt(timer)?;
if hcint & (HCINT_NYET | HCINT_NAK) != 0 && hcint & HCINT_XFRC == 0 {
continue;
}
return self.interpret_halt(hcint, requested);
}
self.interpret_halt(hcint, requested)
}
fn run_periodic_split_packet(
&self,
endpoint: ControlEndpoint,
packet: &Transaction,
timer: &Timer,
) -> Result<usize, TransferError> {
let requested = packet.transfer_size as usize;
let mut next_frame = (self.current_microframe() + 1) & 7;
if next_frame == 6 {
next_frame = 7;
}
self.wait_for_microframe(next_frame, timer);
self.start_channel(endpoint, packet, false, Some(next_frame & 1 == 1));
let hcint = self.wait_for_halt(timer)?;
if hcint & HCINT_ACK == 0 {
return self.interpret_halt(hcint, requested);
}
let mut tries: i32 = if next_frame != 5 { 3 } else { 2 };
next_frame = (next_frame + 2) & 7;
loop {
self.wait_for_microframe(next_frame, timer);
self.start_channel(endpoint, packet, true, Some(next_frame & 1 == 1));
let hcint = self.wait_for_halt(timer)?;
if hcint & (HCINT_STALL | HCINT_TXERR | HCINT_BBERR | HCINT_XFRC) != 0 {
return self.interpret_halt(hcint, requested);
}
if hcint & (HCINT_NYET | HCINT_ACK) != 0 {
if tries == 0 {
return Err(TransferError::Nak);
}
tries -= 1;
next_frame = (next_frame + 1) & 7;
continue;
}
if hcint & HCINT_NAK != 0 {
return Err(TransferError::Nak);
}
return self.interpret_halt(hcint, requested);
}
}
fn current_microframe(&self) -> u8 {
(self.regs().hfnum().read().frnum().bits() & 7) as u8
}
fn wait_for_microframe(&self, frame: u8, timer: &Timer) {
let start = timer.now_micros();
while self.current_microframe() != frame {
if timer.now_micros() - start > 2_000 {
break;
}
}
}
}