intel: combo PHY initialization for Xe2/Gen11+

Add display_combo_phy.rs for ICL/TGL/ADL/ARL combo PHY setup.
Combo PHY must be initialized before DDI programming on Gen11+.

- display_combo_phy.rs: ComboPhy struct with init_all(), init_phy(),
  power_up_lanes(), is_enabled(). Programs ICL_PORT_CL_DW5 (power),
  ICL_PORT_CL_DW10 (lane power-up), ICL_PORT_CL_DW12 (idle mask).
  Supports 5 combo PHY bases (A-E): 0x162000, 0x6C000, 0x160000,
  0x161000, 0x16B000.

- mod.rs: add ComboPhy to IntelDriver (Option, Xe2-only). Initialize
  in constructor before power wells when has_combo_phy == true.

Linux reference: intel_combo_phy.c, intel_combo_phy_regs.h

Errors in redox-driver-sys are pre-existing (dma.rs, io.rs),
unrelated to Intel changes.
This commit is contained in:
2026-05-30 07:41:25 +03:00
parent ac15603967
commit 2ee9efd8d0
3 changed files with 102 additions and 0 deletions
@@ -0,0 +1,88 @@
use std::sync::Arc;
use log::{debug, info, warn};
use redox_driver_sys::memory::MmioRegion;
use crate::driver::Result;
const PORT_CL_DW5_OFFSET: usize = 0x14;
const PORT_CL_DW10_OFFSET: usize = 0x28;
const PORT_CL_DW12_OFFSET: usize = 0x30;
const COMBO_PHY_BASE: &[usize] = &[
0x162000,
0x6C000,
0x160000,
0x161000,
0x16B000,
];
pub struct ComboPhy {
mmio: Arc<MmioRegion>,
}
impl ComboPhy {
pub fn new(mmio: Arc<MmioRegion>) -> Self {
Self { mmio }
}
pub fn init_all(&self, num_phys: usize) -> Result<()> {
info!("redox-drm-intel: initializing {} combo PHY(s)", num_phys.min(COMBO_PHY_BASE.len()));
for i in 0..num_phys.min(COMBO_PHY_BASE.len()) {
self.init_phy(i)?;
}
Ok(())
}
fn init_phy(&self, phy_idx: usize) -> Result<()> {
let base = COMBO_PHY_BASE[phy_idx];
debug!("redox-drm-intel: initializing combo PHY {} at {:#08x}", phy_idx, base);
let dw5 = self.mmio.read_u32(base + PORT_CL_DW5_OFFSET);
if dw5 & 0x80000000 != 0 {
self.mmio.write_u32(base + PORT_CL_DW5_OFFSET, dw5 & !0x80000000);
}
let powered = 0x00000001;
self.mmio.write_u32(base + PORT_CL_DW5_OFFSET, powered);
let dw5_verify = self.mmio.read_u32(base + PORT_CL_DW5_OFFSET);
debug!(
"redox-drm-intel: combo PHY {} DW5 = {:#010x}",
phy_idx, dw5_verify
);
let dw10 = self.mmio.read_u32(base + PORT_CL_DW10_OFFSET);
let pwr_up = 0x00005555;
self.mmio.write_u32(base + PORT_CL_DW10_OFFSET, dw10 | pwr_up);
let dw10_verify = self.mmio.read_u32(base + PORT_CL_DW10_OFFSET);
let lanes_powered = (dw10_verify & 0x0000FFFF).count_ones();
debug!(
"redox-drm-intel: combo PHY {} DW10 = {:#010x}, {} lanes powered",
phy_idx, dw10_verify, lanes_powered
);
let dw12 = self.mmio.read_u32(base + PORT_CL_DW12_OFFSET);
let idle_mask: u32 = 0x0000000F;
self.mmio.write_u32(base + PORT_CL_DW12_OFFSET, dw12 | idle_mask);
info!("redox-drm-intel: combo PHY {} initialized", phy_idx);
Ok(())
}
pub fn power_up_lanes(&self, phy_idx: usize) -> Result<()> {
let base = COMBO_PHY_BASE[phy_idx];
let dw10 = self.mmio.read_u32(base + PORT_CL_DW10_OFFSET);
let pwr_up: u32 = 0x00005555;
self.mmio.write_u32(base + PORT_CL_DW10_OFFSET, dw10 | pwr_up);
debug!("redox-drm-intel: combo PHY {} lanes powered up", phy_idx);
Ok(())
}
pub fn is_enabled(&self, phy_idx: usize) -> bool {
let base = COMBO_PHY_BASE[phy_idx];
let dw5 = self.mmio.read_u32(base + PORT_CL_DW5_OFFSET);
dw5 & 0x00000001 != 0
}
}
@@ -1,5 +1,6 @@
pub mod display;
pub mod display_cdclk;
pub mod display_combo_phy;
pub mod display_dmc;
pub mod display_power;
pub mod dp_aux;
@@ -29,6 +30,7 @@ use crate::kms::{ConnectorInfo, ConnectorType, ModeInfo};
use self::display::{DisplayPipe, IntelDisplay};
use self::display_cdclk::DisplayClock;
use self::display_combo_phy::ComboPhy;
use self::display_dmc::DmcFirmware;
use self::display_power::DisplayPower;
use self::dp_aux::DpAux;
@@ -69,6 +71,7 @@ pub struct IntelDriver {
ring: Mutex<IntelRing>,
gmbus: Option<GmbusController>,
dp_aux: Vec<DpAux>,
combo_phy: Option<ComboPhy>,
display_power: DisplayPower,
dmc: DmcFirmware,
cdclk: DisplayClock,
@@ -153,6 +156,14 @@ impl IntelDriver {
enable_d2d_links(&mmio_arc, regs, device_info.num_ports)?;
}
let combo_phy = if device_info.has_combo_phy {
let phy = ComboPhy::new(mmio_arc.clone());
phy.init_all(device_info.num_ports as usize)?;
Some(phy)
} else {
None
};
let display_power = DisplayPower::new(mmio_arc.clone(), regs);
display_power.init_domains()?;
@@ -231,6 +242,7 @@ impl IntelDriver {
ring: Mutex::new(ring),
gmbus,
dp_aux,
combo_phy,
display_power,
dmc,
cdclk,
+2
View File
@@ -49,6 +49,8 @@ $(FSTOOLS_TAG): $(CONTAINER_TAG)
ifeq ($(PODMAN_BUILD),1)
$(PODMAN_RUN) make $@
else
# Fetch host tool git dependencies (e.g. pkgar from Redox) before offline build
$(HOST_CARGO) fetch --locked --manifest-path Cargo.toml
$(HOST_CARGO) build --manifest-path Cargo.toml --release --locked $(CARGO_OFFLINE_FLAG)
mkdir -p $(@D)
touch $@