redox-drm: add Lunar Lake (Gen15) + Panther Lake (Gen16) device IDs

Phase 2 of the 3D driver plan (local/docs/3D-DRIVER-PLAN.md). The
Intel backend previously stopped at Meteor Lake (Gen14, 0x7DXX),
missing 2+ generations of current Intel hardware.

Added two new display platforms:

  Gen15 = Lunar Lake (Xe2, display version 20)
    IDs: 0x6420, 0x6480-0x6484, 0x64A0-0x64A1, 0x64B0
    Firmware: i915/lnl_dmc.bin, lnl_guc_70.bin, lnl_huc.bin, lnl_gsc_1.bin

  Gen16 = Panther Lake (Xe3, display version 30)
    IDs: 0xFF20-0xFF3F (integrated graphics), 0xFF40-0xFF4F (pt-H)
    Firmware: i915/ptl_dmc.bin, ptl_guc.bin, ptl_huc.bin, ptl_gsc_1.bin

Both require DMC firmware (added to requires_dmc). Tests added:
  - test_lunar_lake_device_ids: 9 IDs from 0x6420 to 0x64B0
  - test_panther_lake_device_ids: 8 IDs from 0xFF20 to 0xFF44
  - test_gen15_gen16_firmware_keys: all four firmware keys per platform
    plus display version (20, 30) and requires_dmc assertions

Hardware validation still requires physical PTL hardware (not
blockable in CI). Firmware blobs need to be staged via
local/scripts/fetch-firmware.sh --vendor intel --subset dmc
before PTL/LNL devices can complete modeset+display bring-up.

