intel: transcoder programming for Xe2/Gen12+ (Phase 2)
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)
This commit is contained in:
@@ -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<MmioRegion>,
|
||||
has_separate_transcoder: bool,
|
||||
}
|
||||
|
||||
impl Transcoder {
|
||||
pub fn new(mmio: Arc<MmioRegion>, 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
|
||||
}
|
||||
}
|
||||
@@ -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<DpAux>,
|
||||
combo_phy: Option<ComboPhy>,
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user