diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_power.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_power.rs index dec7d5b839..a4ed363b29 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_power.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_power.rs @@ -4,73 +4,105 @@ use std::time::{Duration, Instant}; use log::{debug, info, warn}; use redox_driver_sys::memory::MmioRegion; +use super::info::IntelDeviceInfo; use super::regs::IntelRegs; use crate::driver::Result; use crate::driver::DriverError; const POWER_WELL_TIMEOUT_MS: u64 = 20; +const HSW_PWR_WELL_CTL1: usize = 0x45400; +const HSW_PWR_WELL_CTL2: usize = 0x45404; +const ICL_PWR_WELL_CTL_AUX1: usize = 0x45440; +const ICL_PWR_WELL_CTL_AUX2: usize = 0x45444; +const ICL_PWR_WELL_CTL_DDI1: usize = 0x45450; +const ICL_PWR_WELL_CTL_DDI2: usize = 0x45454; +const DC_STATE_EN: usize = 0x45504; + +const PW_REQ: u32 = 0x2; +const PW_STATE: u32 = 0x1; const SKL_PW1_MASK: u32 = 1 << 0; const SKL_PW2_MASK: u32 = 1 << 1; -const SKL_DDI_A_IO_MASK: u32 = 1 << 2; -const SKL_DDI_B_IO_MASK: u32 = 1 << 3; -const SKL_DDI_C_IO_MASK: u32 = 1 << 4; -const SKL_DDI_D_IO_MASK: u32 = 1 << 5; -const SKL_DDI_E_IO_MASK: u32 = 1 << 6; -const SKL_AUX_A_MASK: u32 = 1 << 8; -const SKL_AUX_B_MASK: u32 = 1 << 9; -const SKL_AUX_C_MASK: u32 = 1 << 10; -const SKL_AUX_D_MASK: u32 = 1 << 11; - -const DISPLAY_REQUIRED_WELLS: u32 = - SKL_PW1_MASK - | SKL_PW2_MASK - | SKL_DDI_A_IO_MASK - | SKL_DDI_B_IO_MASK - | SKL_DDI_C_IO_MASK - | SKL_DDI_D_IO_MASK - | SKL_DDI_E_IO_MASK - | SKL_AUX_A_MASK - | SKL_AUX_B_MASK - | SKL_AUX_C_MASK - | SKL_AUX_D_MASK; +const SKL_DDI_MASK: u32 = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); +const SKL_AUX_MASK: u32 = (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11); +const SKL_ALL_WELLS: u32 = SKL_PW1_MASK | SKL_PW2_MASK | SKL_DDI_MASK | SKL_AUX_MASK; pub struct DisplayPower { mmio: Arc, regs: &'static dyn IntelRegs, + is_xe2: bool, } impl DisplayPower { - pub fn new(mmio: Arc, regs: &'static dyn IntelRegs) -> Self { - Self { mmio, regs } + pub fn new(mmio: Arc, regs: &'static dyn IntelRegs, device_info: &IntelDeviceInfo) -> Self { + let is_xe2 = device_info.generation == super::info::IntelGeneration::GenXe2; + Self { mmio, regs, is_xe2 } } pub fn init_domains(&self) -> Result<()> { - info!("redox-drm-intel: enabling display power wells"); + if self.is_xe2 { + self.init_xe2_domains() + } else { + self.init_gen9_domains() + } + } + fn init_gen9_domains(&self) -> Result<()> { + info!("redox-drm-intel: enabling Gen9 display power wells"); let ctl = self.regs.power_well_ctl(); let current = self.mmio.read_u32(ctl); - - if current & DISPLAY_REQUIRED_WELLS == DISPLAY_REQUIRED_WELLS { - debug!("redox-drm-intel: display power wells already enabled ({:#010x})", current); + if current & SKL_ALL_WELLS == SKL_ALL_WELLS { + debug!("redox-drm-intel: power wells already enabled ({:#010x})", current); return Ok(()); } + self.mmio.write_u32(ctl, current | SKL_ALL_WELLS); + self.poll_well(ctl, SKL_ALL_WELLS, "Gen9") + } - self.mmio.write_u32(ctl, current | DISPLAY_REQUIRED_WELLS); + fn init_xe2_domains(&self) -> Result<()> { + info!("redox-drm-intel: enabling Xe2 display power wells"); + self.enable_xe2_well(HSW_PWR_WELL_CTL1, 0, "PW1")?; + self.enable_xe2_well(HSW_PWR_WELL_CTL1, 1, "PW2")?; + + self.mmio.write_u32(ICL_PWR_WELL_CTL_AUX1, + PW_REQ << 0 | PW_REQ << 2 | PW_REQ << 4 | PW_REQ << 6); + self.mmio.write_u32(ICL_PWR_WELL_CTL_DDI1, + PW_REQ << 0 | PW_REQ << 2 | PW_REQ << 4 | PW_REQ << 6); + + self.poll_well(ICL_PWR_WELL_CTL_AUX1, + PW_STATE | PW_STATE << 2 | PW_STATE << 4 | PW_STATE << 6, + "Xe2 AUX")?; + + self.mmio.write_u32(DC_STATE_EN, self.mmio.read_u32(DC_STATE_EN) | 0x1); + info!("redox-drm-intel: Xe2 display power domains enabled"); + Ok(()) + } + + fn enable_xe2_well(&self, reg: usize, idx: u32, name: &str) -> Result<()> { + let req_bit = PW_REQ << (idx * 2); + let state_bit = PW_STATE << (idx * 2); + let current = self.mmio.read_u32(reg); + if current & state_bit != 0 { + debug!("redox-drm-intel: {} power well already enabled", name); + return Ok(()); + } + self.mmio.write_u32(reg, current | req_bit); + self.poll_well(reg, state_bit, name) + } + + fn poll_well(&self, reg: usize, mask: u32, name: &str) -> Result<()> { let deadline = Instant::now() + Duration::from_millis(POWER_WELL_TIMEOUT_MS); loop { - let status = self.mmio.read_u32(ctl); - if status & DISPLAY_REQUIRED_WELLS == DISPLAY_REQUIRED_WELLS { - info!("redox-drm-intel: display power wells enabled ({:#010x})", status); + let status = self.mmio.read_u32(reg); + if status & mask == mask { + debug!("redox-drm-intel: {} power well ready ({:#010x})", name, status); return Ok(()); } if Instant::now() > deadline { - warn!("redox-drm-intel: power well enable timeout — current: {:#010x}, expected: {:#010x}", - status, DISPLAY_REQUIRED_WELLS); + warn!("redox-drm-intel: {} power well timeout: {:#010x}", name, status); return Err(DriverError::Other(format!( - "power well enable timeout: {:#010x} vs {:#010x}", - status, DISPLAY_REQUIRED_WELLS + "{} power well timeout: {:#010x}", name, status ))); } std::hint::spin_loop(); @@ -78,8 +110,14 @@ impl DisplayPower { } pub fn is_display_ready(&self) -> bool { - let ctl = self.regs.power_well_ctl(); - let status = self.mmio.read_u32(ctl); - status & DISPLAY_REQUIRED_WELLS == DISPLAY_REQUIRED_WELLS + if self.is_xe2 { + let pw1 = self.mmio.read_u32(HSW_PWR_WELL_CTL1); + let aux = self.mmio.read_u32(ICL_PWR_WELL_CTL_AUX1); + (pw1 & PW_STATE) != 0 && (aux & PW_STATE) != 0 + } else { + let ctl = self.regs.power_well_ctl(); + let status = self.mmio.read_u32(ctl); + status & SKL_ALL_WELLS == SKL_ALL_WELLS + } } } diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs index 5ede6ec990..edc27c5d36 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs @@ -164,7 +164,7 @@ impl IntelDriver { None }; - let display_power = DisplayPower::new(mmio_arc.clone(), regs); + let display_power = DisplayPower::new(mmio_arc.clone(), regs, &device_info); display_power.init_domains()?; let dmc = DmcFirmware::new(mmio_arc.clone(), regs); diff --git a/local/sources/base b/local/sources/base index 4327f0b48b..12eb4be1c7 160000 --- a/local/sources/base +++ b/local/sources/base @@ -1 +1 @@ -Subproject commit 4327f0b48b66ca6682b5d7aab6229f6ec09f4873 +Subproject commit 12eb4be1c7f9334d8ec2599d84476f2967ddb668