diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/alpm.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/alpm.rs new file mode 100644 index 0000000000..4d08d0f63f --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/alpm.rs @@ -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, + enabled: bool, + port: u8, +} + +impl AlpmState { + pub fn new(mmio: Arc, _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 + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/bandwidth.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/bandwidth.rs new file mode 100644 index 0000000000..6e99559e1a --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/bandwidth.rs @@ -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) +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/panel_fitter.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/panel_fitter.rs new file mode 100644 index 0000000000..6ff250f932 --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/panel_fitter.rs @@ -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_, + } +}