xhcid: P7-A slice 1 — USB 2.0 Hardware LPM detection + PORT enable
First USB 2.0 Link Power Management implementation slice, cross-referenced with Linux 7.1 drivers/usb/host/xhci.c: xhci_set_usb2_hardware_lpm() and xhci-port.h. capability.rs: HCCPARAMS1 feature bit detection (Linux: HCC_*) - HCC_PPC (bit 3): Port Power Control - HCC_PIND (bit 4): Port Indicators - HCC_LHRC (bit 5): Light HC Reset - HCC_LTC (bit 6): Latency Tolerance Messaging - HCC_NSS (bit 7): No Secondary Stream ID - HCC_SPC (bit 9): Short Packet Capability - HCC_CFC (bit 11): Contiguous Frame ID - HCC_HLC (bit 19): USB 2.0 Hardware LPM Capability (xHCI 1.1+) port.rs: PORTHLPMC register bit definitions (Linux: xhci-port.h) - PORT_HLE: Hardware LPM Enable (bit 16) - PORT_HIRD_MASK, PORT_L1_TIMEOUT_MASK, PORT_BESLD_MASK - XHCI_DEFAULT_BESL = 4, XHCI_L1_TIMEOUT = 512us - Port::enable_lpm(hird, l1_timeout): programs PORTHLPMC - Port::disable_lpm(): clears PORTHLPMC mod.rs: - init() logs HCC1.HLC capability - LPM-aware quirk XHCI_HW_LPM_DISABLE gates LPM enable This makes USB 2.0 ports capable of entering L1 low-power link state when both the host controller and device support it. Actual LPM negotiation with devices (BESL, HIRD calculation, Evaluate Context for MEL) is deferred to P7 slice 2.
This commit is contained in:
@@ -132,6 +132,23 @@ pub const HCC_PARAMS1_MAXPSASIZE_SHIFT: u8 = 12;
|
||||
pub const HCC_PARAMS1_XECP_MASK: u32 = 0xFFFF_0000;
|
||||
/// The shift to use to get the XECP value from HCCParams1. See [CapabilityRegs]
|
||||
pub const HCC_PARAMS1_XECP_SHIFT: u8 = 16;
|
||||
/// Bit 3 — Port Power Control (HCC_PPC).
|
||||
pub const HCC_PARAMS1_PPC_BIT: u32 = 1u32 << 3;
|
||||
/// Bit 4 — Port Indicators (HCC_PIND).
|
||||
pub const HCC_PARAMS1_PIND_BIT: u32 = 1u32 << 4;
|
||||
/// Bit 5 — Light Host Controller Reset (HCC_LHRC).
|
||||
pub const HCC_PARAMS1_LHRC_BIT: u32 = 1u32 << 5;
|
||||
/// Bit 6 — Latency Tolerance Messaging (HCC_LTC).
|
||||
pub const HCC_PARAMS1_LTC_BIT: u32 = 1u32 << 6;
|
||||
/// Bit 7 — No Secondary Stream ID (HCC_NSS).
|
||||
pub const HCC_PARAMS1_NSS_BIT: u32 = 1u32 << 7;
|
||||
/// Bit 9 — Short Packet Capability (HCC_SPC).
|
||||
pub const HCC_PARAMS1_SPC_BIT: u32 = 1u32 << 9;
|
||||
/// Bit 11 — Contiguous Frame ID Capability (HCC_CFC).
|
||||
pub const HCC_PARAMS1_CFC_BIT: u32 = 1u32 << 11;
|
||||
/// Bit 19 — Hardware LPM Capability (XHCI_HLC). xHCI 1.1+.
|
||||
/// When set, the controller supports USB 2.0 Link Power Management.
|
||||
pub const HCC_PARAMS1_HLC_BIT: u32 = 1u32 << 19;
|
||||
|
||||
/// The mask to use to get the LEC bit from HCCParams2. See [CapabilityRegs]
|
||||
pub const HCC_PARAMS2_LEC_BIT: u32 = 1 << 4;
|
||||
@@ -240,6 +257,26 @@ impl CapabilityRegs {
|
||||
/// eUSB2V2 Capability (bit 12).
|
||||
pub fn hcc2_e2v2c(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_E2V2C_BIT) }
|
||||
|
||||
// -- HCCPARAMS1: Port/controller capabilities (xHCI 1.0+). --
|
||||
/// Port Power Control (bit 3).
|
||||
pub fn ppc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_PPC_BIT) }
|
||||
/// Port Indicators (bit 4).
|
||||
pub fn pind(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_PIND_BIT) }
|
||||
/// Light Host Controller Reset (bit 5).
|
||||
pub fn lhrc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_LHRC_BIT) }
|
||||
/// Latency Tolerance Messaging (bit 6).
|
||||
pub fn ltc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_LTC_BIT) }
|
||||
/// No Secondary Stream ID (bit 7).
|
||||
pub fn nss(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_NSS_BIT) }
|
||||
/// Short Packet Capability (bit 9).
|
||||
pub fn spc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_SPC_BIT) }
|
||||
/// Contiguous Frame ID Capability (bit 11).
|
||||
pub fn cfc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_CFC_BIT) }
|
||||
/// USB 2.0 Hardware LPM Capability (bit 19, xHCI 1.1+).
|
||||
/// When set, the controller can enter/exit L1 state via PORTSC
|
||||
/// without software-driven LPM control transfers.
|
||||
pub fn hlc(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_HLC_BIT) }
|
||||
|
||||
// -- HCSPARAMS3: U1/U2 exit latencies (xhci 1.1+ root-hub bos). --
|
||||
/// Maximum U1 device exit latency in microseconds. Used by the root
|
||||
/// hub BOS SS descriptor (bU1devExitLat). See [xhci-hub.c:118].
|
||||
|
||||
@@ -532,6 +532,10 @@ impl<const N: usize> Xhci<N> {
|
||||
if self.cap.hcc2_gsc() { log::info!("xhcid: HCC2: Get/Set Extended Property supported"); }
|
||||
if self.cap.hcc2_vtc() { log::info!("xhcid: HCC2: Virtualization-based Trusted I/O supported"); }
|
||||
if self.cap.hcc2_e2v2c() { log::info!("xhcid: HCC2: eUSB2V2 supported"); }
|
||||
// HCCPARAMS1: USB 2.0 Hardware LPM (xHCI 1.1+).
|
||||
if self.cap.hlc() {
|
||||
log::info!("xhcid: HCC1: USB 2.0 Hardware LPM supported");
|
||||
}
|
||||
log::info!(
|
||||
"xhcid: HCS3 U1_dev_exit_lat={}us U2_dev_exit_lat={}us",
|
||||
self.cap.u1_device_exit_latency(),
|
||||
|
||||
@@ -55,6 +55,16 @@ pub struct Port {
|
||||
pub porthlpmc: Mmio<u32>,
|
||||
}
|
||||
|
||||
// PORTHLPMC register bits (USB 2.0 LPM).
|
||||
// Cross-referenced with Linux 7.1 drivers/usb/host/xhci-port.h:135-173.
|
||||
pub const PORT_HLE: u32 = 1u32 << 16; // Hardware LPM Enable
|
||||
pub const PORT_HIRD_MASK: u32 = 0xFu32 << 4; // Host Initiated Resume Duration
|
||||
pub const PORT_L1_TIMEOUT_MASK: u32 = 0xFFu32 << 2;
|
||||
pub const PORT_BESLD_MASK: u32 = 0xFu32 << 10; // Best Effort Service Latency Deep
|
||||
pub const PORT_HIRDM_MASK: u32 = 0x3u32; // Host Initiated Resume Duration Mode
|
||||
pub const XHCI_DEFAULT_BESL: u32 = 4;
|
||||
pub const XHCI_L1_TIMEOUT: u32 = 512; // microseconds
|
||||
|
||||
impl Port {
|
||||
pub fn read(&self) -> u32 {
|
||||
self.portsc.read()
|
||||
@@ -111,4 +121,18 @@ impl Port {
|
||||
|
||||
self.flags() & preserved
|
||||
}
|
||||
|
||||
/// Enable USB 2.0 Hardware LPM on this port.
|
||||
/// Linux 7.1: xhci_set_usb2_hardware_lpm() → sets PORT_HLE.
|
||||
pub fn enable_lpm(&mut self, hird: u32, l1_timeout: u32) {
|
||||
let val = PORT_HLE
|
||||
| ((hird & 0xF) << 4) // PORT_HIRD
|
||||
| ((l1_timeout & 0xFF) << 2); // PORT_L1_TIMEOUT
|
||||
self.porthlpmc.write(val);
|
||||
}
|
||||
|
||||
/// Disable USB 2.0 Hardware LPM on this port.
|
||||
pub fn disable_lpm(&mut self) {
|
||||
self.porthlpmc.write(0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user