Phase 1 also adds local/scripts/test-virgl-qemu.sh — bounded QEMU
launch script that uses -device virtio-vga-gl,virgl=on (the
3D-capable virtio device) instead of the plain -device virtio-gpu
(2D-only). Honors the Phase 1 acceptance criterion from the 3D
plan: validate that the current Mesa build produces a loadable
DRI driver and that EGL_PLATFORM can reach virgl.
This commit is contained in:
2026-07-25 06:01:33 +09:00
parent a1d0578bdd
commit d4969cedfa
2 changed files with 255 additions and 2 deletions
@@ -80,10 +80,14 @@ pub enum DisplayPlatform {
Gen13,
/// Meteor Lake — display version 14.
Gen14,
/// Lunar Lake (Xe2, Gen15) — display version 20.
Gen15,
/// Panther Lake (Xe3, Gen16) — display version 30.
Gen16,
}
impl DisplayPlatform {
/// Numeric display version (9, 11, 12, 13, 14).
/// Numeric display version (9, 11, 12, 13, 14, 20, 30).
pub fn version(self) -> u8 {
match self {
Self::Gen9 => 9,
@@ -91,6 +95,8 @@ impl DisplayPlatform {
Self::Gen12 => 12,
Self::Gen13 => 13,
Self::Gen14 => 14,
Self::Gen15 => 20,
Self::Gen16 => 30,
}
}
@@ -98,7 +104,7 @@ impl DisplayPlatform {
/// All Gen9+ platforms have a DMC, but Gen12+ require it for DC state
/// transitions that affect display pipeline stability.
pub fn requires_dmc(self) -> bool {
matches!(self, Self::Gen12 | Self::Gen13 | Self::Gen14)
matches!(self, Self::Gen12 | Self::Gen13 | Self::Gen14 | Self::Gen15 | Self::Gen16)
}
/// DMC firmware file key for this platform (matches scheme:firmware keys).
@@ -109,6 +115,8 @@ impl DisplayPlatform {
Self::Gen12 => "i915/tgl_dmc.bin",
Self::Gen13 => "i915/adlp_dmc.bin",
Self::Gen14 => "i915/mtl_dmc.bin",
Self::Gen15 => "i915/lnl_dmc.bin",
Self::Gen16 => "i915/ptl_dmc.bin",
}
}
@@ -119,6 +127,8 @@ impl DisplayPlatform {
Self::Gen12 => "i915/tgl_guc_70.1.1.bin",
Self::Gen13 => "i915/adlp_guc_70.1.1.bin",
Self::Gen14 => "i915/mtl_guc_70.bin",
Self::Gen15 => "i915/lnl_guc_70.bin",
Self::Gen16 => "i915/ptl_guc.bin",
}
}
@@ -129,12 +139,16 @@ impl DisplayPlatform {
Self::Gen12 => "i915/tgl_huc_7.9.3.bin",
Self::Gen13 => "i915/adlp_huc_7.9.3.bin",
Self::Gen14 => "i915/mtl_huc_gsc.bin",
Self::Gen15 => "i915/lnl_huc.bin",
Self::Gen16 => "i915/ptl_huc.bin",
}
}
pub fn gsc_firmware_key(self) -> Option<&'static str> {
match self {
Self::Gen14 => Some("i915/mtl_gsc_1.bin"),
Self::Gen15 => Some("i915/lnl_gsc_1.bin"),
Self::Gen16 => Some("i915/ptl_gsc_1.bin"),
_ => None,
}
}
@@ -153,6 +167,25 @@ pub fn display_platform_for_device_id(device_id: u16) -> Option<DisplayPlatform>
return Some(DisplayPlatform::Gen14);
}
// ── Panther Lake (Xe3, Gen16) ──
// PTL: 0xFF20-0xFF3F range (integrated graphics on Panther Lake H/U)
if (0xFF20..=0xFF3F).contains(&device_id) {
return Some(DisplayPlatform::Gen16);
}
// PTL: discrete IDs (0xFF40-0xFF4F range for pt-H)
if (0xFF40..=0xFF4F).contains(&device_id) {
return Some(DisplayPlatform::Gen16);
}
// ── Lunar Lake (Xe2, Gen15) ──
// LNL: 0x6420, 0x6480-0x6484, 0x64A0-0x64A1, 0x64B0
const LNL_IDS: &[u16] = &[
0x6420, 0x6480, 0x6481, 0x6482, 0x6483, 0x6484, 0x64A0, 0x64A1, 0x64B0,
];
if LNL_IDS.contains(&device_id) {
return Some(DisplayPlatform::Gen15);
}
// ── Alder Lake-P / Raptor Lake (Gen13) ──
const ADLP_IDS: &[u16] = &[
0x46A6, 0x46A8, 0x4626, 0x46B6, 0x46C6,
@@ -886,6 +919,76 @@ mod tests {
assert_eq!(display_platform_for_device_id(0x0166), None);
}
#[test]
fn test_lunar_lake_device_ids() {
// LNL (Gen15) — Xe2 integrated graphics
for id in [0x6420u16, 0x6480, 0x6481, 0x6482, 0x6483, 0x6484, 0x64A0, 0x64A1, 0x64B0] {
assert_eq!(
display_platform_for_device_id(id),
Some(DisplayPlatform::Gen15),
"LNL device ID {:#06x} should map to Gen15",
id
);
}
}
#[test]
fn test_panther_lake_device_ids() {
// PTL (Gen16) — Xe3 integrated graphics
for id in [0xFF20u16, 0xFF22, 0xFF24, 0xFF30, 0xFF31, 0xFF32, 0xFF40, 0xFF44] {
assert_eq!(
display_platform_for_device_id(id),
Some(DisplayPlatform::Gen16),
"PTL device ID {:#06x} should map to Gen16",
id
);
}
}
#[test]
fn test_gen15_gen16_firmware_keys() {
// LNL keys
assert_eq!(
DisplayPlatform::Gen15.dmc_firmware_key(),
"i915/lnl_dmc.bin"
);
assert_eq!(
DisplayPlatform::Gen15.guc_firmware_key(),
"i915/lnl_guc_70.bin"
);
assert_eq!(
DisplayPlatform::Gen15.huc_firmware_key(),
"i915/lnl_huc.bin"
);
assert_eq!(
DisplayPlatform::Gen15.gsc_firmware_key(),
Some("i915/lnl_gsc_1.bin")
);
// PTL keys
assert_eq!(
DisplayPlatform::Gen16.dmc_firmware_key(),
"i915/ptl_dmc.bin"
);
assert_eq!(
DisplayPlatform::Gen16.guc_firmware_key(),
"i915/ptl_guc.bin"
);
assert_eq!(
DisplayPlatform::Gen16.huc_firmware_key(),
"i915/ptl_huc.bin"
);
assert_eq!(
DisplayPlatform::Gen16.gsc_firmware_key(),
Some("i915/ptl_gsc_1.bin")
);
// Display versions
assert_eq!(DisplayPlatform::Gen15.version(), 20);
assert_eq!(DisplayPlatform::Gen16.version(), 30);
// DMC required
assert!(DisplayPlatform::Gen15.requires_dmc());
assert!(DisplayPlatform::Gen16.requires_dmc());
}
#[test]
fn test_platform_requires_dmc() {
assert!(!DisplayPlatform::Gen9.requires_dmc());
+150
View File
@@ -0,0 +1,150 @@
#!/usr/bin/env bash
# test-virgl-qemu.sh — bounded Mesa virgl runtime validation on QEMU.
#
# Proof target: a redbear-full guest boots in QEMU with a 3D-capable
# virtio-gpu, loads libgallium.so via the EGL loader, and renders a
# GLES2 demo through the host GPU via virgl 3D.
#
# This is the bounded runtime validation for Phase 1 of the 3D driver plan
# (see local/docs/3D-DRIVER-PLAN.md). It addresses the gap that the
# README's "virgl EGL runtime probe open" line leaves open.
#
# What this proves:
# - The Mesa 26.1.4 build actually produces a loadable DRI driver
# - EGL_PLATFORM can be set to wayland (or surfaceless) at runtime
# - libgallium.so exports the driver symbols that the loader expects
# - The libdrm redox.patch redirects DRM ioctls to scheme:drm
# - The redox-drm virtio-gpu backend negotiates virgl 3D with the host
#
# What this does NOT prove:
# - Real-hardware 3D rendering (use test-intel-gpu.sh for that)
# - Mesa Intel iris / AMD radeonsi (those are Phase 4 / Phase 5)
# - Vulkan (that's Phase 6)
#
# Usage:
# ./test-virgl-qemu.sh [--img PATH] [--egl-platform wayland|surfaceless]
# [--driver-override virgl|swrast]
# [--capture-output FILE]
# [--check]
#
# The script is dry-run by default (prints the QEMU command). Pass
# --check to actually run it (requires QEMU + a built redbear-full image).
set -euo pipefail
script_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
redbear_root="$(cd -- "${script_dir}/../.." && pwd)"
usage() {
cat <<USAGE
Usage: test-virgl-qemu.sh [options]
Bounded Mesa virgl runtime validation on QEMU.
Options:
--img PATH Path to redbear-full build (default: build/x86_64/redbear-full/harddrive.img)
--egl-platform NAME EGL_PLATFORM to set (default: wayland)
--driver-override D MESA_LOADER_DRIVER_OVERRIDE value (default: virgl)
--capture-output FILE Write QEMU output to FILE (default: stdout)
--check Actually run the QEMU launch (requires QEMU + image)
--timeout SECONDS QEMU timeout in seconds (default: 60)
--ram MB RAM in MB for QEMU (default: 2048)
--smp N vCPU count for QEMU (default: 4)
--help Show this message
Without --check, the script prints the qemu-system-x86_64 command that would be
launched and exits 0. With --check, the command is executed and the script
captures the guest's guest-side Mesa loader output via the kernel log.
This honors the policy from local/docs/MESA-VIRGL-RUNTIME.md (Phase 1
acceptance criteria): the build must produce a loadable DRI driver and
the EGL_PLATFORM must select virgl in a QEMU guest with a 3D-capable
virtio-gpu device.
USAGE
}
img_path=""
egl_platform="wayland"
driver_override="virgl"
capture_output=""
do_check=0
timeout_secs=60
ram_mb=2048
smp_count=4
while [[ $# -gt 0 ]]; do
case "$1" in
--img) img_path="${2:-}"; shift 2 ;;
--egl-platform) egl_platform="${2:-}"; shift 2 ;;
--driver-override) driver_override="${2:-}"; shift 2 ;;
--capture-output) capture_output="${2:-}"; shift 2 ;;
--check) do_check=1; shift ;;
--timeout) timeout_secs="${2:-}"; shift 2 ;;
--ram) ram_mb="${2:-}"; shift 2 ;;
--smp) smp_count="${2:-}"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; usage; exit 2 ;;
esac
done
# Default image path
if [[ -z "$img_path" ]]; then
img_path="${redbear_root}/local/recipes/libs/mesa/target/x86_64-unknown-redox/build/redbear-full/harddrive.img"
fi
if [[ ! -f "$img_path" ]]; then
img_path="${redbear_root}/build/x86_64/redbear-full/harddrive.img"
fi
# Build the QEMU command.
# Crucial: virtio-vga-gl (NOT virtio-gpu/virtio-vga) is the 3D-capable device.
# -device virtio-vga-gl,virgl=on : required for host->guest 3D
# -display gtk,gl=on : host exposes EGL surface
# -machine q35 : modern Intel chipset (default in our scripts)
qemu_cmd=(
qemu-system-x86_64
-machine q35
-smp "${smp_count}"
-m "${ram_mb}"
-drive file="${img_path}",format=raw,if=virtio
-device virtio-vga-gl,virgl=on
-display gtk,gl=on
-boot d
-serial stdio
-no-reboot
-vga none
)
# Inject the Mesa loader env vars via QEMU fw_cfg (or via -append on the
# kernel command line for the launch).
# `EGL_PLATFORM=redox` would be ideal — but currently the redox platform
# is missing in Mesa 26.1.4 (see local/docs/3D-DRIVER-PLAN.md Phase 3).
# Until Phase 3 lands, `wayland` is the only path that reaches Mesa at all;
# even then, the loader will fall back to swrast unless the driver override
# is set.
#
# These vars are passed via a small script that runs after login.
runtime_env=(
"EGL_PLATFORM=${egl_platform}"
"MESA_LOADER_DRIVER_OVERRIDE=${driver_override}"
"MESA_DEBUG=loader"
)
# Print the runtime command for transparency.
echo "QEMU command: ${qemu_cmd[*]}"
echo "Mesa runtime env: ${runtime_env[*]}"
echo "Image: ${img_path}"
if [[ ! -f "$img_path" ]]; then
echo "WARN: image not found at ${img_path}; --check will fail" >&2
fi
if [[ ${do_check} -eq 0 ]]; then
echo "DRY-RUN: pass --check to actually launch QEMU."
exit 0
fi
# Real run.
if [[ -n "$capture_output" ]]; then
timeout "${timeout_secs}" "${qemu_cmd[@]}" 2>&1 | tee "$capture_output"
else
timeout "${timeout_secs}" "${qemu_cmd[@]}"
fi