内屏(eDP)点亮:完整诊断记录
本文记录 “跑码时内屏正常、进系统后黑屏” 这一问题的完整排查过程与技术结论,供同机型(Raptor Lake-H + 无独显)遇到相同症状的人参考。
1. 症状
| 阶段 | 现象 |
|---|---|
| 开机跑码 | 内屏正常显示(Verbose 文字正常滚动) |
| 驱动接管瞬间 | 屏幕变黑 |
| 手电筒照射 | 有背光、无画面(背光一直亮着) |
| 外接显示器 | 正常,可进系统 |
| 系统内 | ioreg 能看到内屏(1920×1080,主显示器) |
三条关键事实:系统认得内屏、背光亮着、就是没有画面 —— 说明问题在“视频链路”,不在背光、不在面板识别。
2. 定位过程
2.1 排除背光
- 手电筒能看到背光常亮 → 背光已开
- PCH PWM 占空比已到 100%,但屏幕不亮 → 亮度不走传统 PWM 路径
- 面板 DPCD
0x721 = 0x84:面板处于 AUX 背光模式(背光由 DPCD 寄存器控制),0x722/0x723 = 0xBF00(固件设定的约 74% 亮度)
结论:背光由面板固件通过 DPCD 锁存维持,与“是否有画面”无关。
2.2 锁定视频链路
内核日志给出决定性证据:
FB0: Hardware mode set failed, err = 0xe00002d8
[IGFB][ERROR][AUX] ddi = 0 Time out: 0x5d10023f
0xe00002d8=kIOReturnTimeout,AUX 事务重试耗尽0x5d10023f的 bit28 是 TIMEOUT_ERROR
即:驱动做 modeset 时,所有 AUX 事务都超时,eDP 链路从未完成训练,所以没有视频输出。
2.3 面板与 AUX 硬件是否正常?
用裸寄存器直接访问 DP AUX 通道(绕过驱动栈)做探针,得到:
| 探测 | 结果 |
|---|---|
DPCD 0x000–0x00F(接收器能力) |
可读,正常 |
DPCD 0x202(链路状态) |
0x01(仅 CR 完成,未完成信道均衡) |
DPCD 0x721(背光模式) |
0x84(AUX 背光模式锁存) |
DPCD 0x722/0x723(亮度) |
0xBF00 |
写入 0x722 = 0xFFFF |
AUX 应答 ACK(status=0),但寄存器值不变 |
结论:面板与 AUX 通道本身是好的;面板在链路未训练时对 DPCD 写入返回 ACK 但不落盘(冻结快照行为)。
2.4 为什么固件能、驱动不能?
- 固件(BIOS/UEFI)在开机早期已经完成 eDP 链路训练 → 跑码阶段有画面
- macOS 驱动接管后重新训练这条链路,但它的 AUX 事务要先经过电源井(power well)状态机
- 这台机器的黑苹果环境下,该状态机不工作 → 驱动侧 AUX 全部超时
裸寄存器直连 AUX 是成功的,说明差别只在驱动封装的电源井流程,不在硬件。
3. 失败的尝试(供参考,不要重走)
| 方案 | 结果 |
|---|---|
| 调整 DVMT / 显存补丁 | 无关,FB0 依然 AUX 超时 |
| 反汇编驱动,替换内部 AUX worker(vtable hook) | 会卡启动。在 processKext 阶段改 vtable 影响早期启动路径,两次验证均死机/卡 verbose |
| 修改 DPCD 强制设置链路参数 | 写入被 ACK 但不生效(链路未训练时面板冻结 DPCD) |
| 等待电源井就绪后重试 | 超时依旧,状态机不推进 |
教训:不要在启动关键期用 vtable 钩子改图形驱动内部函数。代价是整个系统起不来。
4. 最终方案:-wex-edp-keep
来自 WhateverXe 上游 issue #43(2026-11)的社区方案。
核心思路:既然固件已经把链路训练好了,就不要重训。
驱动在 modeset 时会先检查链路是否已由固件训练完成:
若 已训练完成 → 返回 Partial modeset(只更新部分状态,不动链路)
加启动参数即可:
- amfi_get_out_of_my_way=1 msgbuf=1048576 -v
+ amfi_get_out_of_my_way=1 msgbuf=1048576 -v -wex-edp-keep
验证
ioreg -l | grep WEXEDPKeep
输出示例:
"WEXEDPKeep" = <01000000 04000000 04000000 00000000 ...>
字段含义:
| 字段 | 值 | 含义 |
|---|---|---|
| version | 1 | 记录结构版本 |
| call | 4 | 驱动共请求 4 次完整 modeset |
| kept | 4 | 4 次全部被拦截为 Partial modeset |
| reasons | 0 | 拦截原因位图(0 = 均为“链路已训练”) |
同时内核日志中的 Hardware mode set failed 完全消失,内屏点亮,Metal 加速正常。
该方案的机制细节
wrapDisplay13ReadAUX中捕获面板 DPCD 的链路能力(capLinkCaps)- 驱动在完整 modeset 时调用
Display13EDPKeep决策 - 满足条件(DDI < 2 且该端口配置为内屏、链路已训练)时返回
Partial modeset - 于是
TRANS_DDI_FUNC_CTL/TRANSCONF/ 时序寄存器按请求更新,但不重新训练链路
5. 代价与限制
| 场景 | 结果 | 原因 |
|---|---|---|
| 睡眠唤醒 | 内屏黑到重启 | 唤醒触发完整 modeset 重训 |
| 手动关闭显示器 | 同上 | 同上 |
| 切换分辨率 / 刷新率 | 同上 | 同上 |
| 日常使用(不碰上述操作) | 完全正常 | — |
规避方式:系统设置里关闭显示器休眠、不手动关屏、分辨率保持默认。
6. 复现所需的最小配置
| 项目 | 值 |
|---|---|
| 核显 | 0xA720(Raptor Lake-H/P Iris Xe) |
| 驱动 | WhateverXe ≥ 0.6.1(0.7.0 验证通过) |
| 补丁 | edp-keep 系列 3 个 commit(eDP 端口准入、VBT panel type 0xFF、keep 决策钩子) |
| 启动参数 | -wex-edp-keep |
| 前提 | 固件阶段内屏已点亮(跑码有画面) |
若跑码阶段内屏就不亮,说明固件没有训练链路,此方案不适用。