# BirmanPlus + LPCAMM2：PMIC Identification 阶段 Fatal (0x406E) 调查报告

**分支**: `birman`　**板子**: BirmanPlus（借用 Selkirk 内存配置）＋ LPCAMM2
**CPU**: AMD Ryzen AI 9 HX 470（Radeon 890M，Gorgon Point 家族，官方规格 LPDDR5X-8533 / DDR5-6400）
**日期**: 2026-08-06 ～ 2026-08-07

---

## 1. 背景

- BirmanPlus 参考设计是 memory-down（SPD 硬编码在板上）。这块板子加了 LPCAMM2 插槽，因此内存配置改为借用 Selkirk 的方案。
- Board-id 映射（`ApcbData_GID_0x1704_Type_BoardIdGettingMethod.c`）把 BirmanPlus+LPCAMM2 从 instance 2 改成了 **instance 11 = `CRB_Selkirk_Instance11`**。
- 四份实测 UART log（仓库根目录）：`apu_Samsung.log`、`apu_cx.log`（长鑫/CXMT）、`apu_Micron.log`、`apu_sk.log`（SK Hynix）。
  **注意**：这几个文件里混了个别 null byte，会被 `file`/`grep` 误判成二进制文件，搜索时要加 `grep -a`。

---

## 2. 现象

镁光(Micron)、SK Hynix 两根模组在 **PMIC identification 阶段**直接 Fatal（错误码 `0x406E`），DRAM 训练根本没开始；三星、长鑫两根模组能顺利通过并完整开机。四根模组实测结果对比：

| 模组 | PMIC 厂商 | PMIC Revision | Reg 0x3B 读值 | DIMM 额定速度(SPD) | 结果 |
|---|---|---|---|---|---|
| Samsung | MPS | 0x2 | **0x05** | 4267MHz(=8533 MT/s) | ✅ 训练通过，确认完整开机 |
| 长鑫 CXMT | MPS | 0x0 | **0x05** | 4267MHz(=8533 MT/s) | ✅ 训练通过，确认完整开机 |
| 镁光 Micron | IDT | 0x20 | **0x10** | 3750MHz(=7500 MT/s) | ❌ PMIC identification 阶段 Fatal |
| SK Hynix | MPS | 0x2 | **0x04** | 3750MHz(=7500 MT/s) | ❌ PMIC identification 阶段 Fatal |

失败时的典型日志（镁光、SK Hynix 完全一样的信号）：

```
PMIC validate identification
PMIC Register 0x3B = 0x10        ← 镁光；SK Hynix 是 0x4
ABL - Error reported
ABL - Debug Error info, MajorError: 9,  MinorError.SocketCount: 406E
ABL - a FATAL Error has been detected, Minor Error: 406E,  DataA: 0, DataB: 0
Ps Err - unsupported Error code
 * FATAL Event: 0000406E Data: 0, 0
```

`0x406E` = `ABL_MEM_ERROR_PMIC_REAL_TIME_ERROR`，定义在 `AGESA/AgesaPkg/Include/AmdRas.h:328`（"The PMIC is reporting that there is Real-time error"）。DataA/DataB 为 0 是因为在 identification 这一步就摆了，还没读到后面 `PMIC Error Check` 步骤该填的 0x08/09/0A/0B/33 寄存器。

通过路径（三星/长鑫）在同一步骤读到的是：`0x3B=0x05` → `0x3C=0xB` → `0x3D=0x2A`，然后走 `PMIC Persistent Error Check`（把 `0x1A` 从 `0x90` 写成 `0x80`，清掉一个 bit4/0x10 标志位）→ `PMIC Overrides`（设 VDD2H/VDD2L/VDDQ/VPP，进入 Programmable Mode）→ `PMIC Send VR Enable` → `PMIC Error Check`（08/09/0A/0B/33 全干净）→ 进入真正的 DDR 训练。

**关键点：identification 是 ABL 对 PMIC 做的第一件事，在这之前 ABL 没有对它做任何跟频率/电压相关的配置**——`PMIC Overrides`（真正会按目标频率设置电压的步骤）在 identification **之后**才执行。所以镁光/SK Hynix 死的时候，ABL 还没来得及做任何差异化的电压 programming，0x3B 这个值反映的更像是 PMIC 自己上电后的原始硬件状态。

---

## 3. 已排除的假设

