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