Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| aba41cb5b2 | |||
| 475bf90eb9 | |||
| 33474c10d3 |
Generated
+20
@@ -2872,6 +2872,25 @@ dependencies = [
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_usb_dwc2"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"atomic_enum",
|
||||
"bytemuck",
|
||||
"device-api",
|
||||
"device-tree",
|
||||
"futures-util",
|
||||
"libk",
|
||||
"libk-mm",
|
||||
"libk-util",
|
||||
"log",
|
||||
"tock-registers",
|
||||
"ygg_driver_usb",
|
||||
"yggdrasil-abi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ygg_driver_usb_xhci"
|
||||
version = "0.1.0"
|
||||
@@ -3029,6 +3048,7 @@ dependencies = [
|
||||
"ygg_driver_nvme",
|
||||
"ygg_driver_pci",
|
||||
"ygg_driver_usb",
|
||||
"ygg_driver_usb_dwc2",
|
||||
"ygg_driver_usb_xhci",
|
||||
"ygg_driver_virtio_blk",
|
||||
"ygg_driver_virtio_gpu",
|
||||
|
||||
Binary file not shown.
+513
-1326
File diff suppressed because it is too large
Load Diff
@@ -58,6 +58,7 @@ device-tree.workspace = true
|
||||
kernel-arch-aarch64.workspace = true
|
||||
ygg_driver_bsp_arm.path = "driver/bsp/arm"
|
||||
ygg_driver_bsp_bcm283x.path = "driver/bsp/bcm283x"
|
||||
ygg_driver_usb_dwc2.path = "driver/usb/dwc2"
|
||||
|
||||
[target.'cfg(target_arch = "riscv64")'.dependencies]
|
||||
device-tree.workspace = true
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "ygg_driver_usb_dwc2"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi = { path = "../../../../lib/abi" }
|
||||
device-api = { path = "../../../lib/device-api", features = ["derive"] }
|
||||
ygg_driver_usb = { path = "../../bus/usb" }
|
||||
device-tree = { path = "../../../lib/device-tree" }
|
||||
|
||||
libk-util = { path = "../../../libk/libk-util" }
|
||||
libk-mm = { path = "../../../libk/libk-mm" }
|
||||
libk = { path = "../../../libk" }
|
||||
|
||||
async-trait.workspace = true
|
||||
log.workspace = true
|
||||
atomic_enum.workspace = true
|
||||
tock-registers.workspace = true
|
||||
bytemuck.workspace = true
|
||||
futures-util.workspace = true
|
||||
@@ -0,0 +1,222 @@
|
||||
#![no_std]
|
||||
|
||||
use core::{
|
||||
sync::atomic::{AtomicBool, AtomicU32},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{
|
||||
device::{Device, DeviceInitContext},
|
||||
interrupt::{InterruptHandler, IrqVector},
|
||||
};
|
||||
use futures_util::task::AtomicWaker;
|
||||
use libk::{error::Error, task::runtime};
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
|
||||
use libk_util::{event::BitmapEvent, sync::IrqSafeSpinlock};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
LocalRegisterCopy,
|
||||
};
|
||||
use yggdrasil_abi::bitflags;
|
||||
|
||||
use crate::{
|
||||
regs::{PortSpeed, Regs},
|
||||
vendor::Dwc2Impl,
|
||||
};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod regs;
|
||||
mod vendor;
|
||||
|
||||
pub struct Dwc2<H: Dwc2Impl> {
|
||||
imp: H,
|
||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||
name: Arc<str>,
|
||||
|
||||
channel_bitmask: AtomicU32,
|
||||
port_event_mask: BitmapEvent<AtomicWaker>,
|
||||
}
|
||||
|
||||
impl<H: Dwc2Impl + 'static> Dwc2<H> {
|
||||
pub unsafe fn new<N: Into<Arc<str>>>(
|
||||
imp: H,
|
||||
base: PhysicalAddress,
|
||||
name: N,
|
||||
) -> Result<Self, Error> {
|
||||
let name = name.into();
|
||||
let regs = IrqSafeSpinlock::new(unsafe { DeviceMemoryIo::map(base, Default::default()) }?);
|
||||
Ok(Self {
|
||||
imp,
|
||||
regs,
|
||||
name,
|
||||
channel_bitmask: AtomicU32::new(0),
|
||||
port_event_mask: BitmapEvent::new(AtomicWaker::new()),
|
||||
})
|
||||
}
|
||||
|
||||
fn signal_events(&self, channels: u16, ports: u32) {
|
||||
self.port_event_mask
|
||||
.signal(((channels as u64) << 32) | (ports as u64));
|
||||
}
|
||||
|
||||
async fn setup_port(self: Arc<Self>, speed: PortSpeed) -> Result<(), Error> {
|
||||
log::info!("{}: setup port", self.name);
|
||||
todo!()
|
||||
}
|
||||
|
||||
async fn wait_for_port_event(&self) -> LocalRegisterCopy<u32, regs::HPRT::Register> {
|
||||
LocalRegisterCopy::new(self.port_event_mask.wait_mask(0x2A).await as u32)
|
||||
}
|
||||
|
||||
async fn wait_for_channel_events(&self) -> u16 {
|
||||
(self.port_event_mask.wait_mask(0xFFFF00000000).await >> 32) as u16
|
||||
}
|
||||
|
||||
async fn wait_for_device(&self) -> PortSpeed {
|
||||
let hprt = self.regs.lock().HPRT.extract();
|
||||
// If already connected, begin init, if not, wait for connect change
|
||||
if !hprt.matches_all(regs::HPRT::PCSTS::SET) {
|
||||
loop {
|
||||
let event = self.wait_for_port_event().await;
|
||||
if event.matches_all(regs::HPRT::PCDET::SET) {
|
||||
log::info!("{}: port connection detected", self.name);
|
||||
break;
|
||||
} else {
|
||||
log::warn!("{}: unhandled port event {:#x}", self.name, event.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("{}: port connected", self.name);
|
||||
// Reset the port
|
||||
{
|
||||
let regs = self.regs.lock();
|
||||
regs.HPRT.modify(regs::HPRT::PRST::SET);
|
||||
}
|
||||
runtime::sleep(Duration::from_millis(10)).await;
|
||||
// Clear the reset
|
||||
{
|
||||
let regs = self.regs.lock();
|
||||
regs.HPRT.modify(regs::HPRT::PRST::CLEAR);
|
||||
}
|
||||
|
||||
// Wait for port enable status
|
||||
loop {
|
||||
let event = self.wait_for_port_event().await;
|
||||
|
||||
if event.matches_all(regs::HPRT::PENA::SET) {
|
||||
log::info!("{}: port enabled", self.name);
|
||||
break;
|
||||
}
|
||||
if event.matches_all(regs::HPRT::PCSTS::CLEAR) {
|
||||
todo!("Handle port disconnect");
|
||||
}
|
||||
}
|
||||
|
||||
let regs = self.regs.lock();
|
||||
match regs.HPRT.read_as_enum(regs::HPRT::PSPD) {
|
||||
Some(regs::HPRT::PSPD::Value::LowSpeed) => PortSpeed::LowSpeed,
|
||||
Some(regs::HPRT::PSPD::Value::FullSpeed) => PortSpeed::FullSpeed,
|
||||
Some(regs::HPRT::PSPD::Value::HighSpeed) => PortSpeed::HighSpeed,
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn softirq(self: Arc<Self>) -> Result<(), Error> {
|
||||
loop {
|
||||
// 4-9
|
||||
let speed = self.wait_for_device().await;
|
||||
|
||||
// 10. HFIR setup for PHY clk TODO
|
||||
// 11. Configure FSLPCS based on step 9 TODO
|
||||
// 12. GRXFSIZ to configure Rx FIFO size
|
||||
// 13. HNPTXFSIZ to configure non-periodic Tx FIFO
|
||||
// 14. HPTXFSIZ to configure periodic Tx FIFO
|
||||
if let Err(error) = self.clone().setup_port(speed).await {
|
||||
log::error!("{}: port error {:?}", self.name, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn setup(self: Arc<Self>) -> Result<(), Error> {
|
||||
log::info!("{}: init", self.name);
|
||||
let regs = self.regs.lock();
|
||||
|
||||
regs.soft_reset(Duration::from_secs(1)).await?;
|
||||
|
||||
// Common setup
|
||||
regs.GAHBCFG
|
||||
.write(regs::GAHBCFG::GINTMSK::SET + regs::GAHBCFG::DMAEN::SET);
|
||||
|
||||
// GUSBCTL
|
||||
// TODO HNP/SRP capability?
|
||||
// TODO OTG_FS/OTG_HS timeout calibration
|
||||
// TODO USB turnaround time
|
||||
|
||||
regs.GINTMSK.write(
|
||||
regs::GINTMSK::OTGINT::SET
|
||||
+ regs::GINTMSK::MMISM::SET
|
||||
+ regs::GINTMSK::USBRST::SET
|
||||
+ regs::GINTMSK::ENUMDNEM::SET
|
||||
+ regs::GINTMSK::OEPINT::SET
|
||||
+ regs::GINTMSK::IEPINT::SET
|
||||
// + regs::GINTMSK::PRTIM::SET
|
||||
+ regs::GINTMSK::DISCINT::SET,
|
||||
);
|
||||
|
||||
let mode = if regs.GINTSTS.matches_all(regs::GINTSTS::CMOD::Host) {
|
||||
"host"
|
||||
} else {
|
||||
log::warn!("TODO: device mode setup");
|
||||
"device"
|
||||
};
|
||||
log::info!("{}: operating in {} mode", self.name, mode);
|
||||
|
||||
// Host mode setup
|
||||
// 1. Enable HPRTINT
|
||||
regs.GINTMSK.modify(regs::GINTMSK::PRTIM::SET);
|
||||
// 2. Setup FS host
|
||||
regs.HCFG
|
||||
.write(regs::HCFG::FSLSS::CLEAR + regs::HCFG::FSLSPCS.val(1));
|
||||
// 3. Drive Vbus on the USB
|
||||
regs.HPRT.modify(regs::HPRT::PPWR::SET);
|
||||
|
||||
// 4. Wait for PCDET interrupt on HPRT0
|
||||
runtime::spawn(self.clone().softirq())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Dwc2Impl + 'static> Device for Dwc2<H> {
|
||||
unsafe fn init(self: Arc<Self>, cx: DeviceInitContext) -> Result<(), Error> {
|
||||
unsafe { self.imp.initialize_host_early(self.clone()) }?;
|
||||
runtime::spawn(self.clone().setup())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl<H: Dwc2Impl + 'static> InterruptHandler for Dwc2<H> {
|
||||
fn handle_irq(self: Arc<Self>, vector: IrqVector) -> bool {
|
||||
let regs = self.regs.lock();
|
||||
let gintsts = regs.take_interrupt();
|
||||
|
||||
let hprt = if gintsts.matches_all(regs::GINTSTS::HPRTINT::SET) {
|
||||
regs.take_port_status().get()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if hprt != 0 {
|
||||
self.signal_events(0, hprt);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
use core::time::Duration;
|
||||
|
||||
use libk::{error::Error, task::runtime, time};
|
||||
use tock_registers::{
|
||||
interfaces::{ReadWriteable, Readable, Writeable},
|
||||
register_bitfields, register_structs,
|
||||
registers::ReadWrite,
|
||||
LocalRegisterCopy,
|
||||
};
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
pub GAHBCFG [
|
||||
PTXFELVL OFFSET(8) NUMBITS(1) [],
|
||||
TXFELVL OFFSET(7) NUMBITS(1) [],
|
||||
DMAEN OFFSET(5) NUMBITS(1) [],
|
||||
HBSTLEN OFFSET(1) NUMBITS(4) [],
|
||||
GINTMSK OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
pub GUSBCFG [
|
||||
FDMOD OFFSET(30) NUMBITS(1) [],
|
||||
FHMOD OFFSET(29) NUMBITS(1) [],
|
||||
ULPIIPD OFFSET(25) NUMBITS(1) [],
|
||||
PTCI OFFSET(24) NUMBITS(1) [],
|
||||
PCCI OFFSET(23) NUMBITS(1) [],
|
||||
TSDPS OFFSET(22) NUMBITS(1) [],
|
||||
ULPIEVBUSI OFFSET(21) NUMBITS(1) [],
|
||||
ULPIEVBUSD OFFSET(20) NUMBITS(1) [],
|
||||
ULPICSM OFFSET(19) NUMBITS(1) [],
|
||||
ULPIAR OFFSET(18) NUMBITS(1) [],
|
||||
ULPIFSLS OFFSET(17) NUMBITS(1) [],
|
||||
PHYLPC OFFSET(15) NUMBITS(1) [],
|
||||
TRDT OFFSET(10) NUMBITS(4) [],
|
||||
HNPCAP OFFSET(9) NUMBITS(1) [],
|
||||
SRPCAP OFFSET(8) NUMBITS(1) [],
|
||||
PHYSEL OFFSET(6) NUMBITS(1) [],
|
||||
TOCAL OFFSET(0) NUMBITS(3) [],
|
||||
],
|
||||
pub GRSTCTL [
|
||||
AHBIDL OFFSET(31) NUMBITS(1) [],
|
||||
DMAREQ OFFSET(30) NUMBITS(1) [],
|
||||
TXFNUM OFFSET(6) NUMBITS(5) [],
|
||||
TXFFLSH OFFSET(5) NUMBITS(1) [],
|
||||
RXFFLSH OFFSET(4) NUMBITS(1) [],
|
||||
FCRST OFFSET(2) NUMBITS(1) [],
|
||||
PSRST OFFSET(1) NUMBITS(1) [],
|
||||
CSRST OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
pub GINTSTS [
|
||||
WKUPINT OFFSET(31) NUMBITS(1) [],
|
||||
SRQINT OFFSET(30) NUMBITS(1) [],
|
||||
DISCINT OFFSET(29) NUMBITS(1) [],
|
||||
CIDSCHG OFFSET(28) NUMBITS(1) [],
|
||||
LPMINT OFFSET(27) NUMBITS(1) [],
|
||||
PTXFE OFFSET(26) NUMBITS(1) [],
|
||||
HCINT OFFSET(25) NUMBITS(1) [],
|
||||
HPRTINT OFFSET(24) NUMBITS(1) [],
|
||||
RSTDET OFFSET(23) NUMBITS(1) [],
|
||||
DATAFSUSP OFFSET(22) NUMBITS(1) [],
|
||||
IPXFR OFFSET(21) NUMBITS(1) [],
|
||||
IISOIXFR OFFSET(20) NUMBITS(1) [],
|
||||
OEPINT OFFSET(19) NUMBITS(1) [],
|
||||
IEPINT OFFSET(18) NUMBITS(1) [],
|
||||
EOPF OFFSET(15) NUMBITS(1) [],
|
||||
ISOODRP OFFSET(14) NUMBITS(1) [],
|
||||
ENUMDNE OFFSET(13) NUMBITS(1) [],
|
||||
USBRST OFFSET(12) NUMBITS(1) [],
|
||||
USBSUSP OFFSET(11) NUMBITS(1) [],
|
||||
ESUSP OFFSET(10) NUMBITS(1) [],
|
||||
GONAKEFF OFFSET(7) NUMBITS(1) [],
|
||||
GINAKEFF OFFSET(6) NUMBITS(1) [],
|
||||
NPTXFE OFFSET(5) NUMBITS(1) [],
|
||||
RXFLVL OFFSET(4) NUMBITS(1) [],
|
||||
SOF OFFSET(3) NUMBITS(1) [],
|
||||
OTGINT OFFSET(2) NUMBITS(1) [],
|
||||
MMIS OFFSET(1) NUMBITS(1) [],
|
||||
CMOD OFFSET(0) NUMBITS(1) [
|
||||
Device = 0,
|
||||
Host = 1
|
||||
],
|
||||
],
|
||||
pub GINTMSK [
|
||||
WUIM OFFSET(31) NUMBITS(1) [],
|
||||
SRQIM OFFSET(30) NUMBITS(1) [],
|
||||
DISCINT OFFSET(29) NUMBITS(1) [],
|
||||
CIDSCHGM OFFSET(28) NUMBITS(1) [],
|
||||
LPMINTM OFFSET(27) NUMBITS(1) [],
|
||||
PTXFEM OFFSET(26) NUMBITS(1) [],
|
||||
HCIM OFFSET(25) NUMBITS(1) [],
|
||||
PRTIM OFFSET(24) NUMBITS(1) [],
|
||||
RSTDETM OFFSET(23) NUMBITS(1) [],
|
||||
FSUSPM OFFSET(22) NUMBITS(1) [],
|
||||
IPXFRM OFFSET(21) NUMBITS(1) [],
|
||||
IISOIXFRM OFFSET(20) NUMBITS(1) [],
|
||||
OEPINT OFFSET(19) NUMBITS(1) [],
|
||||
IEPINT OFFSET(18) NUMBITS(1) [],
|
||||
EOPFM OFFSET(15) NUMBITS(1) [],
|
||||
ISOODRPM OFFSET(14) NUMBITS(1) [],
|
||||
ENUMDNEM OFFSET(13) NUMBITS(1) [],
|
||||
USBRST OFFSET(12) NUMBITS(1) [],
|
||||
USBSUSPM OFFSET(11) NUMBITS(1) [],
|
||||
ESUSPM OFFSET(10) NUMBITS(1) [],
|
||||
GONAKEFFM OFFSET(7) NUMBITS(1) [],
|
||||
GINAKEFFM OFFSET(6) NUMBITS(1) [],
|
||||
NPTXFEM OFFSET(5) NUMBITS(1) [],
|
||||
RXFLVLM OFFSET(4) NUMBITS(1) [],
|
||||
SOFM OFFSET(3) NUMBITS(1) [],
|
||||
OTGINT OFFSET(2) NUMBITS(1) [],
|
||||
MMISM OFFSET(1) NUMBITS(1) [],
|
||||
],
|
||||
pub HCFG [
|
||||
FSLSS OFFSET(2) NUMBITS(1) [],
|
||||
FSLSPCS OFFSET(0) NUMBITS(2) [],
|
||||
],
|
||||
pub HPRT [
|
||||
PSPD OFFSET(17) NUMBITS(2) [
|
||||
HighSpeed = 0,
|
||||
FullSpeed = 1,
|
||||
LowSpeed = 2,
|
||||
],
|
||||
PTCTL OFFSET(13) NUMBITS(4) [],
|
||||
PPWR OFFSET(12) NUMBITS(1) [],
|
||||
PLSTS OFFSET(10) NUMBITS(2) [],
|
||||
PRST OFFSET(8) NUMBITS(1) [],
|
||||
PSUSP OFFSET(7) NUMBITS(1) [],
|
||||
PRES OFFSET(6) NUMBITS(1) [],
|
||||
POCCHNG OFFSET(5) NUMBITS(1) [],
|
||||
POCA OFFSET(4) NUMBITS(1) [],
|
||||
PENCHNG OFFSET(3) NUMBITS(1) [],
|
||||
PENA OFFSET(2) NUMBITS(1) [],
|
||||
PCDET OFFSET(1) NUMBITS(1) [],
|
||||
PCSTS OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
|
||||
pub HCCHARx [
|
||||
CHENA OFFSET(31) NUMBITS(1) [],
|
||||
CHDIS OFFSET(30) NUMBITS(1) [],
|
||||
ODDFRM OFFSET(29) NUMBITS(1) [],
|
||||
DAD OFFSET(22) NUMBITS(7) [],
|
||||
MCNT OFFSET(20) NUMBITS(2) [],
|
||||
EPTYP OFFSET(18) NUMBITS(2) [
|
||||
Control = 0,
|
||||
Isochronous = 1,
|
||||
Bulk = 2,
|
||||
Interrupt = 3
|
||||
],
|
||||
LSDEV OFFSET(17) NUMBITS(1) [],
|
||||
EPDIR OFFSET(15) NUMBITS(1) [
|
||||
Out = 0,
|
||||
In = 1
|
||||
],
|
||||
EPNUM OFFSET(11) NUMBITS(4) [],
|
||||
MPSIZ OFFSET(0) NUMBITS(11) [],
|
||||
],
|
||||
pub HCSPLTx [
|
||||
SPLITEN OFFSET(31) NUMBITS(1) [],
|
||||
COMPLSPLT OFFSET(16) NUMBITS(1) [],
|
||||
XACTPOS OFFSET(14) NUMBITS(2) [
|
||||
Mid = 0,
|
||||
End = 1,
|
||||
Begin = 2,
|
||||
All = 3,
|
||||
],
|
||||
HUBADDR OFFSET(7) NUMBITS(7) [],
|
||||
PRTADDR OFFSET(0) NUMBITS(7) [],
|
||||
],
|
||||
pub HCINTx [
|
||||
DTERR OFFSET(10) NUMBITS(1) [],
|
||||
FRMOR OFFSET(9) NUMBITS(1) [],
|
||||
BBERR OFFSET(8) NUMBITS(1) [],
|
||||
TXERR OFFSET(7) NUMBITS(1) [],
|
||||
NYET OFFSET(6) NUMBITS(1) [],
|
||||
ACK OFFSET(5) NUMBITS(1) [],
|
||||
NAK OFFSET(4) NUMBITS(1) [],
|
||||
STALL OFFSET(3) NUMBITS(1) [],
|
||||
AHBERR OFFSET(2) NUMBITS(1) [],
|
||||
CHH OFFSET(1) NUMBITS(1) [],
|
||||
XFRC OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
pub HCTSIZx [
|
||||
DPID OFFSET(29) NUMBITS(2) [
|
||||
DATA0 = 0,
|
||||
DATA2 = 1,
|
||||
DATA1 = 2,
|
||||
SETUP = 3
|
||||
],
|
||||
PKTCNT OFFSET(19) NUMBITS(10) [],
|
||||
XFRSIZ OFFSET(0) NUMBITS(19) []
|
||||
],
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
pub HostChannelRegs {
|
||||
(0x00 => pub HCCHARx: ReadWrite<u32, HCCHARx::Register>),
|
||||
(0x04 => pub HCSPLTx: ReadWrite<u32, HCSPLTx::Register>),
|
||||
(0x08 => pub HCINTx: ReadWrite<u32, HCINTx::Register>),
|
||||
(0x0C => pub HCINTMSKx: ReadWrite<u32, HCINTx::Register>),
|
||||
(0x10 => pub HCTSIZx: ReadWrite<u32, HCTSIZx::Register>),
|
||||
(0x14 => pub HCDMAx: ReadWrite<u32>),
|
||||
(0x18 => _0),
|
||||
(0x20 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
register_structs! {
|
||||
#[allow(non_snake_case)]
|
||||
pub Regs {
|
||||
(0x000 => pub GOTGCTL: ReadWrite<u32>),
|
||||
(0x004 => pub GOTGINT: ReadWrite<u32>),
|
||||
(0x008 => pub GAHBCFG: ReadWrite<u32, GAHBCFG::Register>),
|
||||
(0x00C => pub GUSBCFG: ReadWrite<u32, GUSBCFG::Register>),
|
||||
(0x010 => pub GRSTCTL: ReadWrite<u32, GRSTCTL::Register>),
|
||||
(0x014 => pub GINTSTS: ReadWrite<u32, GINTSTS::Register>),
|
||||
(0x018 => pub GINTMSK: ReadWrite<u32, GINTMSK::Register>),
|
||||
(0x01C => pub GRXSTSR: ReadWrite<u32>),
|
||||
(0x020 => pub GRXSTSP: ReadWrite<u32>),
|
||||
(0x024 => pub GRXFSIZ: ReadWrite<u32>),
|
||||
(0x028 => pub HNPTXFSIZ: ReadWrite<u32>),
|
||||
(0x02C => pub HNPTXSTS: ReadWrite<u32>),
|
||||
(0x030 => _0),
|
||||
(0x038 => pub GCCFG: ReadWrite<u32>),
|
||||
(0x03C => pub CID: ReadWrite<u32>),
|
||||
(0x040 => _1),
|
||||
(0x054 => pub GLPMCFG: ReadWrite<u32>),
|
||||
(0x058 => _2),
|
||||
(0x100 => pub HPTXFSIZ: ReadWrite<u32>),
|
||||
(0x104 => pub DIEPTXF_N: [ReadWrite<u32>; 8]),
|
||||
(0x124 => _3),
|
||||
(0x400 => pub HCFG: ReadWrite<u32, HCFG::Register>),
|
||||
(0x404 => pub HFIR: ReadWrite<u32>),
|
||||
(0x408 => pub HFNUM: ReadWrite<u32>),
|
||||
(0x40C => _4),
|
||||
(0x410 => pub HPTXSTS: ReadWrite<u32>),
|
||||
(0x414 => pub HAINT: ReadWrite<u32>),
|
||||
(0x418 => pub HAINTMSK: ReadWrite<u32>),
|
||||
(0x41C => _5),
|
||||
(0x440 => pub HPRT: ReadWrite<u32, HPRT::Register>),
|
||||
(0x444 => _6),
|
||||
(0x500 => pub CHANNELx: [HostChannelRegs; 16]),
|
||||
(0x700 => _7),
|
||||
(0x800 => _8),
|
||||
(0xF00 => @END),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Regs {}
|
||||
unsafe impl Sync for Regs {}
|
||||
|
||||
pub enum PortSpeed {
|
||||
LowSpeed,
|
||||
FullSpeed,
|
||||
HighSpeed,
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
pub async fn soft_reset(&self, timeout: Duration) -> Result<(), Error> {
|
||||
self.GRSTCTL.modify(GRSTCTL::CSRST::SET);
|
||||
|
||||
let deadline = time::monotonic_time() + timeout;
|
||||
let mut timeout = true;
|
||||
while time::monotonic_time() < deadline {
|
||||
if self.GRSTCTL.matches_all(GRSTCTL::CSRST::CLEAR) {
|
||||
timeout = false;
|
||||
break;
|
||||
}
|
||||
runtime::sleep(Duration::from_millis(20)).await;
|
||||
}
|
||||
if timeout {
|
||||
return Err(Error::TimedOut);
|
||||
}
|
||||
|
||||
// The spec wants the OS to wait for at least 3 PHY clocks
|
||||
runtime::sleep(Duration::from_millis(100)).await;
|
||||
|
||||
assert!(self.GRSTCTL.matches_all(GRSTCTL::AHBIDL::SET));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn take_interrupt(&self) -> LocalRegisterCopy<u32, GINTSTS::Register> {
|
||||
let intsts = self.GINTSTS.extract();
|
||||
self.GINTSTS.set(intsts.get());
|
||||
intsts
|
||||
}
|
||||
|
||||
pub fn take_port_status(&self) -> LocalRegisterCopy<u32, HPRT::Register> {
|
||||
let hprt = self.HPRT.extract();
|
||||
self.HPRT.set(hprt.get());
|
||||
hprt
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
use alloc::sync::Arc;
|
||||
use device_api::{clock::ClockHandle, device::Device, interrupt::IrqHandle};
|
||||
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
|
||||
use libk::error::Error;
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
|
||||
use crate::{regs::Regs, Dwc2};
|
||||
|
||||
pub trait Dwc2Impl: Send + Sync + Sized {
|
||||
unsafe fn initialize_host_early(&self, dwc2: Arc<Dwc2<Self>>) -> Result<(), Error>;
|
||||
async unsafe fn initialize_host(
|
||||
&self,
|
||||
dwc2: Arc<Dwc2<Self>>,
|
||||
regs: &DeviceMemoryIo<'_, Regs>,
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
pub struct Bcm2835Usb {
|
||||
clk_otg: ClockHandle,
|
||||
irq: IrqHandle,
|
||||
}
|
||||
|
||||
impl Dwc2Impl for Bcm2835Usb {
|
||||
unsafe fn initialize_host_early(&self, dwc2: Arc<Dwc2<Self>>) -> Result<(), Error> {
|
||||
// TODO PHY setup
|
||||
self.irq.register(dwc2)?;
|
||||
self.irq.enable()?;
|
||||
|
||||
self.clk_otg.enable()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async unsafe fn initialize_host(
|
||||
&self,
|
||||
dwc2: Arc<Dwc2<Self>>,
|
||||
regs: &DeviceMemoryIo<'_, Regs>,
|
||||
) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
device_tree_driver! {
|
||||
compatible: ["brcm,bcm2835-usb"],
|
||||
driver: {
|
||||
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
|
||||
let base = node.map_base(context, 0).unwrap();
|
||||
let clk_otg = node.named_clock("otg").unwrap();
|
||||
let irq = node.interrupt(0).unwrap();
|
||||
let name = node.name()?;
|
||||
|
||||
node.dump();
|
||||
|
||||
let imp = Bcm2835Usb {
|
||||
clk_otg,
|
||||
irq
|
||||
};
|
||||
let dwc2 = unsafe { Dwc2::new(imp, base, name) }
|
||||
.inspect_err(|e| log::error!("{name}: setup error {e:?}"))
|
||||
.ok()?;
|
||||
|
||||
Some(Arc::new(dwc2))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,6 +204,21 @@ impl<N: EventNotify> BitmapEvent<N> {
|
||||
self.notify.notify_all();
|
||||
}
|
||||
|
||||
pub async fn wait_mask(&self, mask: u64) -> u64 {
|
||||
let not_mask = !mask;
|
||||
poll_fn(|cx| {
|
||||
let state = self.value.fetch_and(not_mask, Ordering::AcqRel);
|
||||
if state & mask != 0 {
|
||||
self.notify.unsubscribe(cx.waker());
|
||||
Poll::Ready(state)
|
||||
} else {
|
||||
self.notify.subscribe(cx.waker());
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn wait(&self) -> u64 {
|
||||
poll_fn(|cx| {
|
||||
let state = self.value.swap(0, Ordering::AcqRel);
|
||||
|
||||
@@ -87,6 +87,8 @@ pub fn kinit() -> Result<(), Error> {
|
||||
|
||||
random::init();
|
||||
|
||||
loop {}
|
||||
|
||||
let root = setup_root().inspect_err(|error| {
|
||||
log::error!("Cannot setup root filesystem: {error:?}");
|
||||
})?;
|
||||
|
||||
@@ -77,6 +77,7 @@ cfg_if::cfg_if! {
|
||||
} else if #[cfg(target_arch = "aarch64")] {
|
||||
extern crate ygg_driver_bsp_arm;
|
||||
extern crate ygg_driver_bsp_bcm283x;
|
||||
extern crate ygg_driver_usb_dwc2;
|
||||
} else if #[cfg(target_arch = "riscv64")] {
|
||||
extern crate ygg_driver_bsp_riscv;
|
||||
extern crate ygg_driver_bsp_jh7110;
|
||||
|
||||
Reference in New Issue
Block a user