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:
@@ -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,
|
||||
|
||||
@@ -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 $@
|
||||
|
||||
Reference in New Issue
Block a user