intel: universal plane programming + DP MST topology manager

plane_universal.rs: per-plane enable/disable with format+rotation
  XRGB8888, ARGB8888, NV12 format support
  0/90/180/270 rotation via PLANE_CTL bits
  Position, stride, surface address, colorkey programming

dp_mst.rs: Multi-Stream Transport topology management
  DPCD MST capability probe (DPCD 0x0021)
  Upstream MST enable (DPCD 0x0111)
  VCPI allocation/deallocation (payload table + allocate set)
  MstBranchDevice tracking for branch device enumeration

mod.rs: registered plane_universal and dp_mst modules
This commit is contained in:
2026-06-02 05:56:09 +03:00
parent cf38cff205
commit b85f07ad22
3 changed files with 191 additions and 1 deletions
@@ -0,0 +1,91 @@
use std::sync::Arc;
use log::{debug, info};
use redox_driver_sys::memory::MmioRegion;
use super::dp_aux::DpAux;
use crate::driver::{DriverError, Result};
const DP_MST_CAP_OFFSET: u32 = 0x0021;
const DP_MST_CTRL_OFFSET: u32 = 0x0111;
const DP_MST_CTRL_UPSTREAM_ENABLE: u8 = 1 << 0;
const DP_MST_CTRL_UP_REQ_EN: u8 = 1 << 1;
const DP_MST_VC_PAYLOAD_TABLE_SLOT: u32 = 0x02C0;
const DP_MST_VC_PAYLOAD_ALLOCATE_SET: u32 = 0x02C1;
const MAX_MST_BRANCH_DEVICES: usize = 8;
#[derive(Clone)]
pub struct MstTopologyManager {
mmio: Arc<MmioRegion>,
mst_capable: bool,
branch_devices: Vec<MstBranchDevice>,
allocated_vcpi: u8,
}
#[derive(Clone)]
pub struct MstBranchDevice {
pub peer_device_type: u8,
pub num_ports: u8,
pub mst_cap: bool,
}
impl MstTopologyManager {
pub fn new(mmio: Arc<MmioRegion>) -> Self {
Self {
mmio,
mst_capable: false,
branch_devices: Vec::new(),
allocated_vcpi: 0,
}
}
pub fn probe(&mut self, aux: &DpAux) -> Result<bool> {
match aux.read_dpcd(DP_MST_CAP_OFFSET, 1) {
Ok(data) if !data.is_empty() => {
self.mst_capable = data[0] & 0x01 != 0;
if self.mst_capable {
aux.write_dpcd(DP_MST_CTRL_OFFSET,
&[DP_MST_CTRL_UPSTREAM_ENABLE | DP_MST_CTRL_UP_REQ_EN])?;
info!("redox-drm-intel: DP MST topology enabled");
}
Ok(self.mst_capable)
}
_ => Ok(false),
}
}
pub fn allocate_vcpi(&mut self, aux: &DpAux, slot_count: u8, payload_id: u8) -> Result<()> {
if !self.mst_capable {
return Ok(());
}
let payload_table = DP_MST_VC_PAYLOAD_TABLE_SLOT;
aux.write_dpcd(payload_table + payload_id as u32, &[
slot_count,
payload_id,
])?;
aux.write_dpcd(DP_MST_VC_PAYLOAD_ALLOCATE_SET, &[
self.allocated_vcpi | (1 << payload_id),
])?;
self.allocated_vcpi |= 1 << payload_id;
debug!("redox-drm-intel: MST VCPI allocated — slot={} payload_id={}", slot_count, payload_id);
Ok(())
}
pub fn deallocate_vcpi(&mut self, aux: &DpAux, payload_id: u8) -> Result<()> {
if !self.mst_capable {
return Ok(());
}
self.allocated_vcpi &= !(1 << payload_id);
aux.write_dpcd(DP_MST_VC_PAYLOAD_ALLOCATE_SET, &[self.allocated_vcpi])?;
debug!("redox-drm-intel: MST VCPI deallocated — payload_id={}", payload_id);
Ok(())
}
pub fn is_mst_capable(&self) -> bool {
self.mst_capable
}
}
@@ -14,7 +14,7 @@ pub mod display_transcoder;
pub mod display_watermark;
pub mod dp_aux;
pub mod dp_link;
pub mod execbuffer;
pub mod dp_mst;
pub mod drrs;
pub mod execlists;
pub mod fbc;
@@ -33,6 +33,7 @@ pub mod lmem;
pub mod mocs;
pub mod panel_pps;
pub mod pch;
pub mod plane_universal;
pub mod psr2;
pub mod regs;
pub mod regs_gen4_7;
@@ -0,0 +1,98 @@
use std::sync::Arc;
use std::time::Instant;
use log::debug;
use redox_driver_sys::memory::MmioRegion;
use super::info::IntelDeviceInfo;
use crate::driver::Result;
use crate::kms::ModeInfo;
const PLANE_CTL_BASE: usize = 0x70180;
const PLANE_STRIDE_OFFSET: usize = 0x70188;
const PLANE_SURF_OFFSET: usize = 0x7019C;
const PLANE_OFFSET_OFFSET: usize = 0x701A4;
const PLANE_SIZE_OFFSET: usize = 0x70190;
const PLANE_KEYVAL_OFFSET: usize = 0x70194;
const PLANE_KEYMAX_OFFSET: usize = 0x701A0;
const PLANE_KEYMSK_OFFSET: usize = 0x70198;
const PLANE_STRIDE: usize = 0x1000;
const PLANE_CTL_ENABLE: u32 = 1 << 31;
const PLANE_CTL_GAMMA_DISABLE: u32 = 1 << 13;
const PLANE_CTL_PIPE_GAMMA_ENABLE: u32 = 1 << 30;
const PLANE_CTL_ROTATE_180: u32 = 1 << 15;
const PLANE_CTL_ROTATE_270: u32 = 2 << 15;
const PLANE_CTL_ROTATE_90: u32 = 3 << 15;
const PLANE_CTL_FORMAT_XRGB8888: u32 = 4 << 24;
const PLANE_CTL_FORMAT_ARGB8888: u32 = 6 << 24;
const PLANE_CTL_FORMAT_NV12: u32 = 9 << 24;
pub struct UniversalPlane {
mmio: Arc<MmioRegion>,
pipe: u8,
plane: u8,
}
impl UniversalPlane {
pub fn new(mmio: Arc<MmioRegion>, pipe: u8, plane: u8) -> Self {
Self { mmio, pipe, plane }
}
fn base_offset(&self) -> usize {
PLANE_CTL_BASE + self.plane as usize * PLANE_STRIDE
}
pub fn enable(&self, fb_gtt_addr: u64, stride: u32, width: u16, height: u16,
format: u32, rotation: u32) -> Result<()> {
let base = self.base_offset();
self.mmio.write32(base + PLANE_SURF_OFFSET, fb_gtt_addr as u32);
self.mmio.write32(base + PLANE_SURF_OFFSET + 4, (fb_gtt_addr >> 32) as u32);
self.mmio.write32(base + PLANE_STRIDE_OFFSET, stride);
self.mmio.write32(base + PLANE_SIZE_OFFSET,
((height as u32) << 16) | (width as u32));
let fmt = match format {
0 => PLANE_CTL_FORMAT_XRGB8888,
1 => PLANE_CTL_FORMAT_ARGB8888,
2 => PLANE_CTL_FORMAT_NV12,
_ => PLANE_CTL_FORMAT_XRGB8888,
};
let rot = match rotation {
90 => PLANE_CTL_ROTATE_90,
180 => PLANE_CTL_ROTATE_180,
270 => PLANE_CTL_ROTATE_270,
_ => 0,
};
let ctl = PLANE_CTL_ENABLE | PLANE_CTL_GAMMA_DISABLE | fmt | rot;
self.mmio.write32(base, ctl);
debug!("redox-drm-intel: plane enabled pipe={} plane={} {}x{} fmt={:#x} rot={}",
self.pipe, self.plane, width, height, fmt, rotation);
Ok(())
}
pub fn disable(&self) -> Result<()> {
let base = self.base_offset();
self.mmio.write32(base, 0);
Ok(())
}
pub fn set_position(&self, x: u32, y: u32) -> Result<()> {
let base = self.base_offset();
self.mmio.write32(base + PLANE_OFFSET_OFFSET, (y << 16) | (x & 0x1FFF));
Ok(())
}
pub fn set_colorkey(&self, min: u32, max: u32, mask: u32) -> Result<()> {
let base = self.base_offset();
self.mmio.write32(base + PLANE_KEYVAL_OFFSET, min);
self.mmio.write32(base + PLANE_KEYMAX_OFFSET, max);
self.mmio.write32(base + PLANE_KEYMSK_OFFSET, mask);
Ok(())
}
}