From a4a0fbd1989cc0faf957693802f3e8c7ca5f480a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Dec 2025 11:48:47 +0100 Subject: [PATCH] drivers/graphics/ihdgd: Move edid probing into ddi.rs --- drivers/graphics/ihdgd/src/device/ddi.rs | 107 ++++++++++++++++++++ drivers/graphics/ihdgd/src/device/mod.rs | 118 ++--------------------- 2 files changed, 116 insertions(+), 109 deletions(-) diff --git a/drivers/graphics/ihdgd/src/device/ddi.rs b/drivers/graphics/ihdgd/src/device/ddi.rs index d5d3bb8ed7..67fb9cebb5 100644 --- a/drivers/graphics/ihdgd/src/device/ddi.rs +++ b/drivers/graphics/ihdgd/src/device/ddi.rs @@ -1,7 +1,14 @@ use common::io::{Io, MmioPtr, WriteOnly}; +use common::timeout::Timeout; +use embedded_hal::prelude::*; use std::sync::Arc; +use std::time::Duration; use syscall::error::{Error, Result, EIO}; +use crate::device::aux::Aux; +use crate::device::power::PowerWells; +use crate::device::{CallbackGuard, Gmbus, HalTimer}; + use super::{GpioPort, MmioRegion}; // IHD-OS-TGL-Vol 2c-12.21 DDI_AUX_CTL @@ -200,6 +207,106 @@ impl Ddi { self.port_reg((reg as usize) + (lane as usize)) } + pub fn probe_edid( + &mut self, + power_wells: &mut PowerWells, + gttmm: &MmioRegion, + gmbus: &mut Gmbus, + ) -> Result, Error> { + if let Some(port_comp_dw0) = self.port_comp(PortCompReg::Dw0) { + log::debug!("PORT_COMP_DW0_{}: {:08X}", self.name, port_comp_dw0.read()); + } + let mut aux_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { + //TODO: BLOCK TCCOLD? + + //TODO: the request can be shared by multiple DDIs + let pwr_well_ctl_aux_request = ddi.pwr_well_ctl_aux_request; + let pwr_well_ctl_aux_state = ddi.pwr_well_ctl_aux_state; + let mut pwr_well_ctl_aux = unsafe { MmioPtr::new(power_wells.ctl_aux.as_mut_ptr()) }; + let _pwr_guard = CallbackGuard::new( + &mut pwr_well_ctl_aux, + |pwr_well_ctl_aux| { + // Enable aux power + pwr_well_ctl_aux.writef(pwr_well_ctl_aux_request, true); + let timeout = Timeout::from_micros(1500); + while !pwr_well_ctl_aux.readf(pwr_well_ctl_aux_state) { + timeout.run().map_err(|()| { + log::debug!("timeout while requesting DDI {} aux power", ddi.name); + Error::new(EIO) + })?; + } + Ok(()) + }, + |pwr_well_ctl_aux| { + // Disable aux power + pwr_well_ctl_aux.writef(pwr_well_ctl_aux_request, false); + }, + )?; + + let mut edid_data = [0; 128]; + Aux::new(ddi) + .write_read(0x50, &[0x00], &mut edid_data) + .map_err(|_err| Error::new(EIO))?; + + Ok(edid_data) + }; + let mut gmbus_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { + let Some(pin_pair) = ddi.gmbus_pin_pair else { + return Err(Error::new(EIO)); + }; + + let mut edid_data = [0; 128]; + gmbus + .pin_pair(pin_pair) + .write_read(0x50, &[0x00], &mut edid_data) + .map_err(|_err| Error::new(EIO))?; + + Ok(edid_data) + }; + let gpio_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { + let Some(port) = &ddi.gpio_port else { + return Err(Error::new(EIO)); + }; + + let mut edid_data = [0; 128]; + let i2c_freq = 100_000.0; + bitbang_hal::i2c::I2cBB::new( + unsafe { port.clock(gttmm)? }, + unsafe { port.data(gttmm)? }, + HalTimer::new(Duration::from_secs_f64(1.0 / i2c_freq)), + ) + .write_read(0x50, &[0x00], &mut edid_data) + .map_err(|_err| Error::new(EIO))?; + + Ok(edid_data) + }; + let (source, edid_data) = match aux_read_edid(self) { + Ok(edid_data) => ("AUX", edid_data), + Err(err) => { + log::debug!("DDI {} failed to read EDID from AUX: {}", self.name, err); + match gmbus_read_edid(self) { + Ok(edid_data) => ("GMBUS", edid_data), + Err(err) => { + log::debug!("DDI {} failed to read EDID from GMBUS: {}", self.name, err); + match gpio_read_edid(self) { + Ok(edid_data) => ("GPIO", edid_data), + Err(err) => { + log::debug!( + "DDI {} failed to read EDID from GPIO: {}", + self.name, + err + ); + // Will try again but not fail the driver + return Ok(None); + } + } + } + } + } + }; + Ok(Some((source, edid_data))) + } + pub fn voltage_swing_hdmi( &mut self, gttmm: &MmioRegion, diff --git a/drivers/graphics/ihdgd/src/device/mod.rs b/drivers/graphics/ihdgd/src/device/mod.rs index 5a5dbb36dc..916afda64c 100644 --- a/drivers/graphics/ihdgd/src/device/mod.rs +++ b/drivers/graphics/ihdgd/src/device/mod.rs @@ -2,14 +2,12 @@ use common::{ io::{Io, MmioPtr}, timeout::Timeout, }; -use embedded_hal::prelude::*; use pcid_interface::{PciFunction, PciFunctionHandle}; use range_alloc::RangeAllocator; -use std::{collections::VecDeque, fmt, mem, sync::Arc, time::Duration}; +use std::{collections::VecDeque, fmt, mem, sync::Arc}; use syscall::error::{Error, Result, EIO, ENODEV, ERANGE}; mod aux; -use self::aux::*; mod bios; use self::bios::*; mod ddi; @@ -552,102 +550,10 @@ impl Device { // Enable DDI power well self.power_wells.enable_well_by_ddi(ddi.name)?; - //TODO: init port if needed - if let Some(port_comp_dw0) = ddi.port_comp(PortCompReg::Dw0) { - log::debug!("PORT_COMP_DW0_{}: {:08X}", ddi.name, port_comp_dw0.read()); - } - - let mut aux_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { - //TODO: BLOCK TCCOLD? - - //TODO: the request can be shared by multiple DDIs - let pwr_well_ctl_aux_request = ddi.pwr_well_ctl_aux_request; - let pwr_well_ctl_aux_state = ddi.pwr_well_ctl_aux_state; - let mut pwr_well_ctl_aux = - unsafe { MmioPtr::new(self.power_wells.ctl_aux.as_mut_ptr()) }; - let _pwr_guard = CallbackGuard::new( - &mut pwr_well_ctl_aux, - |pwr_well_ctl_aux| { - // Enable aux power - pwr_well_ctl_aux.writef(pwr_well_ctl_aux_request, true); - let timeout = Timeout::from_micros(1500); - while !pwr_well_ctl_aux.readf(pwr_well_ctl_aux_state) { - timeout.run().map_err(|()| { - log::debug!("timeout while requesting DDI {} aux power", ddi.name); - Error::new(EIO) - })?; - } - Ok(()) - }, - |pwr_well_ctl_aux| { - // Disable aux power - pwr_well_ctl_aux.writef(pwr_well_ctl_aux_request, false); - }, - )?; - - let mut edid_data = [0; 128]; - Aux::new(ddi) - .write_read(0x50, &[0x00], &mut edid_data) - .map_err(|_err| Error::new(EIO))?; - - Ok(edid_data) - }; - - let mut gmbus_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { - let Some(pin_pair) = ddi.gmbus_pin_pair else { - return Err(Error::new(EIO)); - }; - - let mut edid_data = [0; 128]; - self.gmbus - .pin_pair(pin_pair) - .write_read(0x50, &[0x00], &mut edid_data) - .map_err(|_err| Error::new(EIO))?; - - Ok(edid_data) - }; - - let gpio_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { - let Some(port) = &ddi.gpio_port else { - return Err(Error::new(EIO)); - }; - - let mut edid_data = [0; 128]; - let i2c_freq = 100_000.0; - bitbang_hal::i2c::I2cBB::new( - unsafe { port.clock(&self.gttmm)? }, - unsafe { port.data(&self.gttmm)? }, - HalTimer::new(Duration::from_secs_f64(1.0 / i2c_freq)), - ) - .write_read(0x50, &[0x00], &mut edid_data) - .map_err(|_err| Error::new(EIO))?; - - Ok(edid_data) - }; - - let (source, edid_data) = match aux_read_edid(ddi) { - Ok(edid_data) => ("AUX", edid_data), - Err(err) => { - log::debug!("DDI {} failed to read EDID from AUX: {}", ddi.name, err); - match gmbus_read_edid(ddi) { - Ok(edid_data) => ("GMBUS", edid_data), - Err(err) => { - log::debug!("DDI {} failed to read EDID from GMBUS: {}", ddi.name, err); - match gpio_read_edid(ddi) { - Ok(edid_data) => ("GPIO", edid_data), - Err(err) => { - log::debug!( - "DDI {} failed to read EDID from GPIO: {}", - ddi.name, - err - ); - // Will try again but not fail the driver - return Ok(false); - } - } - } - } - } + let Some((source, edid_data)) = + ddi.probe_edid(&mut self.power_wells, &self.gttmm, &mut self.gmbus)? + else { + return Ok(false); }; let edid = match edid::parse(&edid_data).to_full_result() { @@ -667,16 +573,10 @@ impl Device { } }; - let mut timing_opt = None; - for desc in edid.descriptors.iter() { - match desc { - edid::Descriptor::DetailedTiming(timing) => { - timing_opt = Some(timing); - break; - } - _ => {} - } - } + let timing_opt = edid.descriptors.iter().find_map(|desc| match desc { + edid::Descriptor::DetailedTiming(timing) => Some(timing), + _ => None, + }); let Some(timing) = timing_opt else { log::warn!( "DDI {} EDID from {} missing detailed timing",