intel: D2D link enable for Xe2 display connection

Add enable_d2d_links() for Xe2/Arrow Lake platforms where the display
connection requires D2D (die-to-die) link setup before connector
detection. Programs DDI_BUF_CTL with D2D_LINK_ENABLE (bit 29) and
polls D2D_LINK_STATE (bit 28) for each port.

Called from IntelDriver::new() when generation == GenXe2, before
power well initialization.

Linux reference: intel_ddi.c (XE2LPD_DDI_BUF_D2D_LINK_ENABLE)

Compiled: 0 new errors
This commit is contained in:
2026-05-30 07:31:59 +03:00
parent 49084b8fbe
commit 5dd1178d83
@@ -149,6 +149,10 @@ impl IntelDriver {
.collect();
info!("redox-drm-intel: initialized {} DP AUX channels", dp_aux.len());
if device_info.generation == IntelGeneration::GenXe2 {
enable_d2d_links(&mmio_arc, regs, device_info.num_ports)?;
}
let display_power = DisplayPower::new(mmio_arc.clone(), regs);
display_power.init_domains()?;
@@ -227,6 +231,37 @@ impl IntelDriver {
cdclk,
})
}
}
fn enable_d2d_links(mmio: &Arc<MmioRegion>, regs: &dyn IntelRegs, num_ports: u8) -> Result<()> {
use std::time::{Duration, Instant};
const D2D_LINK_ENABLE: u32 = 1 << 29;
const D2D_LINK_STATE: u32 = 1 << 28;
const D2D_TIMEOUT_MS: u64 = 10;
for port in 0..num_ports {
let ddi_ctl = regs.ddi_buf_ctl(port);
let current = mmio.read_u32(ddi_ctl);
if current & D2D_LINK_STATE != 0 {
continue;
}
mmio.write_u32(ddi_ctl, current | D2D_LINK_ENABLE);
let deadline = Instant::now() + Duration::from_millis(D2D_TIMEOUT_MS);
loop {
let status = mmio.read_u32(ddi_ctl);
if status & D2D_LINK_STATE != 0 {
info!("redox-drm-intel: D2D link enabled on port {}", port);
break;
}
if Instant::now() > deadline {
warn!("redox-drm-intel: D2D link timeout on port {}", port);
break;
}
std::hint::spin_loop();
}
}
Ok(())
}
fn refresh_connectors(&self) -> Result<Vec<ConnectorInfo>> {
let (connectors, encoders) = detect_display_topology(&self.display)?;