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