base: bump submodule — acpid GPE _Lxx/_Exx dispatch + PM timer (0485ae66)

Also: redox-drm DPCD AUX stub replaced with real implementation.

- redox-drm/intel/display.rs: read_dpcd skeleton (hardcoded
  vec![0x12,0x0A,0x84,0x01]) replaced with real native AUX channel
  read. aux_read() implements the DP AUX protocol: native read cmd
  (0x9) + 20-bit address + len-1 written to DP_AUX_CH_DATA, SEND_BUSY
  + message size + MTL POWER_REQUEST to DP_AUX_CH_CTL, DONE/error
  polling, ACK reply check, payload extract. Per zero-stub policy.
  Reference: Linux intel_dp_aux.c + intel_dp_aux_regs.h, VESA DP 1.4.

- redox-drm/intel/backlight.rs: remove leftover fake_mmio_size test
  artifact.

- Plan doc: Phase 3.3 marked code-complete (GMBUS EDID real, DPCD
  AUX real; modeset proof needs host). ACPICA assessment updated with
  GPE _Lxx/_Exx dispatch and PM timer.
This commit is contained in:
2026-07-22 19:15:05 +09:00
parent 07ba337133
commit c0410449cb
4 changed files with 89 additions and 6 deletions
@@ -101,6 +101,8 @@ the existing `acpi-rs` vendored fork + `acpid` daemon:
| _DSW/_PSW wake arming | ✅ Ported (2026-07-22) | `WakeRegistry::arm_wake_devices()` / `disarm_wake_devices()` — _DSW(1)/_PSW(1) enable + GPE wake enable |
| Sleep state discovery | ✅ Ported (2026-07-22) | `SleepStates::discover()` — _S0 through _S5 enumeration |
| GPE block handling | ✅ Already in acpid/gpe.rs | FADT-driven, write-1-to-clear, enable preserve |
| GPE _Lxx/_Exx dispatch | ✅ Ported (2026-07-22) | `enabled_active_gpes()` + `\_GPE._L{gpe:02X}`/`_E{gpe:02X}` method evaluation in handle_sci (evgpe.c acpi_ev_gpe_detect) |
| ACPI PM timer | ✅ Ported (2026-07-22) | `pm_timer_read()` from FADT pm_timer_block; `/scheme/acpi/pmtimer` endpoint (3.579545 MHz) |
| EC query protocol | ✅ Already in acpid/ec.rs | SCI_EVT poll/IRQ, QR_EC drain, bounded at 32 |
| Fixed event dispatch | ✅ Already in acpid/power_events.rs | PM1_STS PWRBTN/SLPBTN/RTC |
| Sleep/wake (S0ix entry) | 🟡 Partial | `enter_s2idle()` now arms wake devices; `exit_s2idle()` disarms them. MWAIT idle loop remains (kernel idle-loop work) |
@@ -235,7 +237,7 @@ Follows `local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md` Workstream C.
|---|---|---|---|
| 3.1 | Validate vesad at native panel mode (eDP; likely 2560×1600); confirm fbcond + any framebuffer consumers | vesad/bootloader EDID handoff | S |
| 3.2 | ~~Per-generation display differentiation~~ **INVESTIGATED AND DISPROVEN (2026-07-22)** — register offsets are IDENTICAL from Gen8 (SKL) through Gen14 (MTL): PIPECONF=0x70008, PLANE_CTL=0x70180, PLANE_SURF=0x7019C, DDI_BUF_CTL=0x64000, HTOTAL=0x60000. Only CHICKEN_TRANS has a DISPLAY_VER>=14 branch. The real MTL gap is DMC firmware loading (Phase 3.4), not register offsets. | `redox-drm/source/src/drivers/intel/{mod,display}.rs` | ~~L~~ → ✅ DONE (investigation) |
| 3.3 | Real connector/EDID bring-up on eDP: GMBUS read at panel; bounded modeset proof via `redbear-drm-display-check` on the host | display.rs + test-drm-display-runtime.sh | M |
| 3.3 | Real connector/EDID bring-up on eDP: GMBUS read at panel; bounded modeset proof via `redbear-drm-display-check` on the host | display.rs + test-drm-display-runtime.sh | M → 🟡 CODE-COMPLETE (2026-07-22) — GMBUS EDID read already real (I2C via GMBUS0-3); **DPCD AUX stub replaced with real native AUX channel read** (DP_AUX_CH_CTL/DATA, native read cmd 0x9, ACK check, MTL POWER_REQUEST). Modeset proof + panel bring-up need host boot. |
| 3.4 | **DMC firmware load sequence**: CSS header parse, DMA-to-DMC-store, DC state enable — port from Linux i915 `intel_dmc.c`. Consume the already-preloaded `mtl_dmc.bin` | `intel/mod.rs`, new `intel/dmc.rs`; firmware-loader | ML → ✅ DONE (2026-07-22) — full DMC v1+v3 parser, payload MMIO loading, DisplayPlatform enum, wired into IntelDriver::new() |
| 3.5 | eDP backlight control (DDI PWM / DPCD) — brightness keys need WMI (Phase 9); scheme-level brightness first | new `intel/backlight.rs` | M → ✅ DONE (2026-07-22) — CPU PWM backlight with UTIL_PIN mode setup, BLC_PWM_CPU_CTL[2] duty cycle control, enable/disable/set_brightness, Gen9+ register offsets |
| 3.6 | GuC/HuC/GSC: manifest entries now, load sequences **deferred** (render path, not display blocker). Document as convergence work in DRM plan | `main.rs` firmware keys | S (manifest only) → ✅ DONE (2026-07-22) — guc_firmware_key(), huc_firmware_key(), gsc_firmware_key() on DisplayPlatform; manifest logged at IntelDriver::new() |
@@ -138,8 +138,6 @@ mod tests {
#[test]
fn brightness_clamped_to_max() {
let mut bl = Backlight::new(0);
let fake_mmio_size = 0x50000;
let _ = fake_mmio_size;
bl.current = bl.max_brightness + 1;
assert!(bl.current > bl.max_brightness);
}
@@ -61,6 +61,21 @@ const EDID_SLAVE_ADDR: u8 = 0x50;
/// EDID block size in bytes.
const EDID_BLOCK_SIZE: usize = 128;
const DP_AUX_CH_CTL_BASE: usize = 0x64010;
const DP_AUX_CH_DATA_BASE: usize = 0x64014;
const AUX_CTL_SEND_BUSY: u32 = 1 << 31;
const AUX_CTL_DONE: u32 = 1 << 30;
const AUX_CTL_TIME_OUT_ERROR: u32 = 1 << 28;
const AUX_CTL_RECEIVE_ERROR: u32 = 1 << 25;
const AUX_CTL_MESSAGE_SIZE_SHIFT: u32 = 20;
const AUX_CTL_POWER_REQUEST: u32 = 1 << 19;
const AUX_CTL_POWER_STATUS: u32 = 1 << 18;
const AUX_NATIVE_READ: u8 = 0x9;
const AUX_REPLY_ACK: u8 = 0x0;
const AUX_MAX_PAYLOAD: usize = 16;
#[derive(Clone, Copy, Debug)]
pub struct DisplayPipe {
pub index: u8,
@@ -247,8 +262,76 @@ impl IntelDisplay {
return Vec::new();
}
debug!("redox-drm: Intel AUX/DPCD skeleton read on port {}", port);
vec![0x12, 0x0A, 0x84, 0x01]
let mut dpcd = vec![0u8; 16];
match self.aux_read(port, 0x00000, &mut dpcd) {
Ok(()) => {
debug!("redox-drm: DPCD read on port {}: {:02x?}", port, &dpcd[..4]);
dpcd
}
Err(e) => {
debug!("redox-drm: DPCD AUX read failed on port {}: {}", port, e);
Vec::new()
}
}
}
/// Native AUX DPCD read (Linux intel_dp_aux.c, VESA DP 1.4 §2.6):
/// request [cmd<<4|addr19:16, addr15:8, addr7:0, len-1], reply byte0 nibble = ACK.
fn aux_read(&self, port: u8, address: u32, buf: &mut [u8]) -> Result<()> {
let len = buf.len().min(AUX_MAX_PAYLOAD);
if len == 0 {
return Err(DriverError::InvalidArgument("AUX read of zero length".into()));
}
let ctl = DP_AUX_CH_CTL_BASE + usize::from(port) * PORT_STRIDE;
let data_base = DP_AUX_CH_DATA_BASE + usize::from(port) * PORT_STRIDE;
let b0 = (AUX_NATIVE_READ << 4) | ((address >> 16) & 0x0F) as u8;
let b1 = ((address >> 8) & 0xFF) as u8;
let b2 = (address & 0xFF) as u8;
let b3 = (len - 1) as u8;
self.write32(data_base, u32::from_ne_bytes([b0, b1, b2, b3]))?;
for i in 1..5 {
self.write32(data_base + i * 4, 0)?;
}
let ctl_val = AUX_CTL_SEND_BUSY
| (5u32 << AUX_CTL_MESSAGE_SIZE_SHIFT)
| AUX_CTL_POWER_REQUEST;
self.write32(ctl, ctl_val)?;
let mut timeout: u32 = 200_000;
let status = loop {
let status = self.read32(ctl)?;
if status & AUX_CTL_DONE != 0 {
break status;
}
if status & (AUX_CTL_TIME_OUT_ERROR | AUX_CTL_RECEIVE_ERROR) != 0 {
return Err(DriverError::Io(format!(
"AUX read error on port {port}: status={status:#010x}"
)));
}
timeout = timeout
.checked_sub(1)
.ok_or_else(|| DriverError::Io(format!("AUX read timeout on port {port}")))?;
};
if status & AUX_CTL_POWER_REQUEST != 0 && status & AUX_CTL_POWER_STATUS == 0 {
debug!("redox-drm: AUX power status not set on port {}", port);
}
let mut resp = [0u8; 20];
for i in 0..5 {
let val = self.read32(data_base + i * 4)?;
resp[i * 4..i * 4 + 4].copy_from_slice(&val.to_ne_bytes());
}
if (resp[0] >> 4) & 0x3 != AUX_REPLY_ACK {
return Err(DriverError::Io(format!(
"AUX read NACK/DEFER on port {port}: reply={:#04x}",
resp[0]
)));
}
buf[..len].copy_from_slice(&resp[1..1 + len]);
Ok(())
}
pub fn set_mode(&self, pipe: &DisplayPipe, mode: &ModeInfo) -> Result<()> {