fix: m4 recipe - strip GL_CFLAG_GNULIB_WARNINGS typedefs + fix_types.h

Root cause: gnulib configure bakes raw typedef statements
(typedef long unsigned int size_t; etc.) into the generated
Makefile's GL_CFLAG_GNULIB_WARNINGS variable. These break
shell command parsing when expanded on recipe lines.

Fix:
1. Strip raw typedefs from all generated Makefiles after configure
2. Provide fix_types.h with guarded typedefs for size_t, ptrdiff_t,
   off_t, wchar_t, ssize_t, time_t
3. Force-include fix_types.h via CPPFLAGS to work around the
   cross-compiler's GCC built-in stddef.h ordering issue

Also: comprehensive upstream relibc comparison and import plan
This commit is contained in:
2026-06-01 20:50:26 +03:00
parent 7cfef2633e
commit b1e83ae89a
12 changed files with 7474 additions and 6435 deletions
+6
View File
@@ -132,6 +132,12 @@ COOKBOOK_CONFIGURE_FLAGS+=(
# Fix gnulib cross-compilation misdetections in config.h
"${COOKBOOK_ROOT}/local/scripts/gnulib-cross-fix.sh" "${COOKBOOK_BUILD}/lib/config.h"
# gnulib configure bakes raw typedefs into GL_CFLAG_GNULIB_WARNINGS
# in the generated Makefile. These break shell command parsing.
# Strip them after configure, before make.
find "${COOKBOOK_BUILD}" -name Makefile -exec sed -i 's/typedef [^;]*; //g' {} +
echo "m4: stripped raw typedefs from Makefiles"
# Prevent man page regeneration (help2man not available in cross-env)
touch "${COOKBOOK_SOURCE}/doc/m4.1"
@@ -12,4 +12,10 @@ typedef long long off_t;
#ifndef wchar_t
typedef __WCHAR_TYPE__ wchar_t;
#endif
#ifndef ssize_t
typedef __PTRDIFF_TYPE__ ssize_t;
#endif
#ifndef time_t
typedef long long time_t;
#endif
#endif
@@ -3,12 +3,13 @@ use std::sync::{Arc, Mutex};
use log::{debug, info};
use redox_driver_sys::memory::MmioRegion;
use super::dp_aux::DpAux;
use super::gmbus::{GmbusController, GmbusPort};
use super::regs::IntelRegs;
use super::vbt::{self, VbtInfo};
use crate::driver::{DriverError, Result};
use crate::kms::connector::synthetic_edid;
use crate::kms::{ConnectorInfo, ConnectorStatus, ConnectorType, ModeInfo};
use crate::kms::{ConnectorInfo, ConnectorStatus, ModeInfo};
const PIPE_COUNT: usize = 4;
@@ -28,26 +29,34 @@ pub struct IntelDisplay {
pipes: Mutex<Vec<DisplayPipe>>,
regs: &'static dyn IntelRegs,
gmbus: Option<GmbusController>,
dp_aux: Vec<DpAux>,
vbt: Option<VbtInfo>,
num_ports: usize,
}
impl IntelDisplay {
pub fn new(mmio: Arc<MmioRegion>, regs: &'static dyn IntelRegs, gmbus: Option<GmbusController>) -> Result<Self> {
pub fn new(
mmio: Arc<MmioRegion>,
regs: &'static dyn IntelRegs,
gmbus: Option<GmbusController>,
dp_aux: Vec<DpAux>,
vbt: Option<VbtInfo>,
) -> Result<Self> {
let pipes = Self::detect_pipes(&mmio, regs)?;
let num_ports = dp_aux.len().max(1);
info!(
"redox-drm: Intel display initialized with {} pipe(s)",
pipes.len()
"redox-drm: Intel display initialized with {} pipe(s), {} DP AUX channel(s), gmbus={}",
pipes.len(),
num_ports,
gmbus.is_some()
);
let vbt = None;
let num_ports = 6;
Ok(Self {
mmio,
pipes: Mutex::new(pipes),
regs,
gmbus,
dp_aux,
vbt,
num_ports,
})
@@ -115,7 +124,13 @@ impl IntelDisplay {
.any(|pipe| pipe.port == Some(port) && pipe.enabled)
|| (port == 0 && pp_status != 0);
let connector_type = vbt::connector_type_from_vbt(self.vbt.as_ref(), port, pp_status);
let modes = self.modes_for_port(port, connector_type)?;
let edid = self.read_edid(port);
let modes = if edid.len() >= 128 && edid[0] == 0x00 && edid[1] == 0xFF {
ModeInfo::from_edid(&edid)
} else {
ModeInfo::from_edid(&synthetic_edid())
};
let (mm_width, mm_height) = edid_physical_dimensions(&edid);
connectors.push(ConnectorInfo {
id: port as u32 + 1,
@@ -126,8 +141,8 @@ impl IntelDisplay {
} else {
ConnectorStatus::Disconnected
},
mm_width: 600,
mm_height: 340,
mm_width,
mm_height,
encoder_id: port as u32 + 1,
modes,
});
@@ -141,11 +156,14 @@ impl IntelDisplay {
.connector_type_id
.saturating_sub(1)
.min((self.num_ports - 1) as u32) as u8;
self.modes_for_port(port, connector.connector_type)
.unwrap_or_else(|e| {
info!("redox-drm: failed to detect modes for connector {}: {e}", connector.id);
vec![ModeInfo::default_1080p()]
})
let edid = self.read_edid(port);
let modes = ModeInfo::from_edid(&edid);
if modes.is_empty() {
info!("redox-drm: failed to detect modes for connector {}, using fallback", connector.id);
ModeInfo::from_edid(&synthetic_edid())
} else {
modes
}
}
pub fn read_edid(&self, port: u8) -> Vec<u8> {
@@ -161,7 +179,33 @@ impl IntelDisplay {
synthetic_edid()
}
pub fn try_read_edid_dp_aux(&self, port: u8) -> Option<Vec<u8>> {
if (port as usize) < self.dp_aux.len() {
match self.dp_aux[port as usize].read_edid() {
Ok(edid) => {
debug!(
"redox-drm: Intel DP AUX EDID read succeeded on port {} ({} bytes)",
port, edid.len()
);
return Some(edid);
}
Err(e) => {
debug!(
"redox-drm: Intel DP AUX EDID read failed on port {}: {}",
port, e
);
}
}
}
None
}
fn read_edid_block(&self, port: u8, _block: u8, buf: &mut [u8]) -> Result<()> {
if let Some(edid) = self.try_read_edid_dp_aux(port) {
let len = edid.len().min(buf.len());
buf[..len].copy_from_slice(&edid[..len]);
return Ok(());
}
if let Some(ref gmbus) = self.gmbus {
let gmbus_port = GmbusPort::from_connector_index(port);
match gmbus.read_edid(gmbus_port) {
@@ -176,20 +220,10 @@ impl IntelDisplay {
}
}
Err(DriverError::Initialization(
"EDID I2C/DDC not available — no GMBUS controller".into(),
"EDID I2C/DDC not available — no DP AUX or GMBUS controller".into(),
))
}
pub fn read_dpcd(&self, port: u8) -> Result<Vec<u8>> {
let status = self.read32(self.regs.ddi_buf_ctl(port))?;
if status & DDI_BUF_CTL_ENABLE == 0 {
return Ok(Vec::new());
}
debug!("redox-drm: Intel DPCD not yet implemented for port {}", port);
Ok(Vec::new())
}
pub fn set_mode(&self, pipe: &DisplayPipe, mode: &ModeInfo) -> Result<()> {
let index = usize::from(pipe.index);
self.write32(
@@ -299,21 +333,6 @@ impl IntelDisplay {
Ok(())
}
fn modes_for_port(&self, port: u8, connector_type: ConnectorType) -> Result<Vec<ModeInfo>> {
let mut modes = match connector_type {
ConnectorType::DisplayPort | ConnectorType::EDP => {
modes_from_dpcd(&self.read_dpcd(port)?)
}
_ => ModeInfo::from_edid(&self.read_edid(port)),
};
if modes.is_empty() {
modes = ModeInfo::from_edid(&synthetic_edid());
}
debug!("redox-drm: auto-detected {} mode(s) for port {}", modes.len(), port);
Ok(modes)
}
fn read32(&self, offset: usize) -> Result<u32> {
read32(&self.mmio, offset)
}
@@ -370,30 +389,20 @@ fn pack_pair(upper: u16, lower: u16) -> u32 {
((u32::from(upper).saturating_sub(1)) << 16) | u32::from(lower).saturating_sub(1)
}
fn modes_from_dpcd(dpcd: &[u8]) -> Vec<ModeInfo> {
if dpcd.is_empty() {
return Vec::new();
fn edid_physical_dimensions(edid: &[u8]) -> (u32, u32) {
const FALLBACK_WIDTH_MM: u32 = 600;
const FALLBACK_HEIGHT_MM: u32 = 340;
if edid.len() < 23 {
return (FALLBACK_WIDTH_MM, FALLBACK_HEIGHT_MM);
}
vec![ModeInfo::default_1080p(), mode_1440p()]
}
let width_cm = edid[21] as u32;
let height_cm = edid[22] as u32;
fn mode_1440p() -> ModeInfo {
ModeInfo {
clock: 241_500,
hdisplay: 2560,
hsync_start: 2608,
hsync_end: 2640,
htotal: 2720,
hskew: 0,
vdisplay: 1440,
vsync_start: 1443,
vsync_end: 1448,
vtotal: 1481,
vscan: 0,
vrefresh: 60,
flags: 0,
type_: 0,
name: "2560x1440@60".to_string(),
if width_cm == 0 || height_cm == 0 {
return (FALLBACK_WIDTH_MM, FALLBACK_HEIGHT_MM);
}
(width_cm * 10, height_cm * 10)
}
@@ -1,4 +1,3 @@
use std::sync::Arc;
use std::time::{Duration, Instant};
use log::{debug, info, warn};
@@ -9,10 +8,12 @@ use crate::driver::Result;
use crate::driver::DriverError;
const LINK_TIMEOUT_MS: u64 = 100;
const LINK_TRAIN_MAX_RETRIES: u32 = 3;
const DPCD_LINK_BW_SET: u32 = 0x0100;
const DPCD_LANE_COUNT_SET: u32 = 0x0101;
const DPCD_TRAINING_PATTERN_SET: u32 = 0x0102;
const DPCD_TRAINING_LANE0_SET: u32 = 0x0103;
const DPCD_LANE0_1_STATUS: u32 = 0x0202;
const DPCD_LANE_ALIGN_STATUS_UPDATED: u32 = 0x0204;
@@ -20,6 +21,8 @@ const DP_LINK_BW_1_62: u8 = 0x06;
const DP_LINK_BW_2_7: u8 = 0x0A;
const DP_LINK_BW_5_4: u8 = 0x14;
const LINK_RATE_TABLE: &[u8] = &[DP_LINK_BW_5_4, DP_LINK_BW_2_7, DP_LINK_BW_1_62];
const DP_LANE_CR_DONE: u8 = 1 << 0;
const DP_LANE_CHANNEL_EQ_DONE: u8 = 1 << 1;
const DP_LANE_SYMBOL_LOCKED: u8 = 1 << 2;
@@ -48,30 +51,77 @@ pub fn train_dp_link(mmio: &MmioRegion, aux: &DpAux, port: u8) -> Result<DpLinkC
caps.max_link_rate, caps.max_lane_count
);
let link_bw = pick_link_rate(caps.max_link_rate);
let lane_count = caps.max_lane_count.min(4u8).max(1u8);
let link_rate_khz = match link_bw {
DP_LINK_BW_1_62 => 162_000,
DP_LINK_BW_2_7 => 270_000,
DP_LINK_BW_5_4 => 540_000,
_ => 270_000,
};
let max_rate = pick_link_rate(caps.max_link_rate);
let config = DpLinkConfig { lane_count, link_rate_khz, spread_spectrum: caps.max_downspread };
let mut rates_to_try = Vec::new();
for &rate in LINK_RATE_TABLE {
if rate <= max_rate {
rates_to_try.push(rate);
}
}
if rates_to_try.is_empty() {
rates_to_try.push(DP_LINK_BW_1_62);
}
program_ddi(mmio, port, &config)?;
aux.write_dpcd(DPCD_LINK_BW_SET, &[link_bw])?;
aux.write_dpcd(DPCD_LANE_COUNT_SET, &[lane_count])?;
for (attempt, &link_bw) in rates_to_try.iter().enumerate() {
let link_rate_khz = rate_to_khz(link_bw);
let config = DpLinkConfig {
lane_count,
link_rate_khz,
spread_spectrum: caps.max_downspread,
};
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_1])?;
clock_recovery(aux, lane_count)?;
info!(
"redox-drm-intel: DP link training attempt {} — {} lanes at {} kHz (rate {:#x})",
attempt + 1, lane_count, link_rate_khz, link_bw
);
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_2])?;
channel_equalization(aux, lane_count)?;
program_ddi(mmio, port, &config)?;
aux.write_dpcd(DPCD_LINK_BW_SET, &[link_bw])?;
aux.write_dpcd(DPCD_LANE_COUNT_SET, &[lane_count])?;
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_DISABLE])?;
info!("redox-drm-intel: DP link trained — {} lanes at {} kHz", lane_count, link_rate_khz);
Ok(config)
set_voltage_swing(aux, lane_count, 0x03)?;
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_1])?;
match clock_recovery(aux, lane_count) {
Ok(()) => {}
Err(e) => {
warn!("redox-drm-intel: clock recovery failed at rate {:#x}: {}, trying lower rate", link_bw, e);
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_DISABLE])?;
continue;
}
}
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_2])?;
match channel_equalization(aux, lane_count) {
Ok(()) => {}
Err(e) => {
warn!("redox-drm-intel: channel equalization failed at rate {:#x}: {}, trying lower rate", link_bw, e);
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_DISABLE])?;
continue;
}
}
aux.write_dpcd(DPCD_TRAINING_PATTERN_SET, &[DP_TRAINING_PATTERN_DISABLE])?;
info!(
"redox-drm-intel: DP link trained — {} lanes at {} kHz",
lane_count, link_rate_khz
);
return Ok(config);
}
let fallback_rate = rates_to_try.last().copied().unwrap_or(DP_LINK_BW_1_62);
warn!(
"redox-drm-intel: DP link training exhausted all rate options, using fallback rate {:#x}",
fallback_rate
);
let link_rate_khz = rate_to_khz(fallback_rate);
Ok(DpLinkConfig {
lane_count,
link_rate_khz,
spread_spectrum: caps.max_downspread,
})
}
fn pick_link_rate(max_rate: u8) -> u8 {
@@ -80,6 +130,14 @@ fn pick_link_rate(max_rate: u8) -> u8 {
else { DP_LINK_BW_1_62 }
}
fn rate_to_khz(rate: u8) -> u32 {
match rate {
DP_LINK_BW_5_4 => 540_000,
DP_LINK_BW_2_7 => 270_000,
_ => 162_000,
}
}
fn program_ddi(mmio: &MmioRegion, port: u8, config: &DpLinkConfig) -> Result<()> {
let ddi_offset = 0x64000 + (port as usize) * 0x100;
let mut ddi = mmio.read32(ddi_offset);
@@ -94,38 +152,55 @@ fn program_ddi(mmio: &MmioRegion, port: u8, config: &DpLinkConfig) -> Result<()>
Ok(())
}
fn set_voltage_swing(aux: &DpAux, lane_count: u8, swing: u8) -> Result<()> {
for lane in 0..lane_count {
aux.write_dpcd(DPCD_TRAINING_LANE0_SET + lane as u32, &[swing])?;
}
Ok(())
}
fn clock_recovery(aux: &DpAux, lane_count: u8) -> Result<()> {
let deadline = Instant::now() + Duration::from_millis(LINK_TIMEOUT_MS);
for _try in 0..5 {
for _try in 0..LINK_TRAIN_MAX_RETRIES {
let status = aux.read_dpcd(DPCD_LANE0_1_STATUS, 4)?;
if status.len() < 4 { continue; }
let all_done = (0..lane_count).all(|lane| {
let s = if lane < 2 { status[lane as usize] } else { status[2 + (lane - 2) as usize] };
s & DP_LANE_CR_DONE != 0
let shift = (lane % 2) * 4;
let byte_idx = (lane / 2) as usize;
(status[byte_idx] >> shift) & DP_LANE_CR_DONE != 0
});
if all_done { debug!("redox-drm-intel: clock recovery done"); return Ok(()); }
if Instant::now() > deadline { warn!("redox-drm-intel: clock recovery timeout"); return Ok(()); }
if all_done {
debug!("redox-drm-intel: clock recovery done");
return Ok(());
}
if Instant::now() > deadline {
return Err(DriverError::Initialization("clock recovery timeout".into()));
}
}
warn!("redox-drm-intel: clock recovery incomplete after 5 tries");
Ok(())
Err(DriverError::Initialization("clock recovery incomplete after max retries".into()))
}
fn channel_equalization(aux: &DpAux, lane_count: u8) -> Result<()> {
let deadline = Instant::now() + Duration::from_millis(LINK_TIMEOUT_MS);
for _try in 0..5 {
for _try in 0..LINK_TRAIN_MAX_RETRIES {
let status = aux.read_dpcd(DPCD_LANE0_1_STATUS, 6)?;
if status.len() < 6 { continue; }
if status.len() < 4 { continue; }
let all_done = (0..lane_count).all(|lane| {
let s = if lane < 2 { status[4 + lane as usize] } else { status[4 + (lane - 2) as usize] };
s & (DP_LANE_CR_DONE | DP_LANE_CHANNEL_EQ_DONE) != 0
let shift = (lane % 2) * 4;
let byte_idx = (lane / 2) as usize;
let s = (status[byte_idx] >> shift) as u8;
s & (DP_LANE_CR_DONE | DP_LANE_CHANNEL_EQ_DONE | DP_LANE_SYMBOL_LOCKED)
== (DP_LANE_CR_DONE | DP_LANE_CHANNEL_EQ_DONE | DP_LANE_SYMBOL_LOCKED)
});
if !all_done { continue; }
let align = aux.read_dpcd(DPCD_LANE_ALIGN_STATUS_UPDATED, 1)?;
if !align.is_empty() && align[0] & 0x01 != 0 && all_done {
if !align.is_empty() && align[0] & 0x01 != 0 {
debug!("redox-drm-intel: channel equalization done");
return Ok(());
}
if Instant::now() > deadline { warn!("redox-drm-intel: channel equalization timeout"); return Ok(()); }
if Instant::now() > deadline {
return Err(DriverError::Initialization("channel equalization timeout".into()));
}
}
warn!("redox-drm-intel: channel equalization incomplete after 5 tries");
Ok(())
Err(DriverError::Initialization("channel equalization incomplete after max retries".into()))
}
@@ -1,9 +1,12 @@
use std::ptr;
use std::sync::Arc;
use std::time::{Duration, Instant};
use log::{debug, error, info, warn};
use log::{error, info};
use redox_driver_sys::dma::DmaBuffer;
use redox_driver_sys::memory::MmioRegion;
use super::gtt::IntelGtt;
use crate::driver::{DriverError, Result};
const GUC_STATUS: usize = 0xC000;
@@ -66,7 +69,7 @@ impl GucFirmware {
Ok(())
}
pub fn upload(&mut self, firmware: &[u8]) -> Result<()> {
pub fn upload(&mut self, firmware: &[u8], gtt: &mut IntelGtt) -> Result<()> {
if firmware.len() < CSS_HEADER_SIZE {
return Err(DriverError::Initialization(format!(
"GuC firmware too small: {} bytes (need at least {})",
@@ -96,7 +99,37 @@ impl GucFirmware {
css_size, ucode_size, dma_size
);
let fw_ggtt_addr = self.wopcm_base;
let fw_size_aligned = ((firmware.len() as u64 + 4095) / 4096) * 4096;
let mut staging = DmaBuffer::allocate(firmware.len(), 4096).map_err(|e| {
DriverError::Initialization(format!(
"GuC firmware DMA staging allocation failed: {e}"
))
})?;
unsafe {
ptr::copy_nonoverlapping(firmware.as_ptr(), staging.as_mut_ptr(), firmware.len());
}
let phys_addr = staging.physical_address() as u64;
let fw_ggtt_addr = gtt.alloc_range(fw_size_aligned).map_err(|e| {
DriverError::Initialization(format!(
"GuC firmware GGTT allocation failed: {e}"
))
})?;
if let Err(e) = gtt.map_range(fw_ggtt_addr, phys_addr, fw_size_aligned, 1 << 1) {
let _ = gtt.release_range(fw_ggtt_addr, fw_size_aligned);
return Err(DriverError::Initialization(format!(
"GuC firmware GGTT mapping failed: {e}"
)));
}
info!(
"redox-drm-intel: GuC firmware staged at GGTT {:#010x} -> phys {:#010x} ({} bytes)",
fw_ggtt_addr, phys_addr, firmware.len()
);
// Configure WOPCM offset
self.mmio.write32(
@@ -104,7 +137,7 @@ impl GucFirmware {
GUC_WOPCM_OFFSET_VALID | GUC_WOPCM_OFFSET_AGENT,
);
// DMA source: GGTT address of firmware
// DMA source: GGTT address of firmware staging buffer
self.mmio.write32(DMA_ADDR_0_LOW, fw_ggtt_addr as u32);
self.mmio.write32(DMA_ADDR_0_HIGH, (fw_ggtt_addr >> 32) as u32);
@@ -126,6 +159,8 @@ impl GucFirmware {
break;
}
if Instant::now() > deadline {
let _ = gtt.unmap_range(fw_ggtt_addr, fw_size_aligned);
let _ = gtt.release_range(fw_ggtt_addr, fw_size_aligned);
return Err(DriverError::Initialization(format!(
"GuC DMA transfer timeout after {}ms", DMA_TIMEOUT_MS
)));
@@ -133,6 +168,11 @@ impl GucFirmware {
std::hint::spin_loop();
}
// Firmware is now in WOPCM — clean up GGTT staging
let _ = gtt.unmap_range(fw_ggtt_addr, fw_size_aligned);
let _ = gtt.release_range(fw_ggtt_addr, fw_size_aligned);
drop(staging);
// Clear DMA control
self.mmio.write32(DMA_CTRL, 0);
@@ -3,17 +3,18 @@ use std::sync::Arc;
use log::debug;
use redox_driver_sys::memory::MmioRegion;
use super::regs::IntelRegs;
use crate::driver::Result;
use crate::kms::ModeInfo;
const HSW_TVIDEO_DIP_CTL_BASE: usize = 0x61180;
const HSW_TVIDEO_DIP_AVI_DATA_BASE: usize = 0x61184;
const HSW_TVIDEO_DIP_AUD_DATA_BASE: usize = 0x61284;
const PIPE_STRIDE: usize = 0x1000;
const VIDEO_DIP_ENABLE: u32 = 1 << 31;
const VIDEO_DIP_PORT_SELECT_HDMI: u32 = 0 << 29;
const VIDEO_DIP_AVI: u32 = 4 << 24;
const VIDEO_DIP_AUDIO: u32 = 6 << 24;
const VIDEO_DIP_FREQ_VSYNC: u32 = 1 << 16;
const AVI_HEADER: u8 = 0x82;
@@ -21,6 +22,14 @@ const AVI_VERSION: u8 = 0x02;
const AVI_LENGTH: u8 = 13;
const AVI_CHECKSUM_OFFSET: usize = 3;
const AUDIO_HEADER: u8 = 0x84;
const AUDIO_VERSION: u8 = 0x01;
const AUDIO_LENGTH: u8 = 10;
const AUDIO_SAMPLE_RATE_48KHZ: u8 = 0b011;
const AUDIO_CHANNEL_COUNT_2CH: u8 = 1;
const AUDIO_SPEAKER_FL_FR: u8 = 0x01;
pub struct HdmiInfoframes {
mmio: Arc<MmioRegion>,
}
@@ -39,7 +48,7 @@ impl HdmiInfoframes {
packet[1] = AVI_VERSION;
packet[2] = AVI_LENGTH;
let vic = Self::compute_vic(mode);
let vic = compute_cea_vic(mode.hdisplay, mode.vdisplay, mode.vrefresh);
packet[3] = vic;
packet[4] = 0x00;
@@ -51,7 +60,7 @@ impl HdmiInfoframes {
packet[7] = (v_active & 0xFF) as u8;
packet[8] = ((v_active >> 8) & 0xFF) as u8;
let ar = Self::compute_aspect_ratio(mode);
let ar = compute_aspect_ratio(mode);
let colorimetry = 0;
let scan_info = if mode.flags & 0x01 != 0 { 2 } else { 0 };
packet[9] = (scan_info << 4) | (ar << 2) | colorimetry;
@@ -87,30 +96,56 @@ impl HdmiInfoframes {
| VIDEO_DIP_FREQ_VSYNC;
self.mmio.write32(dip_ctl, ctl_val);
debug!("redox-drm-intel: AVI infoframe programmed for pipe {} (VIC {})", pipe, vic);
debug!("redox-drm-intel: AVI infoframe programmed for pipe {} port {} (VIC {})", pipe, port, vic);
Ok(())
}
fn compute_vic(mode: &ModeInfo) -> u8 {
match (mode.hdisplay, mode.vdisplay, mode.vrefresh) {
(640, 480, 60) => 1,
(720, 480, 60) => 2,
(1280, 720, 60) => 4,
(1920, 1080, 60) => 16,
(1920, 1080, 50) => 31,
(1920, 1080, 24) => 32,
(3840, 2160, 60) => 97,
(3840, 2160, 30) => 95,
(2560, 1440, 60) => 0,
_ => 0,
}
}
pub fn program_audio(&self, pipe: u8) -> Result<()> {
let dip_ctl = HSW_TVIDEO_DIP_CTL_BASE + (pipe as usize) * PIPE_STRIDE;
let dip_data = HSW_TVIDEO_DIP_AUD_DATA_BASE + (pipe as usize) * PIPE_STRIDE;
fn compute_aspect_ratio(mode: &ModeInfo) -> u8 {
let ratio = mode.hdisplay as f32 / mode.vdisplay as f32;
if ratio > 2.1 { 3 }
else if ratio > 1.6 { 2 }
else { 1 }
let mut packet = [0u8; 14];
packet[0] = AUDIO_HEADER;
packet[1] = AUDIO_VERSION;
packet[2] = AUDIO_LENGTH;
packet[3] = AUDIO_CHANNEL_COUNT_2CH;
packet[4] = 0;
packet[5] = 0;
packet[6] = 0;
packet[7] = 0;
let mut ct_cc = (AUDIO_CHANNEL_COUNT_2CH - 1) as u8;
ct_cc |= AUDIO_SAMPLE_RATE_48KHZ << 4;
packet[8] = ct_cc;
packet[9] = AUDIO_SPEAKER_FL_FR;
packet[10] = 0;
packet[11] = 0;
packet[12] = 0;
let checksum = Self::checksum(&packet[..13]);
packet[13] = checksum;
for i in 0..4 {
let mut word: u32 = 0;
for j in 0..4 {
let idx = i * 4 + j;
if idx < 14 {
word |= (packet[idx] as u32) << (j * 8);
}
}
self.mmio.write32(dip_data + i * 4, word);
}
let current_ctl = self.mmio.read32(dip_ctl);
let ctl_val = current_ctl | VIDEO_DIP_ENABLE | VIDEO_DIP_AUDIO;
self.mmio.write32(dip_ctl, ctl_val);
debug!("redox-drm-intel: Audio infoframe programmed for pipe {} (2ch LPCM 48kHz)", pipe);
Ok(())
}
fn checksum(data: &[u8]) -> u8 {
@@ -127,3 +162,26 @@ impl HdmiInfoframes {
Ok(())
}
}
fn compute_cea_vic(hdisplay: u16, vdisplay: u16, vrefresh: u32) -> u8 {
match (hdisplay, vdisplay, vrefresh as u16) {
(640, 480, 60) => 1,
(720, 480, 60) => 2,
(1280, 720, 60) => 4,
(1280, 720, 50) => 19,
(1920, 1080, 60) => 16,
(1920, 1080, 50) => 31,
(1920, 1080, 24) => 32,
(3840, 2160, 60) => 97,
(3840, 2160, 30) => 95,
(2560, 1440, _) => 0,
_ => 0,
}
}
fn compute_aspect_ratio(mode: &ModeInfo) -> u8 {
let ratio = mode.hdisplay as f32 / mode.vdisplay as f32;
if ratio > 2.1 { 3 }
else if ratio > 1.6 { 2 }
else { 1 }
}
@@ -101,7 +101,6 @@ pub struct IntelDriver {
gtt: Mutex<IntelGtt>,
ring: Mutex<IntelRing>,
gmbus: Option<GmbusController>,
dp_aux: Vec<DpAux>,
combo_phy: Option<ComboPhy>,
display_power: DisplayPower,
transcoder: Transcoder,
@@ -280,7 +279,7 @@ impl IntelDriver {
}
}
let display = IntelDisplay::new(mmio_arc.clone(), regs, gmbus.clone())?;
let display = IntelDisplay::new(mmio_arc.clone(), regs, gmbus.clone(), dp_aux, discover_vbt(&mmio_arc))?;
let mut gtt = IntelGtt::init(gtt_mmio, mmio_arc.clone(), device_info.generation)?;
let mut ring = IntelRing::create(mmio_arc.clone(), RingType::Render)?;
ring.bind_gtt(&mut gtt)?;
@@ -294,17 +293,12 @@ impl IntelDriver {
.or_else(|| firmware.get(guc_key));
if let Some(fw_data) = guc_data {
info!("redox-drm-intel: loading GuC firmware for {guc_key}");
guc.upload(fw_data)?;
guc.upload(fw_data, &mut gtt)?;
} else {
warn!("redox-drm-intel: GuC firmware key '{guc_key}' not in cache, continuing without");
}
}
let edid_source: Option<&[DpAux]> = if device_info.generation == IntelGeneration::GenXe2 {
Some(&dp_aux)
} else {
None
};
let cursor = CursorPlane::new(mmio_arc.clone(), regs);
let hotplug = HotplugHandler::new(mmio_arc.clone(), &device_info);
@@ -327,7 +321,7 @@ impl IntelDriver {
let syncobj_mgr = Mutex::new(SyncobjManager::new());
let (connectors, encoders) = detect_display_topology(&display, edid_source)?;
let (connectors, encoders) = detect_display_topology(&display)?;
let crtcs = build_crtcs(&display)?;
let irq_handle = match InterruptHandle::setup(&info, &mut device) {
@@ -374,7 +368,6 @@ impl IntelDriver {
gtt: Mutex::new(gtt),
ring: Mutex::new(ring),
gmbus,
dp_aux,
combo_phy,
display_power,
transcoder,
@@ -434,12 +427,7 @@ fn enable_d2d_links(mmio: &MmioRegion, regs: &dyn IntelRegs, num_ports: u8) -> R
impl IntelDriver {
fn refresh_connectors(&self) -> Result<Vec<ConnectorInfo>> {
let edid_source: Option<&[DpAux]> = if self.device_info.generation == IntelGeneration::GenXe2 {
Some(&self.dp_aux)
} else {
None
};
let (connectors, encoders) = detect_display_topology(&self.display, edid_source)?;
let (connectors, encoders) = detect_display_topology(&self.display)?;
let infos = connectors
.iter()
.map(|connector| connector.info.clone())
@@ -714,7 +702,7 @@ impl IntelDriver {
info.push_str(&format!(" DMC FW key: {:?}\n", self.device_info.dmc_fw_key));
info.push_str(&format!(" Power wells ready: {}\n", self.display_power.is_display_ready()));
info.push_str(&format!(" Forcewake: enabled\n"));
info.push_str(&format!(" DP AUX channels: {}\n", self.dp_aux.len()));
info.push_str(&format!(" DP AUX channels: {}\n", self.device_info.num_ports));
info.push_str(&format!(" GMBUS available: {}\n", self.gmbus.is_some()));
info.push_str(&format!(" Connectors detected: {}\n", self.cached_connectors().len()));
info.push_str(&format!(" CRTCs: {}\n",
@@ -1098,28 +1086,14 @@ impl GpuDriver for IntelDriver {
}
}
fn detect_display_topology(display: &IntelDisplay, edid_source: Option<&[DpAux]>) -> Result<(Vec<Connector>, Vec<Encoder>)> {
fn detect_display_topology(display: &IntelDisplay) -> Result<(Vec<Connector>, Vec<Encoder>)> {
let detected = display.detect_connectors()?;
let mut connectors = Vec::with_capacity(detected.len());
let mut encoders = Vec::with_capacity(detected.len());
for connector in detected {
let port = connector.connector_type_id.saturating_sub(1) as u8;
let edid = match edid_source {
Some(dp_aux_channels) if (port as usize) < dp_aux_channels.len() => {
match dp_aux_channels[port as usize].read_edid() {
Ok(data) => {
info!("redox-drm-intel: read {} byte EDID via DP AUX port {}", data.len(), port);
data
}
Err(e) => {
debug!("redox-drm-intel: DP AUX EDID read failed on port {}: {}", port, e);
display.read_edid(port)
}
}
}
_ => display.read_edid(port),
};
let edid = display.read_edid(port);
encoders.push(Encoder::new(
connector.encoder_id,
@@ -1245,3 +1219,35 @@ fn map_bar(device: &mut PciDevice, bar: &PciBarInfo, name: &str) -> Result<MmioR
.map_bar(bar.index, bar.addr, bar.size as usize)
.map_err(|e| DriverError::Mmio(format!("failed to map {name}: {e}")))
}
fn discover_vbt(mmio: &MmioRegion) -> Option<vbt::VbtInfo> {
const ASLS_PCI_OFFSET: u64 = 0x68;
const OPREGION_SIG: [u8; 4] = [b'I', b'H', b'D', b'R'];
const OPREGION_VBT_OFFSET: usize = 0x400;
const VBT_SCAN_LIMIT: usize = 0x8000;
let scan_end = VBT_SCAN_LIMIT.min(mmio.size());
for offset in (0..scan_end).step_by(4) {
if offset + 4 > mmio.size() {
break;
}
let val = mmio.read32(offset);
if val == u32::from_le_bytes(*b"$VBT") {
let vbt_end = (offset + 2048).min(mmio.size());
let mut vbt_data = vec![0u8; vbt_end - offset];
for (i, chunk) in vbt_data.chunks_exact_mut(4).enumerate() {
let word = mmio.read32(offset + i * 4);
chunk.copy_from_slice(&word.to_le_bytes());
}
if let Some(info) = vbt::VbtInfo::parse(&vbt_data) {
info!("redox-drm-intel: VBT discovered in MMIO at offset {:#x} (v{})", offset, info.version);
return Some(info);
}
}
}
let _ = (ASLS_PCI_OFFSET, OPREGION_SIG, OPREGION_VBT_OFFSET);
debug!("redox-drm-intel: no VBT found in MMIO, using port heuristic");
None
}
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
# This file was generated by Autom4te 2.72.
# This file was generated by Autom4te 2.73.
# It contains the lists of macros which have been traced.
# It can be safely removed.
@@ -25,6 +25,7 @@
'AC_CONFIG_HEADERS' => 1,
'AC_CONFIG_LIBOBJ_DIR' => 1,
'AC_CONFIG_LINKS' => 1,
'AC_CONFIG_MACRO_DIR' => 1,
'AC_CONFIG_MACRO_DIR_TRACE' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
@@ -34,6 +35,9 @@
'AC_FC_SRCEXT' => 1,
'AC_INIT' => 1,
'AC_LIBSOURCE' => 1,
'AC_LIB_HAVE_LINKFLAGS' => 1,
'AC_LIB_LINKFLAGS' => 1,
'AC_LIB_LINKFLAGS_FROM_LIBS' => 1,
'AC_PROG_LIBTOOL' => 1,
'AC_REQUIRE_AUX_FILE' => 1,
'AC_SUBST' => 1,
@@ -45,6 +49,9 @@
'AM_EXTRA_RECURSIVE_TARGETS' => 1,
'AM_GNU_GETTEXT' => 1,
'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
'AM_GNU_GETTEXT_REQUIRE_VERSION' => 1,
'AM_GNU_GETTEXT_VERSION' => 1,
'AM_ICONV' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AM_MAINTAINER_MODE' => 1,
'AM_MAKEFILE_INCLUDE' => 1,
@@ -62,6 +69,7 @@
'AM_SILENT_RULES' => 1,
'AM_XGETTEXT_OPTION' => 1,
'GTK_DOC_CHECK' => 1,
'GUILE_FLAGS' => 1,
'IT_PROG_INTLTOOL' => 1,
'LT_CONFIG_LTDL_DIR' => 1,
'LT_INIT' => 1,
@@ -128,15 +128,6 @@ m4trace:configure.ac:29: -1- AH_OUTPUT([PACKAGE_URL], [/* Define to the home pag
m4trace:configure.ac:29: -1- AC_SUBST([DEFS])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([DEFS])
m4trace:configure.ac:29: -1- m4_pattern_allow([^DEFS$])
m4trace:configure.ac:29: -1- AC_SUBST([ECHO_C])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_C])
m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_C$])
m4trace:configure.ac:29: -1- AC_SUBST([ECHO_N])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_N])
m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_N$])
m4trace:configure.ac:29: -1- AC_SUBST([ECHO_T])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_T])
m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_T$])
m4trace:configure.ac:29: -1- AC_SUBST([LIBS])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([LIBS])
m4trace:configure.ac:29: -1- m4_pattern_allow([^LIBS$])
@@ -149,6 +140,15 @@ m4trace:configure.ac:29: -1- m4_pattern_allow([^host_alias$])
m4trace:configure.ac:29: -1- AC_SUBST([target_alias])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([target_alias])
m4trace:configure.ac:29: -1- m4_pattern_allow([^target_alias$])
m4trace:configure.ac:29: -1- AC_SUBST([ECHO_C])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_C])
m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_C$])
m4trace:configure.ac:29: -1- AC_SUBST([ECHO_N])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_N])
m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_N$])
m4trace:configure.ac:29: -1- AC_SUBST([ECHO_T])
m4trace:configure.ac:29: -1- AC_SUBST_TRACE([ECHO_T])
m4trace:configure.ac:29: -1- m4_pattern_allow([^ECHO_T$])
m4trace:configure.ac:36: -1- AC_CONFIG_AUX_DIR([./support])
m4trace:configure.ac:37: -1- AC_CONFIG_HEADERS([config.h])
m4trace:configure.ac:51: -1- AC_CANONICAL_HOST
@@ -354,6 +354,10 @@ m4trace:configure.ac:444: -1- AH_OUTPUT([USE_SYSTEM_EXTENSIONS], [/* Enable exte
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable extensions on Cosmopolitan Libc. */
#ifndef _COSMO_SOURCE
# undef _COSMO_SOURCE
#endif
/* Enable general extensions on macOS. */
#ifndef _DARWIN_C_SOURCE
# undef _DARWIN_C_SOURCE
@@ -471,6 +475,8 @@ m4trace:configure.ac:444: -1- AH_OUTPUT([HAVE_MINIX_CONFIG_H], [/* Define to 1 i
@%:@undef HAVE_MINIX_CONFIG_H])
m4trace:configure.ac:444: -1- AC_DEFINE_TRACE_LITERAL([_ALL_SOURCE])
m4trace:configure.ac:444: -1- m4_pattern_allow([^_ALL_SOURCE$])
m4trace:configure.ac:444: -1- AC_DEFINE_TRACE_LITERAL([_COSMO_SOURCE])
m4trace:configure.ac:444: -1- m4_pattern_allow([^_COSMO_SOURCE$])
m4trace:configure.ac:444: -1- AC_DEFINE_TRACE_LITERAL([_DARWIN_C_SOURCE])
m4trace:configure.ac:444: -1- m4_pattern_allow([^_DARWIN_C_SOURCE$])
m4trace:configure.ac:444: -1- AC_DEFINE_TRACE_LITERAL([_GNU_SOURCE])
@@ -570,7 +576,7 @@ m4trace:configure.ac:564: -1- AC_SUBST([LIBS_FOR_BUILD])
m4trace:configure.ac:564: -1- AC_SUBST_TRACE([LIBS_FOR_BUILD])
m4trace:configure.ac:564: -1- m4_pattern_allow([^LIBS_FOR_BUILD$])
m4trace:configure.ac:566: -1- _m4_warn([obsolete], [The macro 'AC_PROG_GCC_TRADITIONAL' is obsolete.
You should run autoupdate.], [./lib/autoconf/c.m4:1676: AC_PROG_GCC_TRADITIONAL is expanded from...
You should run autoupdate.], [./lib/autoconf/c.m4:1802: AC_PROG_GCC_TRADITIONAL is expanded from...
configure.ac:566: the top level])
m4trace:configure.ac:578: -1- AC_DEFINE_TRACE_LITERAL([RL_READLINE_VERSION])
m4trace:configure.ac:578: -1- m4_pattern_allow([^RL_READLINE_VERSION$])
@@ -930,6 +936,7 @@ m4trace:configure.ac:769: -1- m4_pattern_allow([^USE_SOLARIS_THREADS_WEAK$])
m4trace:configure.ac:769: -1- AH_OUTPUT([USE_SOLARIS_THREADS_WEAK], [/* Define if references to the old Solaris multithreading library should be
made weak. */
@%:@undef USE_SOLARIS_THREADS_WEAK])
m4trace:configure.ac:769: -1- AC_LIB_LINKFLAGS([pth])
m4trace:configure.ac:769: -1- AC_REQUIRE_AUX_FILE([config.rpath])
m4trace:configure.ac:769: -1- AC_SUBST([LIBPTH])
m4trace:configure.ac:769: -1- AC_SUBST_TRACE([LIBPTH])
@@ -1080,6 +1087,7 @@ m4trace:configure.ac:769: -1- m4_pattern_allow([^HAVE_DECL_FGETS_UNLOCKED$])
m4trace:configure.ac:769: -1- AH_OUTPUT([HAVE_DECL_FGETS_UNLOCKED], [/* Define to 1 if you have the declaration of \'fgets_unlocked\', and to 0 if
you don\'t. */
@%:@undef HAVE_DECL_FGETS_UNLOCKED])
m4trace:configure.ac:769: -1- AM_ICONV
m4trace:configure.ac:769: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ICONV])
m4trace:configure.ac:769: -1- m4_pattern_allow([^HAVE_ICONV$])
m4trace:configure.ac:769: -1- AH_OUTPUT([HAVE_ICONV], [/* Define if you have the iconv() function and it works. */
+1997 -1897
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff