intel: bandwidth calc, ALPM, panel fitter — remaining MINOR items

bandwidth.rs: link bandwidth computation
  compute_data_rate per mode+bpp
  compute_required_lanes for DP link negotiation
  compute_dbuf_blocks per display buffer configuration

alpm.rs: Adaptive Link Power Management
  ALPM_CTL enable/disable per DP port
  Link power state monitoring via ALPM_STATUS

panel_fitter.rs: Panel fitting / scaling mode
  compute_panel_fitter for non-native resolution handling
  ScalingMode enum: None/FullScreen/Center/FullAspect
  Aspect ratio-aware destination rectangle computation
This commit is contained in:
2026-06-02 06:12:38 +03:00
parent 483a40d318
commit e2253df39a
3 changed files with 157 additions and 0 deletions
@@ -0,0 +1,50 @@
use std::sync::Arc;
use log::debug;
use redox_driver_sys::memory::MmioRegion;
use super::info::IntelDeviceInfo;
use crate::driver::Result;
const ALPM_CTL_BASE: usize = 0x60100;
const ALPM_CTL_ENABLE: u32 = 1 << 31;
const ALPM_STATUS_BASE: usize = 0x60104;
const ALPM_STATUS_ACTIVE: u32 = 1 << 0;
pub struct AlpmState {
mmio: Arc<MmioRegion>,
enabled: bool,
port: u8,
}
impl AlpmState {
pub fn new(mmio: Arc<MmioRegion>, _device_info: &IntelDeviceInfo, port: u8) -> Self {
Self { mmio, enabled: false, port }
}
pub fn enable(&mut self) -> Result<()> {
if self.enabled {
return Ok(());
}
let ctl = ALPM_CTL_BASE + self.port as usize * 0x100;
self.mmio.write32(ctl, ALPM_CTL_ENABLE);
self.enabled = true;
debug!("redox-drm-intel: ALPM enabled on port {}", self.port);
Ok(())
}
pub fn disable(&mut self) -> Result<()> {
if !self.enabled {
return Ok(());
}
let ctl = ALPM_CTL_BASE + self.port as usize * 0x100;
self.mmio.write32(ctl, 0);
self.enabled = false;
Ok(())
}
pub fn is_active(&self) -> bool {
let status = ALPM_STATUS_BASE + self.port as usize * 0x100;
self.mmio.read32(status) & ALPM_STATUS_ACTIVE != 0
}
}
@@ -0,0 +1,41 @@
use super::info::IntelDeviceInfo;
use crate::kms::ModeInfo;
pub struct BandwidthInfo {
pub data_rate_kbps: u64,
pub required_lanes: u8,
pub link_rate_khz: u32,
}
pub fn compute_data_rate(mode: &ModeInfo, bpp: u32) -> u64 {
let pixel_clock = mode.clock as u64 * 1000;
let htotal = mode.htotal as u64;
let vtotal = mode.vtotal as u64;
pixel_clock * bpp as u64 * htotal * vtotal / (htotal * vtotal * 8)
}
pub fn compute_required_lanes(data_rate_kbps: u64, max_link_rate_khz: u32) -> u8 {
let lane_capacity = max_link_rate_khz as u64;
let lanes = (data_rate_kbps + lane_capacity - 1) / lane_capacity;
lanes.min(4) as u8
}
pub fn compute_dbuf_blocks(mode: &ModeInfo, device_info: &IntelDeviceInfo) -> u32 {
let pixel_rate_khz = mode.clock;
let dbuf_slices: u32 = if device_info.is_gen12_or_later() { 2 } else { 1 };
let htotal = mode.htotal as u32;
let vtotal = mode.vtotal as u32;
let active_area = mode.hdisplay as u32 * mode.vdisplay as u32;
let frame_area = htotal * vtotal;
if frame_area == 0 { return 0; }
let ratio = (active_area as u64 * 100 / frame_area as u64) as u32;
let blocks = if ratio > 95 {
dbuf_slices * 4
} else if ratio > 75 {
dbuf_slices * 3
} else {
dbuf_slices * 2
};
blocks.min(8)
}
@@ -0,0 +1,66 @@
use super::info::IntelDeviceInfo;
use crate::kms::ModeInfo;
pub struct PanelFitterConfig {
pub enabled: bool,
pub src_width: u16,
pub src_height: u16,
pub dst_width: u16,
pub dst_height: u16,
pub scaling_mode: ScalingMode,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ScalingMode {
None,
FullScreen,
Center,
FullAspect,
}
pub fn compute_panel_fitter(mode: &ModeInfo, panel_native: Option<&ModeInfo>,
device_info: &IntelDeviceInfo) -> PanelFitterConfig {
let native = match panel_native {
Some(n) => n,
None => return PanelFitterConfig {
enabled: false, src_width: mode.hdisplay, src_height: mode.vdisplay,
dst_width: mode.hdisplay, dst_height: mode.vdisplay,
scaling_mode: ScalingMode::None,
},
};
let need_scaling = mode.hdisplay != native.hdisplay
|| mode.vdisplay != native.vdisplay;
if !need_scaling || !device_info.is_gen12_or_later() {
return PanelFitterConfig {
enabled: false,
src_width: mode.hdisplay, src_height: mode.vdisplay,
dst_width: mode.hdisplay, dst_height: mode.vdisplay,
scaling_mode: ScalingMode::None,
};
}
let src_aspect = mode.hdisplay as f32 / mode.vdisplay as f32;
let dst_aspect = native.hdisplay as f32 / native.vdisplay as f32;
let (dst_w, dst_h, mode_) = if (src_aspect - dst_aspect).abs() < 0.01 {
(native.hdisplay, native.vdisplay, ScalingMode::FullScreen)
} else {
let h = (native.hdisplay as f32 * mode.vdisplay as f32
/ mode.hdisplay as f32) as u16;
if h <= native.vdisplay {
let x = (native.hdisplay - ((h as f32 * src_aspect) as u16)) / 2;
(native.hdisplay.saturating_sub(x * 2), h, ScalingMode::FullAspect)
} else {
(native.hdisplay, native.vdisplay, ScalingMode::FullScreen)
}
};
PanelFitterConfig {
enabled: true,
src_width: mode.hdisplay, src_height: mode.vdisplay,
dst_width: dst_w, dst_height: dst_h,
scaling_mode: mode_,
}
}