intel: scaler/rotation, display power gating, GPU statistics

- cursor.rs: plane scaler (PS_CTRL/PS_WIN/PS_SIZE) with nearest filter,
  rotation property (0/90/180/270) via PLANE_ROT_CTL registers
- display_power.rs: gate_ddi_wells + gate_aux_wells per active port count
- gt.rs: GpuStats struct and gpu_stats() method for utilization reporting
This commit is contained in:
2026-06-01 21:55:45 +03:00
parent 53cab7e445
commit 25b9bd60c6
3 changed files with 116 additions and 1 deletions
@@ -4,7 +4,25 @@ use log::debug;
use redox_driver_sys::memory::MmioRegion;
use super::regs::IntelRegs;
use crate::driver::Result;
use crate::driver::{DriverError, Result};
const PS_CTRL_BASE: usize = 0x68180;
const PS_WIN_POS_BASE: usize = 0x68170;
const PS_WIN_SIZE_BASE: usize = 0x68174;
const PS_STRIDE: usize = 0x1000;
const PS_SCALER_ENABLE: u32 = 1 << 31;
const PS_SCALER_MODE_7X5: u32 = 0 << 28;
const PS_FILTER_SELECT: u32 = 1 << 23;
const PS_VERT_FILTER_MASK: u32 = 0x7 << 20;
const PS_HORZ_FILTER_MASK: u32 = 0x7 << 16;
const PS_VERT_FILTER_NEAREST: u32 = 0;
const PS_HORZ_FILTER_NEAREST: u32 = 0;
const PLANE_ROT_CTL_BASE: usize = 0x683C8;
const PLANE_ROT_CTL_ROTATE_90: u32 = 1 << 0;
const PLANE_ROT_CTL_ROTATE_180: u32 = 2 << 0;
const PLANE_ROT_CTL_ROTATE_270: u32 = 3 << 0;
pub struct CursorPlane {
mmio: Arc<MmioRegion>,
@@ -64,4 +82,44 @@ impl CursorPlane {
self.mmio.write32(pos_reg, pos_val);
Ok(())
}
pub fn enable_scaler(&self, pipe: u8, src_w: u16, src_h: u16, dst_w: u16, dst_h: u16) -> Result<()> {
let ps_ctrl = PS_CTRL_BASE + pipe as usize * PS_STRIDE;
let ps_win = PS_WIN_POS_BASE + pipe as usize * PS_STRIDE;
let ps_size = PS_WIN_SIZE_BASE + pipe as usize * PS_STRIDE;
let win_pos = (dst_w as u32 & 0x1FFF) | ((dst_h as u32 & 0x1FFF) << 16);
self.mmio.write32(ps_win, win_pos);
self.mmio.write32(ps_size, (src_w as u32) | ((src_h as u32) << 16));
let ctrl = PS_SCALER_ENABLE
| PS_SCALER_MODE_7X5
| PS_FILTER_SELECT
| PS_HORZ_FILTER_NEAREST
| PS_VERT_FILTER_NEAREST;
self.mmio.write32(ps_ctrl, ctrl);
debug!("redox-drm-intel: scaler enabled pipe={} {}x{}→{}x{}", pipe, src_w, src_h, dst_w, dst_h);
Ok(())
}
pub fn disable_scaler(&self, pipe: u8) -> Result<()> {
let ps_ctrl = PS_CTRL_BASE + pipe as usize * PS_STRIDE;
self.mmio.write32(ps_ctrl, 0);
debug!("redox-drm-intel: scaler disabled on pipe {}", pipe);
Ok(())
}
pub fn set_rotation(&self, pipe: u8, rotation: u32) -> Result<()> {
let rot = PLANE_ROT_CTL_BASE + pipe as usize * PS_STRIDE;
let val = match rotation {
0 => 0,
90 => PLANE_ROT_CTL_ROTATE_90,
180 => PLANE_ROT_CTL_ROTATE_180,
270 => PLANE_ROT_CTL_ROTATE_270,
_ => return Err(DriverError::InvalidArgument("valid rotation values: 0, 90, 180, 270")),
};
self.mmio.write32(rot, val);
debug!("redox-drm-intel: rotation {}° set on pipe {}", rotation, pipe);
Ok(())
}
}
@@ -120,4 +120,42 @@ impl DisplayPower {
status & SKL_ALL_WELLS == SKL_ALL_WELLS
}
}
pub fn gate_ddi_wells(&self, active_ports: u8) -> Result<()> {
if !self.is_xe2 {
let ctl = self.regs.power_well_ctl();
let current = self.mmio.read32(ctl);
let ddi_mask: u32 = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
let new = if active_ports == 0 {
current & !ddi_mask
} else {
current | ddi_mask
};
if new != current {
self.mmio.write32(ctl, new);
info!("redox-drm-intel: DDI power wells {} (active_ports={})",
if active_ports > 0 { "enabled" } else { "gated" }, active_ports);
}
}
Ok(())
}
pub fn gate_aux_wells(&self, active_aux: u8) -> Result<()> {
if !self.is_xe2 {
let ctl = self.regs.power_well_ctl();
let current = self.mmio.read32(ctl);
let aux_mask: u32 = (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11);
let new = if active_aux == 0 {
current & !aux_mask
} else {
current | aux_mask
};
if new != current {
self.mmio.write32(ctl, new);
info!("redox-drm-intel: AUX power wells {} (active_aux={})",
if active_aux > 0 { "enabled" } else { "gated" }, active_aux);
}
}
Ok(())
}
}
@@ -395,6 +395,16 @@ impl IntelGtManager {
self.target_freq * 50
}
pub fn gpu_stats(&self) -> GpuStats {
GpuStats {
wakeref_count: self.wakeref_count,
forcewake_active: self.forcewake_active,
rc6_enabled: self.rc6_enabled,
target_freq_mhz: self.target_freq * 50,
current_freq_mhz: self.current_frequency_mhz(),
}
}
fn init_cache_config(&mut self) -> Result<()> {
debug!("redox-drm-intel: configuring L3 cache");
@@ -487,3 +497,12 @@ impl IntelGtManager {
self.forcewake_active
}
}
#[derive(Clone, Debug)]
pub struct GpuStats {
pub wakeref_count: u32,
pub forcewake_active: bool,
pub rc6_enabled: bool,
pub target_freq_mhz: u32,
pub current_freq_mhz: u32,
}