intel: Xe2/Arrow Lake support — regs_xe2.rs, device IDs, generation selection
Add Arrow Lake-P Arc Pro 130T/140T (0x7d51) and other Xe2 device IDs. Create Xe2 register table with correct forcewake (0xa188/0xdfc), DMC (0x80000 base), and DBUF/D2D registers. - info.rs: add GenXe2 generation (display ver 20, gt ver 20), 4 Arrow Lake device IDs, update generation gating for Xe2 (has_combo_phy, has_dbuf_slice, has_separate_transcoder = true; has_gmbus = false — Xe2 uses DP AUX for EDID) - regs_xe2.rs: Xe2Regs implementing IntelRegs trait with Xe2-specific forcewake, DMC offsets. Xe2LpdRegs struct for Xe2LPD display registers (DE_CAP, DFSM, DBUF_CTL, D2D_LINK_CTL) - mod.rs: dynamic register table selection based on generation (GenXe2 → Xe2Regs, default → Gen9Regs). GMBUS controller moved to Option — initialized only for non-Xe2 platforms. Import IntelGeneration for generation dispatch. Linux reference: xe_pci.c (INTEL_ARL_IDS), xe_gt_regs.h, intel_display_regs.h (XE2LPD_* defines) Compiled: library modules clean (pre-existing daemon errors unrelated)
This commit is contained in:
@@ -11,6 +11,7 @@ pub enum IntelGeneration {
|
||||
Gen9_5,
|
||||
Gen12,
|
||||
Gen12_7,
|
||||
GenXe2,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@@ -26,6 +27,7 @@ impl IntelGeneration {
|
||||
Self::Gen9_5 => 11,
|
||||
Self::Gen12 => 12,
|
||||
Self::Gen12_7 => 14,
|
||||
Self::GenXe2 => 20,
|
||||
Self::Unknown => 0,
|
||||
}
|
||||
}
|
||||
@@ -41,6 +43,7 @@ impl IntelGeneration {
|
||||
Self::Gen9_5 => 9,
|
||||
Self::Gen12 => 12,
|
||||
Self::Gen12_7 => 12,
|
||||
Self::GenXe2 => 20,
|
||||
Self::Unknown => 0,
|
||||
}
|
||||
}
|
||||
@@ -50,6 +53,7 @@ impl IntelGeneration {
|
||||
Self::Gen4 | Self::Gen5 => 2,
|
||||
Self::Gen6 | Self::Gen7 | Self::Gen8 => 3,
|
||||
Self::Gen9 | Self::Gen9_5 | Self::Gen12 | Self::Gen12_7 => 4,
|
||||
Self::GenXe2 => 4,
|
||||
Self::Unknown => 1,
|
||||
}
|
||||
}
|
||||
@@ -81,11 +85,12 @@ impl IntelDeviceInfo {
|
||||
| IntelGeneration::Gen9_5
|
||||
| IntelGeneration::Gen12
|
||||
| IntelGeneration::Gen12_7
|
||||
| IntelGeneration::GenXe2
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_gen12_or_later(&self) -> bool {
|
||||
matches!(self.generation, IntelGeneration::Gen12 | IntelGeneration::Gen12_7)
|
||||
matches!(self.generation, IntelGeneration::Gen12 | IntelGeneration::Gen12_7 | IntelGeneration::GenXe2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +148,10 @@ const DEVICE_ID_TABLE: &[DeviceIdEntry] = &[
|
||||
DeviceIdEntry { device_id: 0x7D60, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL") },
|
||||
DeviceIdEntry { device_id: 0x7D45, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL") },
|
||||
DeviceIdEntry { device_id: 0x7D67, gen: IntelGeneration::Gen12_7, platform_name: "Meteor Lake", dmc_fw_key: Some("MTL") },
|
||||
DeviceIdEntry { device_id: 0x7D41, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-U", dmc_fw_key: Some("ARL") },
|
||||
DeviceIdEntry { device_id: 0x7D51, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-P Arc Pro 130T/140T", dmc_fw_key: Some("ARL") },
|
||||
DeviceIdEntry { device_id: 0x7DD1, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-P", dmc_fw_key: Some("ARL") },
|
||||
DeviceIdEntry { device_id: 0xB640, gen: IntelGeneration::GenXe2, platform_name: "Arrow Lake-H", dmc_fw_key: Some("ARL") },
|
||||
];
|
||||
|
||||
pub fn device_info_from_id(device_id: u16) -> IntelDeviceInfo {
|
||||
@@ -154,14 +163,14 @@ pub fn device_info_from_id(device_id: u16) -> IntelDeviceInfo {
|
||||
display_version: gen.display_version(),
|
||||
gt_version: gen.gt_version(),
|
||||
num_pipes: gen.num_pipes(),
|
||||
num_ports: if gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7 { 6 } else { 4 },
|
||||
has_ddi: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7),
|
||||
has_dp_aux: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7),
|
||||
has_gmbus: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7),
|
||||
has_dmc: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7),
|
||||
has_combo_phy: matches!(gen, IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7),
|
||||
has_dbuf_slice: gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7,
|
||||
has_separate_transcoder: gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7,
|
||||
num_ports: if gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7 || gen == IntelGeneration::GenXe2 { 6 } else { 4 },
|
||||
has_ddi: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7 | IntelGeneration::GenXe2),
|
||||
has_dp_aux: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7 | IntelGeneration::GenXe2),
|
||||
has_gmbus: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5),
|
||||
has_dmc: matches!(gen, IntelGeneration::Gen9 | IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7 | IntelGeneration::GenXe2),
|
||||
has_combo_phy: matches!(gen, IntelGeneration::Gen9_5 | IntelGeneration::Gen12 | IntelGeneration::Gen12_7 | IntelGeneration::GenXe2),
|
||||
has_dbuf_slice: gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7 || gen == IntelGeneration::GenXe2,
|
||||
has_separate_transcoder: gen == IntelGeneration::Gen12 || gen == IntelGeneration::Gen12_7 || gen == IntelGeneration::GenXe2,
|
||||
dmc_fw_key: entry.dmc_fw_key,
|
||||
platform_name: entry.platform_name,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ pub mod gtt;
|
||||
pub mod info;
|
||||
pub mod regs;
|
||||
pub mod regs_gen9;
|
||||
pub mod regs_xe2;
|
||||
pub mod ring;
|
||||
|
||||
use std::collections::HashMap;
|
||||
@@ -31,9 +32,10 @@ use self::display_dmc::DmcFirmware;
|
||||
use self::display_power::DisplayPower;
|
||||
use self::gmbus::GmbusController;
|
||||
use self::gtt::IntelGtt;
|
||||
use self::info::{IntelDeviceInfo, device_info_from_id};
|
||||
use self::info::{IntelDeviceInfo, IntelGeneration, device_info_from_id};
|
||||
use self::regs::IntelRegs;
|
||||
use self::regs_gen9::Gen9Regs;
|
||||
use self::regs_xe2::Xe2Regs;
|
||||
use self::ring::{IntelRing, RingType};
|
||||
|
||||
const FORCEWAKE: usize = 0xA18C;
|
||||
@@ -54,7 +56,7 @@ pub struct IntelDriver {
|
||||
info: PciDeviceInfo,
|
||||
device_info: IntelDeviceInfo,
|
||||
mmio: Arc<MmioRegion>,
|
||||
regs: &'static Gen9Regs,
|
||||
regs: &'static dyn IntelRegs,
|
||||
irq_handle: Mutex<Option<InterruptHandle>>,
|
||||
display: IntelDisplay,
|
||||
gem: Mutex<GemManager>,
|
||||
@@ -63,7 +65,7 @@ pub struct IntelDriver {
|
||||
encoders: Mutex<Vec<Encoder>>,
|
||||
gtt: Mutex<IntelGtt>,
|
||||
ring: Mutex<IntelRing>,
|
||||
gmbus: GmbusController,
|
||||
gmbus: Option<GmbusController>,
|
||||
display_power: DisplayPower,
|
||||
dmc: DmcFirmware,
|
||||
cdclk: DisplayClock,
|
||||
@@ -119,16 +121,25 @@ impl IntelDriver {
|
||||
|
||||
let device_info = device_info_from_id(info.device_id);
|
||||
info!(
|
||||
"redox-drm: Intel {} detected (device {:#06x}, display ver {})",
|
||||
device_info.platform_name, info.device_id, device_info.display_version
|
||||
"redox-drm: Intel {} detected (device {:#06x}, display ver {}, gen {:?})",
|
||||
device_info.platform_name, info.device_id, device_info.display_version, device_info.generation
|
||||
);
|
||||
|
||||
let regs = &Gen9Regs;
|
||||
let regs: &'static dyn IntelRegs = match device_info.generation {
|
||||
IntelGeneration::GenXe2 => &Xe2Regs,
|
||||
_ => &Gen9Regs,
|
||||
};
|
||||
let mmio_arc = Arc::new(mmio);
|
||||
let display_mmio_arc = Arc::new(display_mmio);
|
||||
|
||||
let gmbus = GmbusController::new(display_mmio_arc.clone(), regs);
|
||||
gmbus.init()?;
|
||||
let gmbus = if device_info.has_gmbus {
|
||||
let ctrl = GmbusController::new(display_mmio_arc.clone(), regs);
|
||||
ctrl.init()?;
|
||||
Some(ctrl)
|
||||
} else {
|
||||
info!("redox-drm-intel: Xe2 platform — skipping GMBUS (uses DP AUX for EDID)");
|
||||
None
|
||||
};
|
||||
|
||||
let display_power = DisplayPower::new(mmio_arc.clone(), regs);
|
||||
display_power.init_domains()?;
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
use super::regs::IntelRegs;
|
||||
|
||||
pub struct Xe2Regs;
|
||||
|
||||
impl IntelRegs for Xe2Regs {
|
||||
fn forcewake_req(&self) -> usize { 0xa188 }
|
||||
fn forcewake_ack(&self) -> usize { 0xdfc }
|
||||
|
||||
fn power_well_ctl(&self) -> usize { 0x45400 }
|
||||
|
||||
fn cdclk_ctl(&self) -> usize { 0x46000 }
|
||||
|
||||
fn dmc_mmio_start(&self) -> usize { 0x80000 }
|
||||
fn dmc_mmio_end(&self) -> usize { 0x8FFFF }
|
||||
fn dmc_fw_base(&self) -> usize { 0x80008 }
|
||||
fn dmc_ctrl(&self) -> usize { 0x80020 }
|
||||
fn dmc_status(&self) -> usize { 0x80024 }
|
||||
fn dmc_sram_base(&self) -> usize { 0x10000 }
|
||||
|
||||
fn gmbus0(&self) -> usize { 0xC5100 }
|
||||
fn gmbus1(&self) -> usize { 0xC5104 }
|
||||
fn gmbus2(&self) -> usize { 0xC5108 }
|
||||
fn gmbus3(&self) -> usize { 0xC510C }
|
||||
fn gmbus4(&self) -> usize { 0xC5110 }
|
||||
fn gmbus5(&self) -> usize { 0xC5120 }
|
||||
|
||||
fn pipeconf(&self, pipe: u8) -> usize {
|
||||
0x70008 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn pipeconf_enable_mask(&self) -> u32 { 1 << 31 }
|
||||
|
||||
fn htotal(&self, pipe: u8) -> usize {
|
||||
0x60000 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn hblank(&self, pipe: u8) -> usize {
|
||||
0x60004 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn hsync(&self, pipe: u8) -> usize {
|
||||
0x60008 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn vtotal(&self, pipe: u8) -> usize {
|
||||
0x6000C + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn vblank(&self, pipe: u8) -> usize {
|
||||
0x60010 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn vsync(&self, pipe: u8) -> usize {
|
||||
0x60014 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn pipe_src(&self, pipe: u8) -> usize {
|
||||
0x6001C + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn pipe_stride(&self) -> usize { 0x1000 }
|
||||
|
||||
fn dspcntr(&self, pipe: u8) -> usize {
|
||||
0x70180 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn dspcntr_enable_mask(&self) -> u32 { 1 << 31 }
|
||||
fn dspsurf(&self, pipe: u8) -> usize {
|
||||
0x7019C + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn plane_size(&self, pipe: u8) -> usize {
|
||||
0x70190 + (pipe as usize) * 0x1000
|
||||
}
|
||||
|
||||
fn ddi_buf_ctl(&self, port: u8) -> usize {
|
||||
0x64000 + (port as usize) * 0x100
|
||||
}
|
||||
fn ddi_port_stride(&self) -> usize { 0x100 }
|
||||
|
||||
fn curcntr(&self, pipe: u8) -> usize {
|
||||
0x70080 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn curpos(&self, pipe: u8) -> usize {
|
||||
0x70084 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn curbase(&self, pipe: u8) -> usize {
|
||||
0x70088 + (pipe as usize) * 0x1000
|
||||
}
|
||||
|
||||
fn pipeframe_reg(&self, pipe: u8) -> usize {
|
||||
0x70040 + (pipe as usize) * 0x1000
|
||||
}
|
||||
fn pipeframe_count_mask(&self) -> u32 { 0x00FFFFFF }
|
||||
|
||||
fn gfx_flsh_cntl(&self) -> usize { 0x101008 }
|
||||
|
||||
fn pp_status(&self) -> usize { 0xC7200 }
|
||||
}
|
||||
|
||||
pub struct Xe2LpdRegs {
|
||||
pub de_cap: usize,
|
||||
pub dfsm: usize,
|
||||
pub dbuf_ctl: usize,
|
||||
pub d2d_link_ctl: usize,
|
||||
pub aux_ctl: usize,
|
||||
}
|
||||
|
||||
impl Xe2LpdRegs {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
de_cap: 0x41100,
|
||||
dfsm: 0x51000,
|
||||
dbuf_ctl: 0x45008,
|
||||
d2d_link_ctl: 0x64200,
|
||||
aux_ctl: 0x64010,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_xe2_forcewake() {
|
||||
let regs = Xe2Regs;
|
||||
assert_eq!(regs.forcewake_req(), 0xa188);
|
||||
assert_ne!(regs.forcewake_req(), 0xA18C);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_xe2_dmc() {
|
||||
let regs = Xe2Regs;
|
||||
assert_eq!(regs.dmc_mmio_start(), 0x80000);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user