- **不是 IDT 这个 PMIC 厂商不兼容**：SK Hynix 用的 PMIC 跟三星**完全同厂商同 revision**（MPS rev 0x2），却依然 fatal，只是读到的值不同（0x04 vs 三星的 0x05）。如果是厂商不兼容，同款 PMIC 应该表现一致。
- **不是模组本身物理损坏/PMIC 硬件坏了**：镁光、SK Hynix 这两根模组在其他笔记本上都能正常使用，说明模组和 PMIC 本身是健康的，问题只在这一台机器/这套 BIOS 配置的组合上才出现。
- **同一根失败模组多次冷启动（真断电）复测过，现象没有变化**：每次都在同一个点 fatal，不是偶发/随机的。
- **不是训练用的电气参数表（`PsBusCfgDRAMDOWN_CE80.c`，按频率分档配 ODT/驱动强度）导致的**：这个表要等到训练阶段（2D training/PHY init）才会被查，PMIC identification 发生得更早，还没轮到这个表。
- **不是板级内存频率上限表导致的**：那张表（`PsMaxFreqDRAMDOWN*.c`）是板级配置，四份 log 里算出来的值完全一样（都是 3750/7500），跟哪根模组无关，不会对镁光/SK Hynix 做差异化处理。
- **不是频率档位决定的**：DIMM 额定速度(8533 vs 7500) 与结果之前看起来有 2:2 的巧合关联，但反编译确认（见第 4 节）ABL 在这一步实际测的是寄存器 0x3B 的一个具体 bit，跟频率/DIMM 自报速度完全无关，之前的"经验关联"已被证实只是巧合。

---

## 4. 寄存器 0x3B 是什么 —— 已通过反编译确认判断逻辑

- **不在** `AmdRas.h` 里列出的"real-time error"寄存器组（那组是 0x08/09/0A/0B/33，是后面 `PMIC Error Check` 才读的）。
- **该寄存器实际是 JEDEC 标准 JESD301-3（《PMIC52x0 LP5 Power Management Integrated Circuit (PMIC) Device Specification》）里定义的**——这解释了为什么 MPS 和 IDT 两个不同厂商的芯片在 ABL 眼里是同一套寄存器地址。

### 反编译确认的判断逻辑

反编译 ABL 二进制（TypeId0x30，19 段 zlib 压缩流，解压后约 1.05MB ARM 代码，已解压副本见 session scratchpad `abl_full.bin`），定位到 `PMIC validate identification` 函数本体（`arm-none-eabi-objdump` 反汇编，Thumb-2），完整还原出判断逻辑：

```
读 0x3B → log "PMIC Register 0x3B = 0x%x"
若 (0x3B & 0x01) == 0        →  直接跳到 Fatal（根本不读 0x3C / 0x3D）
若 (0x3B & 0x01) == 1        →  继续读 0x3C、0x3D
    若 0x3C != 0 或 0x3D != 0  →  通过，继续往下走
    若 0x3C == 0 且 0x3D == 0  →  Fatal
Fatal 路径: MajorError=9, MinorError=0x406E, TP=0xE331 → ABL_MEM_ERROR_PMIC_REAL_TIME_ERROR
```

**核心结论：ABL 实际测试的是寄存器 0x3B 的 bit0（最低位），不是"精确等于 0x05"，也跟频率/厂商无关。** 用四份实测数据验证，完全吻合：

| 模组 | 0x3B | bit0 | 结果 | 是否与代码逻辑吻合 |
|---|---|---|---|---|
| Samsung | 0x05 = `0b101` | **1** | 继续读 0x3C=0xB(非零)→PASS | ✅ |
| 长鑫 CXMT | 0x05 = `0b101` | **1** | 继续读 0x3C=0xB(非零)→PASS | ✅ |
| 镁光 Micron | 0x10 = `0b10000` | **0** | 直接 Fatal，从未读 0x3C/0x3D | ✅（log 里确实没有 0x3C/0x3D 那两行） |
| SK Hynix | 0x04 = `0b100` | **0** | 直接 Fatal，从未读 0x3C/0x3D | ✅（log 里确实没有 0x3C/0x3D 那两行） |

之前"必须精确等于 0x05 才能过"的猜测被推翻——真正的判据只是 bit0 这一个标志位。0x3C/0x3D 更可能是真正的芯片识别字节（两次 PASS 里数值完全相同：0xB / 0x2A），但只有 bit0(0x3B) 先过了才会去读它们；bit0 本身看起来是 PMIC 自己上报的一个"就绪/OK"状态位。

---

## 5. 下一步建议

判断逻辑已经通过反编译确认（见第 4 节），问题精确收敛为：**镁光、SK Hynix 这两根模组的 PMIC，在这台机器上报出来的 0x3B 寄存器 bit0 是 0（未就绪/未 OK），而三星、长鑫是 1**。接下来能做的：

1. 如果拿到 JEDEC JESD301-3 文档，查一下 0x3B bit0 官方定义是什么状态位（比如是否是"上电就绪"、"校准完成"之类），能直接确定这是时序问题还是真故障。
