From b21494dacf15c0cb09ae518c5253a10e82d4e55f Mon Sep 17 00:00:00 2001 From: Admin Pupkin Date: Sat, 30 May 2026 09:24:55 +0300 Subject: [PATCH] intel: transcoder programming for Xe2/Gen12+ (Phase 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add display_transcoder.rs — TRANS_DDI_FUNC_CTL programming for platforms with separate transcoders (Xe2/Gen12+ where pipe != transcoder). - Transcoder::configure(): program TRANS_DDI_FUNC_CTL (0x60400 + 0x1000 per transcoder) with DDI select, DP/HDMI mode select, port width (1/2/4 lanes), and enable bit - disable(): clear TRANS_DDI_FUNC_ENABLE - is_enabled(): check TRANS_DDI_FUNC_ENABLE status - EDP transcoder at 0x6F400 for pipe 3 Wire into IntelDriver::set_crtc — configure transcoder after modesetting, using pipe.port and TransDdiMode::Dp with 4 lanes. Only active when has_separate_transcoder == true. Linux reference: intel_ddi.c (TRANS_DDI_FUNC_CTL programming) --- .../src/drivers/intel/display_transcoder.rs | 90 +++++++++++++++++++ .../redox-drm/source/src/drivers/intel/mod.rs | 11 +++ 2 files changed, 101 insertions(+) create mode 100644 local/recipes/gpu/redox-drm/source/src/drivers/intel/display_transcoder.rs diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_transcoder.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_transcoder.rs new file mode 100644 index 0000000000..61a0ee868e --- /dev/null +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/display_transcoder.rs @@ -0,0 +1,90 @@ +use std::sync::Arc; + +use log::{debug, info}; +use redox_driver_sys::memory::MmioRegion; + +use super::info::IntelDeviceInfo; +use crate::driver::Result; + +const TRANS_DDI_FUNC_CTL_BASE: usize = 0x60400; +const TRANS_STRIDE: usize = 0x1000; +const TRANS_DDI_FUNC_CTL_EDP: usize = 0x6F400; + +const TRANS_DDI_FUNC_ENABLE: u32 = 1 << 31; +const TRANS_DDI_SELECT_MASK: u32 = 0x7 << 28; +const TRANS_DDI_MODE_SELECT_MASK: u32 = 0x7 << 24; +const TRANS_DDI_PORT_WIDTH_X1: u32 = 0 << 1; +const TRANS_DDI_PORT_WIDTH_X2: u32 = 1 << 1; +const TRANS_DDI_PORT_WIDTH_X4: u32 = 3 << 1; + +const TRANS_DDI_DP_MODE: u32 = 2 << 24; +const TRANS_DDI_HDMI_MODE: u32 = 3 << 24; + +pub enum TransDdiMode { + Dp, + Hdmi, +} + +pub struct Transcoder { + mmio: Arc, + has_separate_transcoder: bool, +} + +impl Transcoder { + pub fn new(mmio: Arc, device_info: &IntelDeviceInfo) -> Self { + let has_separate_transcoder = device_info.has_separate_transcoder; + Self { mmio, has_separate_transcoder } + } + + pub fn configure(&self, pipe: u8, port: u8, mode: TransDdiMode, lane_count: u8) -> Result<()> { + if !self.has_separate_transcoder { + return Ok(()); + } + + let ddi_func_ctl = if pipe == 3 { TRANS_DDI_FUNC_CTL_EDP } + else { TRANS_DDI_FUNC_CTL_BASE + (pipe as usize) * TRANS_STRIDE }; + + let mut ctl = 0u32; + + let ddi_select = (port as u32) << 28; + ctl |= ddi_select; + + let mode_select = match mode { + TransDdiMode::Dp => TRANS_DDI_DP_MODE, + TransDdiMode::Hdmi => TRANS_DDI_HDMI_MODE, + }; + ctl |= mode_select; + + let width = match lane_count { + 4 => TRANS_DDI_PORT_WIDTH_X4, + 2 => TRANS_DDI_PORT_WIDTH_X2, + _ => TRANS_DDI_PORT_WIDTH_X1, + }; + ctl |= width; + + ctl |= TRANS_DDI_FUNC_ENABLE; + + self.mmio.write_u32(ddi_func_ctl, ctl); + + info!("redox-drm-intel: transcoder {} configured (port {}, {:?}, {} lanes, ctl {:#010x})", + pipe, port, mode, lane_count, ctl); + Ok(()) + } + + pub fn disable(&self, pipe: u8) -> Result<()> { + if !self.has_separate_transcoder { return Ok(()); } + let ddi_func_ctl = if pipe == 3 { TRANS_DDI_FUNC_CTL_EDP } + else { TRANS_DDI_FUNC_CTL_BASE + (pipe as usize) * TRANS_STRIDE }; + self.mmio.write_u32(ddi_func_ctl, 0); + debug!("redox-drm-intel: transcoder {} disabled", pipe); + Ok(()) + } + + pub fn is_enabled(&self, pipe: u8) -> bool { + if !self.has_separate_transcoder { return true; } + let ddi_func_ctl = if pipe == 3 { TRANS_DDI_FUNC_CTL_EDP } + else { TRANS_DDI_FUNC_CTL_BASE + (pipe as usize) * TRANS_STRIDE }; + let val = self.mmio.read_u32(ddi_func_ctl); + val & TRANS_DDI_FUNC_ENABLE != 0 + } +} diff --git a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs index 38622b5d6e..1687e29bb0 100644 --- a/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs +++ b/local/recipes/gpu/redox-drm/source/src/drivers/intel/mod.rs @@ -6,6 +6,7 @@ pub mod display_combo_phy; pub mod display_dmc; pub mod display_dpll; pub mod display_power; +pub mod display_transcoder; pub mod display_watermark; pub mod dp_aux; pub mod dp_link; @@ -46,6 +47,7 @@ use self::display_combo_phy::ComboPhy; use self::display_dmc::DmcFirmware; use self::display_dpll::DisplayPll; use self::display_power::DisplayPower; +use self::display_transcoder::{TransDdiMode, Transcoder}; use self::display_watermark::DisplayWatermark; use self::dp_aux::DpAux; use self::gmbus::GmbusController; @@ -89,6 +91,7 @@ pub struct IntelDriver { dp_aux: Vec, combo_phy: Option, display_power: DisplayPower, + transcoder: Transcoder, watermark: DisplayWatermark, dpll: DisplayPll, dmc: DmcFirmware, @@ -188,6 +191,8 @@ impl IntelDriver { let display_power = DisplayPower::new(mmio_arc.clone(), regs, &device_info); display_power.init_domains()?; + let transcoder = Transcoder::new(mmio_arc.clone(), &device_info); + let watermark = DisplayWatermark::new(mmio_arc.clone(), &device_info); watermark.init()?; @@ -284,6 +289,7 @@ impl IntelDriver { dp_aux, combo_phy, display_power, + transcoder, watermark, dpll, dmc, @@ -581,6 +587,11 @@ impl GpuDriver for IntelDriver { pipe.port = Some(self.connector_port(connectors[0])?); self.display.set_mode(&pipe, mode)?; + + if let Some(port) = pipe.port { + self.transcoder.configure(pipe.index, port, TransDdiMode::Dp, 4)?; + } + self.display.page_flip(&pipe, fb_addr)?; let mut crtcs = self