use core::ops::{Deref, DerefMut};
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use alloc::{boxed::Box, collections::BTreeMap};
use dma_api::{DArray, DmaDirection};
use futures::FutureExt;
use futures::future::BoxFuture;
use tock_registers::interfaces::*;
pub use usb_if::DrMode;
use usb_if::Speed;
use crate::backend::ty::Event;
use crate::backend::{
kmod::{hub::HubOp, kcore::CoreOp, xhci::Xhci},
ty::{DeviceOp, EventHandlerOp},
};
use crate::osal::Kernel;
use crate::{DeviceAddressInfo, KernelOp, Mmio};
use reg::GUSB2PHYCFG;
use {
event::EventBuffer,
reg::{GCTL, GHWPARAMS0, GHWPARAMS1, GHWPARAMS3, GHWPARAMS4, GUCTL1},
udphy::Udphy,
};
use crate::err::{Result, USBError};
use reg::GEVNTSIZ;
use usb2phy::Usb2Phy;
pub use usb2phy::Usb2PhyParam;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum UsbPhyInterfaceMode {
#[default]
Unknown,
Utmi,
UtmiWide,
}
pub mod grf;
mod consts;
mod event;
mod reg;
mod udphy;
pub mod usb2phy;
use consts::*;
use reg::Dwc3Regs;
pub use udphy::UdphyParam;
pub trait CruOp: Sync + Send + 'static {
fn reset_assert(&self, id: u64);
fn reset_deassert(&self, id: u64);
}
pub struct DwcNewParams<'a, C: CruOp> {
pub ctrl: Mmio,
pub phy: Mmio,
pub phy_param: UdphyParam<'a>,
pub usb2_phy_param: Usb2PhyParam<'a>,
pub cru: C,
pub rst_list: &'a [(&'a str, u64)],
pub params: DwcParams,
pub kernel: &'static dyn KernelOp,
}
#[derive(Debug, Default, Clone)]
pub struct DwcParams {
pub dr_mode: DrMode,
pub max_speed: Speed,
pub hsphy_mode: UsbPhyInterfaceMode,
pub delayed_status: bool,
pub ep0_bounced: bool,
pub ep0_expect_in: bool,
pub has_hibernation: bool,
pub has_lpm_erratum: bool,
pub is_utmi_l1_suspend: bool,
pub is_selfpowered: bool,
pub is_fpga: bool,
pub needs_fifo_resize: bool,
pub pullups_connected: bool,
pub resize_fifos: bool,
pub setup_packet_pending: bool,
pub start_config_issued: bool,
pub three_stage_setup: bool,
pub disable_scramble_quirk: bool,
pub u2exit_lfps_quirk: bool,
pub u2ss_inp3_quirk: bool,
pub req_p1p2p3_quirk: bool,
pub del_p1p2p3_quirk: bool,
pub del_phy_power_chg_quirk: bool,
pub lfps_filter_quirk: bool,
pub rx_detect_poll_quirk: bool,
pub dis_u3_susphy_quirk: bool,
pub dis_u2_susphy_quirk: bool,
pub dis_u1u2_quirk: bool,
pub dis_enblslpm_quirk: bool,
pub dis_u2_freeclk_exists_quirk: bool,
pub tx_de_emphasis_quirk: bool,
pub tx_de_emphasis: u8, pub usb2_phyif_utmi_width: u8, }
pub struct Dwc {
xhci: Xhci,
usb3_phy: Udphy,
usb2_phy: Usb2Phy,
dwc_regs: Dwc3Regs,
cru: Arc<dyn CruOp>,
rsts: BTreeMap<String, u64>,
ev_buffs: Vec<EventBuffer>,
revistion: u32,
nr_scratch: u32,
params: DwcParams,
scratchbuf: Option<DArray<u8>>,
}
impl Dwc {
pub fn new(mut params: DwcNewParams<'_, impl CruOp>) -> Result<Self> {
let mmio_base = params.ctrl.as_ptr() as usize;
params.params.max_speed = Speed::Full;
let cru = Arc::new(params.cru);
let xhci = Xhci::new(params.ctrl, params.kernel)?;
let phy = Udphy::new(params.phy, cru.clone(), params.phy_param);
let usb2_phy = Usb2Phy::new(cru.clone(), params.usb2_phy_param, xhci.kernel().clone());
let dwc_regs = unsafe { Dwc3Regs::new(mmio_base) };
let mut rsts = BTreeMap::new();
for &(name, id) in params.rst_list.iter() {
rsts.insert(String::from(name), id);
}
Ok(Self {
xhci,
dwc_regs,
usb3_phy: phy,
usb2_phy,
cru,
rsts,
ev_buffs: vec![],
revistion: 0,
nr_scratch: 0,
params: params.params,
scratchbuf: None,
})
}
async fn dwc3_init(&mut self) -> Result<()> {
self.alloc_event_buffers(DWC3_EVENT_BUFFERS_SIZE)?;
self.core_init().await?;
self.event_buffers_setup();
Ok(())
}
fn alloc_event_buffers(&mut self, len: usize) -> Result<()> {
let num_buffs = self
.dwc_regs
.globals()
.ghwparams1
.read(GHWPARAMS1::NUM_EVENT_BUFFERS);
debug!("Allocating {} event buffers", num_buffs);
for _ in 0..num_buffs {
let ev_buff = EventBuffer::new(len, self.kernel())?;
self.ev_buffs.push(ev_buff);
}
Ok(())
}
fn event_buffers_setup(&mut self) {
info!("DWC3: Setting up event buffers");
let regs = self.dwc_regs.globals();
for (i, ev_buff) in self.ev_buffs.iter().enumerate() {
if i >= regs.gevnt.len() {
warn!("DWC3: Invalid event buffer index {}", i);
break;
}
let dma_addr = ev_buff.dma_addr();
let length = ev_buff.buffer.len();
debug!(
"DWC3: Event buffer {} - DMA addr: {:#x}, length: {}",
i, dma_addr, length
);
regs.gevnt[i].adrlo.set((dma_addr & 0xffffffff) as u32);
regs.gevnt[i].adrhi.set((dma_addr >> 32) as u32);
regs.gevnt[i]
.size
.modify(GEVNTSIZ::INTMASK::Unmasked + GEVNTSIZ::SIZE.val(length as _));
regs.gevnt[i].count.set(0);
debug!(
"DWC3: GEVNTSIZ[{}] = {:?} (INTMASK cleared, SIZE={})",
i,
regs.gevnt[i].size.debug(),
length
);
}
debug!("DWC3: Event buffers setup completed");
}
async fn core_init(&mut self) -> Result<()> {
self.revistion = self.dwc_regs.read_revision() as _;
if self.revistion != 0x55330000 {
Err(anyhow!(
"Unsupported DWC3 revision: 0x{:08x}",
self.revistion
))?;
}
self.revistion += self.dwc_regs.read_product_id();
debug!("DWC3: Detected revision 0x{:08x}", self.revistion);
if let Some(GHWPARAMS3::SSPHY_IFC::Value::Disabled) = self
.dwc_regs
.globals()
.ghwparams3
.read_as_enum(GHWPARAMS3::SSPHY_IFC)
&& self.max_speed == Speed::SuperSpeed
{
self.max_speed = Speed::High;
}
debug!("DWC3: Max speed {:?}", self.max_speed);
self.dwc_regs.device_soft_reset().await;
info!("DWC3: Starting core soft reset (includes PHY soft reset)");
self.dwc_regs.core_soft_reset(self.kernel()).await;
let gusb3_val = self.dwc_regs.globals().gusb3pipectl0.extract();
let gusb2_val = self.dwc_regs.globals().gusb2phycfg0.extract();
info!(
"DWC3: After core_soft_reset - GUSB3PIPECTL={:#010x}, GUSB2PHYCFG={:#010x}",
gusb3_val.get(),
gusb2_val.get()
);
info!("DWC3: Clearing suspendusb20 bit (TRM requirement)");
self.dwc_regs
.globals()
.gusb2phycfg0
.modify(GUSB2PHYCFG::SUSPHY::Disable);
if self.revistion >= DWC3_REVISION_250A {
debug!("DWC3: Revision 250A or later detected");
if matches!(self.max_speed, Speed::Full | Speed::High) {
self.dwc_regs
.globals()
.guctl1
.modify(GUCTL1::DEV_FORCE_20_CLK_FOR_30_CLK::Enable);
}
}
let mut reg = self.dwc_regs.globals().gctl.extract();
reg.modify(GCTL::SCALEDOWN::None);
match self
.dwc_regs
.globals()
.ghwparams1
.read_as_enum(GHWPARAMS1::EN_PWROPT)
{
Some(GHWPARAMS1::EN_PWROPT::Value::Clock) => {
if (DWC3_REVISION_210A..=DWC3_REVISION_250A).contains(&self.revistion) {
reg.modify(GCTL::DSBLCLKGTNG::Enable + GCTL::SOFITPSYNC::Enable);
} else {
reg.modify(GCTL::DSBLCLKGTNG::Disable);
}
}
Some(GHWPARAMS1::EN_PWROPT::Value::Hibernation) => {
self.nr_scratch = self
.dwc_regs
.globals()
.ghwparams4
.read(GHWPARAMS4::HIBER_SCRATCHBUFS) as _;
reg.modify(GCTL::GBLHIBERNATIONEN::Enable);
}
_ => {
debug!("No power optimization available");
}
}
reg.modify(GCTL::DISSCRAMBLE::Disable);
if self.u2exit_lfps_quirk {
reg.modify(GCTL::U2EXIT_LFPS::Enable);
}
if self.revistion < DWC3_REVISION_190A {
debug!("Applying DWC3 <1.90a SuperSpeed connect workaround");
reg.modify(GCTL::U2RSTECN::Enable);
}
self.dwc_regs.globals().gctl.set(reg.get());
self.phy_setup().await?;
self.alloc_scratch_buffers()?;
self.setup_scratch_buffers();
self.core_init_mode()?;
Ok(())
}
fn hsphy_mode_setup(&mut self) {
use reg::GUSB2PHYCFG;
match self.hsphy_mode {
UsbPhyInterfaceMode::Utmi => {
self.dwc_regs.globals().gusb2phycfg0.modify(
GUSB2PHYCFG::PHYIF.val(0) + GUSB2PHYCFG::USBTRDTIM.val(9), );
debug!("DWC3: HS PHY configured as UTMI 8-bit");
}
UsbPhyInterfaceMode::UtmiWide => {
self.dwc_regs.globals().gusb2phycfg0.modify(
GUSB2PHYCFG::PHYIF.val(1) + GUSB2PHYCFG::USBTRDTIM.val(5), );
debug!("DWC3: HS PHY configured as UTMI 16-bit");
}
UsbPhyInterfaceMode::Unknown => {
debug!("DWC3: HS PHY mode unknown, using default configuration");
}
}
}
async fn phy_setup(&mut self) -> Result<()> {
use reg::{GUSB2PHYCFG, GUSB3PIPECTL};
info!("DWC3: Configuring PHY");
let is_mode_drd = matches!(
self.dwc_regs
.globals()
.ghwparams0
.read_as_enum(GHWPARAMS0::MODE),
Some(GHWPARAMS0::MODE::Value::DRD)
);
let gusb3_init = self.dwc_regs.globals().gusb3pipectl0.extract();
info!(
"DWC3: Initial GUSB3PIPECTL = {:#010x} before config",
gusb3_init.get()
);
let mut gusb3 = self.dwc_regs.globals().gusb3pipectl0.extract();
if self.revistion > DWC3_REVISION_194A {
gusb3.modify(GUSB3PIPECTL::SUSPHY::Enable);
}
if is_mode_drd {
gusb3.modify(GUSB3PIPECTL::SUSPHY::Disable);
}
if self.u2ss_inp3_quirk {
gusb3.modify(GUSB3PIPECTL::U2SSINP3OK::Enable);
}
if self.req_p1p2p3_quirk {
gusb3.modify(GUSB3PIPECTL::REQP0P1P2P3::Yes);
}
if self.del_p1p2p3_quirk {
gusb3.modify(GUSB3PIPECTL::DEP1P2P3::Enable);
}
if self.del_phy_power_chg_quirk {
gusb3.modify(GUSB3PIPECTL::DEPOCHANGE::Enable);
}
if self.lfps_filter_quirk {
gusb3.modify(GUSB3PIPECTL::LFPSFILT::Enable);
}
if self.rx_detect_poll_quirk {
gusb3.modify(GUSB3PIPECTL::RX_DETOPOLL::Enable);
}
if self.tx_de_emphasis_quirk {
gusb3.modify(GUSB3PIPECTL::TX_DEEPH.val(self.tx_de_emphasis as u32));
}
const IS_ROCKCHIP: bool = true;
if self.dis_u3_susphy_quirk || IS_ROCKCHIP {
gusb3.modify(GUSB3PIPECTL::SUSPHY::Disable);
}
self.dwc_regs.globals().gusb3pipectl0.set(gusb3.get());
self.hsphy_mode_setup();
self.kernel().delay(core::time::Duration::from_millis(100));
let gusb2_init = self.dwc_regs.globals().gusb2phycfg0.extract();
info!(
"DWC3: Initial GUSB2PHYCFG = {:#010x} before config",
gusb2_init.get()
);
let mut gusb2 = self.dwc_regs.globals().gusb2phycfg0.extract();
if self.revistion > DWC3_REVISION_194A {
gusb2.modify(GUSB2PHYCFG::SUSPHY::Enable);
}
if is_mode_drd {
gusb2.modify(GUSB2PHYCFG::SUSPHY::Disable);
}
if self.dis_u2_susphy_quirk {
gusb2.modify(GUSB2PHYCFG::SUSPHY::Disable);
}
if self.dis_enblslpm_quirk {
gusb2.modify(GUSB2PHYCFG::ENBLSLPM::Disable);
} else {
gusb2.modify(GUSB2PHYCFG::ENBLSLPM::Enable);
}
if self.dis_u2_freeclk_exists_quirk {
gusb2.modify(GUSB2PHYCFG::U2_FREECLK_EXISTS::No);
}
self.dwc_regs.globals().gusb2phycfg0.set(gusb2.get());
self.kernel().delay(core::time::Duration::from_millis(100));
debug!("DWC3: PHY configuration completed");
Ok(())
}
fn alloc_scratch_buffers(&mut self) -> Result<()> {
if !self.has_hibernation {
return Ok(());
}
if self.nr_scratch == 0 {
return Ok(());
}
let scratch_size = (self.nr_scratch as usize) * DWC3_SCRATCHBUF_SIZE;
let scratchbuf = self
.kernel()
.array_zero_with_align(
scratch_size,
self.kernel().page_size(),
DmaDirection::Bidirectional,
)
.map_err(|_| USBError::NoMemory)?;
self.scratchbuf = Some(scratchbuf);
debug!(
"DWC3: Allocated {} scratch buffers (total {} bytes)",
self.nr_scratch, scratch_size
);
Ok(())
}
fn setup_scratch_buffers(&mut self) {
if let Some(_scratchbuf) = &self.scratchbuf {
todo!()
}
}
fn core_init_mode(&mut self) -> Result<()> {
match self.dr_mode {
DrMode::Host => {
info!("DWC3: Initializing in HOST mode");
self.dwc_regs.globals().gctl.modify(GCTL::PRTCAPDIR::Host);
}
DrMode::Otg => {
todo!()
}
DrMode::Peripheral => todo!(),
}
Ok(())
}
fn dump_registers(&self) {
use reg::*;
let regs = self.dwc_regs.globals();
info!("=== DWC3 寄存器状态 ===");
let gctl = regs.gctl.extract();
let gctl_val = gctl.get();
info!("GCTL = {:#010x}", gctl_val);
let prtcapdir_val = gctl.read(GCTL::PRTCAPDIR);
let prtcapdir_str = match prtcapdir_val {
0 => "Device",
1 => "Host",
2 => "OTG",
3 => "Reserved",
_ => "Unknown",
};
info!(" PRTCAPDIR = {} ({})", prtcapdir_str, prtcapdir_val);
let gusb3 = regs.gusb3pipectl0.extract();
let gusb3_val = gusb3.get();
info!("GUSB3PIPECTL = {:#010x}", gusb3_val);
info!(" SUSPHY = {}", gusb3.is_set(GUSB3PIPECTL::SUSPHY));
info!(" U2SSINP3OK = {}", gusb3.is_set(GUSB3PIPECTL::U2SSINP3OK));
info!(
" REQP0P1P2P3 = {}",
gusb3.is_set(GUSB3PIPECTL::REQP0P1P2P3)
);
info!(" DEP1P2P3 = {}", gusb3.is_set(GUSB3PIPECTL::DEP1P2P3));
let gusb2 = regs.gusb2phycfg0.extract();
let gusb2_val = gusb2.get();
info!("GUSB2PHYCFG = {:#010x}", gusb2_val);
info!(" SUSPHY = {}", gusb2.is_set(GUSB2PHYCFG::SUSPHY));
info!(" ENBLSLPM = {}", gusb2.is_set(GUSB2PHYCFG::ENBLSLPM));
let phyif = gusb2.read(GUSB2PHYCFG::PHYIF);
info!(
" PHYIF = {} ({}-bit)",
phyif,
if phyif == 0 { 8 } else { 16 }
);
let usbtrdtim = gusb2.read(GUSB2PHYCFG::USBTRDTIM);
info!(" USBTRDTIM = {}", usbtrdtim);
let hwparams0 = regs.ghwparams0.extract();
info!("GHWPARAMS0 = {:#010x}", hwparams0.get());
let mode_val = hwparams0.read(GHWPARAMS0::MODE);
let mode_str = match mode_val {
0 => "Gadget",
1 => "Host",
2 => "DRD",
3 => "Reserved",
_ => "Unknown",
};
info!(" MODE = {} ({})", mode_str, mode_val);
let hwparams1 = regs.ghwparams1.extract();
let num_event_buffers = hwparams1.read(GHWPARAMS1::NUM_EVENT_BUFFERS);
info!("GHWPARAMS1 = {:#010x}", hwparams1.get());
info!(" NUM_EVENT_BUFFERS = {}", num_event_buffers);
info!("======================");
}
async fn _init(&mut self) -> Result {
info!("DWC3: Starting controller initialization");
for &id in self.rsts.values() {
self.cru.reset_assert(id);
}
self.kernel().delay(core::time::Duration::from_millis(1));
self.usb2_phy.setup().await?;
let kernel = self.kernel().clone();
self.usb3_phy.setup(&kernel).await?;
for &id in self.rsts.values() {
self.cru.reset_deassert(id);
}
self.dwc3_init().await?;
self.xhci.init().await?;
self.dump_registers();
Ok(())
}
}
impl CoreOp for Dwc {
fn init(&mut self) -> BoxFuture<'_, Result<()>> {
self._init().boxed()
}
fn root_hub(&mut self) -> Box<dyn HubOp> {
self.xhci.root_hub()
}
fn create_event_handler(&mut self) -> Box<dyn EventHandlerOp> {
Box::new(DwcEventHandler {
xhci: self.xhci.create_event_handler(),
_dwc: self.dwc_regs.clone(),
})
}
fn new_addressed_device<'a>(
&'a mut self,
addr: DeviceAddressInfo,
) -> BoxFuture<'a, Result<Box<dyn DeviceOp>>> {
self.xhci.new_addressed_device(addr)
}
fn kernel(&self) -> &Kernel {
self.xhci.kernel()
}
}
impl Deref for Dwc {
type Target = DwcParams;
fn deref(&self) -> &Self::Target {
&self.params
}
}
impl DerefMut for Dwc {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.params
}
}
pub struct DwcEventHandler {
xhci: Box<dyn EventHandlerOp>,
_dwc: Dwc3Regs,
}
impl EventHandlerOp for DwcEventHandler {
fn handle_event(&self) -> Event {
self.xhci.handle_event()
}
}