## 1. 背景与现象

- **设备**：Google Kaisa（Acer CXI4 Chromebox，基于 Puff baseboard）  
- **固件**：coreboot + Chrome EC  
- **主要问题**：
  - Windows 下曾出现热事件关机；
  - EC 控扇仅依赖一颗板载热敏电阻，温度响应滞后于 CPU，风扇启动与拉满偏晚。

本文整理 Puff/Kaisa 上 **温度传感器、EC 温控、DPTF 控扇** 的整体路径，并记录调试 DPTF FAND/\_FSL 时的关键发现。

---

## 2. 温度与 EC 的关系概览

- **CPU/主机侧温度**：
  - Linux：`/sys/class/thermal/thermal_zone*` 中的 `TCPU`、`x86_pkg_temp` 等，由 CPU/PCH 提供，不经过 EC。
  - Windows：DPTF 通过 ACPI 热区（如 `\_SB.PCI0.TCPU`）取 CPU 温度。

- **EC 侧温度**（Puff/Kaisa）：
  - 只有 **1 路板载 thermistor**：
    - ADC：`ADC_TEMP_SENSOR_1`（NPCX_ADC_CH0）
    - 逻辑 ID：`TEMP_SENSOR_CORE`
    - 读函数：`get_temp_3v3_30k9_47k_4050b`
  - EC 每秒读这路 ADC，写入 EC memory map，对外通过 ACPI 暴露为 `TSR0`。

**结论**：  
目前板上可用的温感来源只有两类：CPU 自身温度 + EC 的一颗板载 thermistor，没有额外硬件温感。

---

## 3. EC 控扇链路（Puff/Kaisa）

### 3.1 板级配置（`ec/board/puff/board.c` & `board.h`）

- 温度枚举：

```c
enum temp_sensor_id {
	TEMP_SENSOR_CORE,
	TEMP_SENSOR_COUNT
};
```

- ADC 与 `temp_sensors[]`：

```c
[ADC_TEMP_SENSOR_1] = {
	.name = "TEMP_SENSOR_1",
	.input_ch = NPCX_ADC_CH0,
	.factor_mul = ADC_MAX_VOLT,
	.factor_div = ADC_READ_MAX + 1,
},

const struct temp_sensor_t temp_sensors[] = {
	[TEMP_SENSOR_CORE] = {
		.name = "Core",
		.type = TEMP_SENSOR_TYPE_BOARD,
		.read = get_temp_3v3_30k9_47k_4050b,
		.idx = ADC_TEMP_SENSOR_1,
	},
};
```

- EC 的温阈值与风扇曲线（`thermal_params[]`）：

```c
const static struct ec_thermal_config thermal_a = {
	.temp_host = {
		[EC_TEMP_THRESH_WARN] = 0,
		[EC_TEMP_THRESH_HIGH] = C_TO_K(68),
		[EC_TEMP_THRESH_HALT] = C_TO_K(78),
	},
	.temp_host_release = {
		[EC_TEMP_THRESH_WARN] = 0,
		[EC_TEMP_THRESH_HIGH] = C_TO_K(58),
		[EC_TEMP_THRESH_HALT] = 0,
	},
	.temp_fan_off = C_TO_K(40),  // <40℃ 关风扇
	.temp_fan_max = C_TO_K(60),  // ≥60℃ 满速
};

struct ec_thermal_config thermal_params[] = {
	[TEMP_SENSOR_CORE] = thermal_a,
};
```

### 3.2 通用 thermal 引擎（`ec/common/thermal.c`）

- 每秒执行一次 `thermal_control()`：

  1. 遍历所有温度传感器（这里只读 `TEMP_SENSOR_CORE`）：
     ```c
     for (i = 0; i < TEMP_SENSOR_COUNT; ++i)
         rv = temp_sensor_read(i, &t);
     ```
  2. 根据 `thermal_params[i].temp_host[]` 与 `temp_host_release[]` 统计 WARN/HIGH/HALT，触发：
     - `chipset_force_shutdown(CHIPSET_SHUTDOWN_THERMAL);`
     - `throttle_ap(THROTTLE_ON, THROTTLE_HARD/SOFT, THROTTLE_SRC_THERMAL);`
  3. 根据 `temp_fan_off` 和 `temp_fan_max` 计算该传感器需要的风扇百分比：
     ```c
     f = thermal_fan_percent(thermal_params[i].temp_fan_off,
                             thermal_params[i].temp_fan_max,
                             t);
     fmax = max(fmax, f);
     ```
  4. 对所有风扇设置统一需求：
     ```c
     for (i = 0; i < fan_get_count(); i++)
         fan_set_percent_needed(i, fmax);
     ```

**结论**：  
在 “EC 自动控扇” 模式下，风扇完全由 EC 根据这路 thermistor + `thermal_a` 曲线驱动。

---

## 4. DPTF 与 EC 的桥接（ACPI/DPTF 侧）

### 4.1 温度：TSR0..TSR4

- coreboot 的 `ec_dptf_helpers.c` 为 DPTF temp participants 生成 `_TMP`：

```c
/* TSRx._TMP = EC0.TSRD(x) */
acpigen_write_method_serialized("_TMP", 0);
acpigen_emit_byte(RETURN_OP);
acpigen_emit_namestring(acpi_device_path_join(ec, "TSRD"));
acpigen_write_integer(tsr_index);  // 0..4
```

- `ec.asl` 中：

```asl
Method (TINS, 1, Serialized)
{
	Switch (ToInteger (Arg0)) {
		Case (0) { Return (TIN0) }
		Case (1) { Return (TIN1) }
		...
		Default  { Return (TIN0) }
	}
}

Method (TSRD, 1, Serialized)
{
	Local0 = \_SB.PCI0.LPCB.EC0.TINS (Arg0)
	/* 检查 TNCA/TNPR/TNOP/TBAD 省略 */
	Local0 += \_SB.PCI0.LPCB.EC0.TOFS
	Local0 *= 10     // 转为 1/10 K
	Return (Local0)
}
```

- Puff 上：只有 `TEMP_SENSOR_CORE` → `TIN0` → `TSR0`，其它 TSR1..TSR4 基本为空。

### 4.2 风扇：TFN1 + FST/FSL + FAND

根据 DPTF 规范，FAN participant（`TFN1`）需要提供：

- `_FST`：返回 `{ Revision, Control, Speed }`；
- `_FSL(level)`：设置 fan level/duty。

Chrome EC 路径（`ec_dptf_helpers.c`）：

- 写回包 `TFST`：

```c
/* TFST = { Revision, Control, Speed } */
acpigen_write_name("TFST");
acpigen_write_package(3);
acpigen_write_integer(0); /* Revision */
acpigen_write_integer(0); /* Control */
acpigen_write_integer(0); /* Speed */
acpigen_pop_len();        /* Package */
```

- `_FST` 实现大致为：

```c
/* _FST: TFST[1] = EC0.FAND; TFST[2] = FANx_RPM; return TFST */
acpigen_write_method_serialized("_FST", 0);
acpigen_write_store();
acpigen_emit_namestring(acpi_device_path_join(ec, "FAND"));
acpigen_emit_byte(INDEX_OP);
acpigen_emit_namestring("TFST");
acpigen_write_integer(1);  // Control
...
acpigen_write_store();
acpigen_emit_namestring(acpi_device_path_join(ec, "FAN0")); // 实际 RPM 来源
acpigen_emit_byte(INDEX_OP);
acpigen_emit_namestring("TFST");
acpigen_write_integer(2);  // Speed
...
acpigen_emit_byte(RETURN_OP);
acpigen_emit_namestring("TFST");
acpigen_pop_len();
```

- `_FSL(level)` 实现：

```c
/* _FSL(Arg0): Store(Arg0, EC0.FAND) */
acpigen_write_method_serialized("_FSL", 1);
acpigen_write_store();
acpigen_emit_byte(ARG0_OP);
acpigen_emit_namestring(acpi_device_path_join(ec, "FAND"));
acpigen_pop_len();
```

其中 `FAND` 对应 EC ACPI RAM 中地址 `0x04`（`EC_ACPI_MEM_FAN_DUTY`），在 `ec_commands.h` 定义为：

```c
/* DPTF Target Fan Duty (0-100, 0xff for auto/none) */
#define EC_ACPI_MEM_FAN_DUTY 0x04
```

ACPI 通过 `EC_ACPI_MEM_FAN_DUTY` 写入后，EC C 侧（`ec/common/acpi.c`）处理：

```c
case EC_ACPI_MEM_FAN_DUTY:
	dptf_set_fan_duty_target(data);
	break;
```

`dptf_set_fan_duty_target()` 实现（`ec/common/fan.c`）：

```c
/* 0-100% sets duty, out of range means let the EC drive */
void dptf_set_fan_duty_target(int pct)
{
	int fan;

	if (pct < 0 || pct > 100) {
		/* 超出范围：交回 EC 自动控扇 */
		for (fan = 0; fan < fan_count; fan++)
			set_thermal_control_enabled(fan, 1);
	} else {
		/* 合法 0-100：按 duty 控扇，关闭 thermal 自动控扇 */
		for (fan = 0; fan < fan_count; fan++)
			set_duty_cycle(fan, pct);
	}
}
```

读取时，若处于 duty 模式，`dptf_get_fan_duty_target()` 返回 0–100，否则返回 -1，对应 FAND=0xff。

**结论（非常重要）**：

- 写入 **0–100**：DPTF 接管风扇，EC 用该 duty 控扇，thermal 自动模式被关闭；
- 写入 **0xff 或越界值（<0 或 >100，例如 0x80）**：退回 EC 自动控扇模式，FAND 对外显示为 0xff。

---

## 5. 模式选择：EC 控扇 vs Windows DPTF 控扇

### 5.1 EC 控扇模式（稳定默认）

coreboot defconfig 中：

```text
CONFIG_MINIPC_EC_FULL_FAN_CONTROL=y
CONFIG_DRIVERS_INTEL_DPTF_DISABLE_ACTIVE_FAN=y
```

- DPTF 风扇参与者被隐藏/禁用 Active Policy；
- EC 在 `_REG` 时写 `FAND=0xFF`，明确进入自动模式；
- 风扇完全由 EC thermal 引擎（第 3 节）驱动。

适用：  
- 无 Windows DPTF 驱动或不希望依赖 DPTF；  
- 简化行为，只调一条 EC 曲线。

### 5.2 Windows DPTF 控扇模式（实验/优化）

coreboot defconfig 中：

```text
# CONFIG_MINIPC_EC_FULL_FAN_CONTROL is not set
# CONFIG_DRIVERS_INTEL_DPTF_DISABLE_ACTIVE_FAN is not set
CONFIG_DRIVERS_INTEL_DPTF_ECTST_FAND_DEBUG=y
```

- DPTF FAN（TFN1）暴露给 Windows；  
- Active Policy 启用，DPTF 根据 CPU 温度 + TSR0 等决定何时 `_FSL(level)`；  
- EC 通过 `dptf_set_fan_duty_target(level)` 接收 duty：
  - 0–100：DPTF 覆盖；
  - 0xff/越界：交回 EC 自动。

**前提**：  
Windows 中必须安装并启用 Intel DPTF 驱动（INT3400/INT3404 等设备正常工作），否则不会按策略调用 `_FSL()`。

---

## 6. ECT0 调试：为什么 `_FSL(0x80)` 后 FAND 一直是 0xff？

在 Windows 下，使用 `ECT0._FST/_FSL` 调试 FAND（`logs.txt`）：

```powershell
[1] Current FAND from _FST:
  FAND = 0x46          # 70%，说明曾经处于 duty 模式

[2] Writing FAND via _FSL(0x80) ...

[3] Read-back FAND after _FSL:
  FAND = 0xff

[4] 继续监视 _FST:
  FAND 始终是 0xff
```

**结合第 4 节的实现：**

- 0x80 = 128 > 100 → 按 `dptf_set_fan_duty_target()` 的语义，这是“越界值”：
  - 进入 `pct < 0 || pct > 100` 分支；
  - 调用 `set_thermal_control_enabled(fan, 1)`，**恢复 EC 自动控扇**；
  - `dptf_get_fan_duty_target()` 返回 -1，对 ACPI 显示为 FAND=0xff。

**正确结论**：

- **FSL/FST → EC 的链路是通的**，只是你写入的是一个“退回自动”的值（>100），EC 正确地退出了 DPTF duty 模式；
- `_FST` 一直看到 FAND=0xff，说明当前处于 “auto/none” 状态，而不是链路失效。

**正确的测试方式**：

- 要验证 DPTF/ECT0 控扇是否生效，应使用 **0–100** 的值：

  ```powershell
  ectest -acpi \_SB.ECT0._FSL 50   # 50%
  ectest -acpi \_SB.ECT0._FST      # FAND 应为 0x32，且风扇转速有变化
  ```

- 要主动退回 EC 自动控扇，可以写 **0xff 或 >100**（例如 0x80）：

### 13.7 用其他方法监控 DPTF 是否发送风扇控制信号

除轮询 `\_SB.ECT0._FST` 看 FAND 是否随温度变化外，可用脚本 `Monitor_DPTF_Fan.ps1` 做两类监控（需管理员、ectest 可用）：

| 模式 | 说明 |
|------|------|
| **check** | 检查本机是否有 DPTF/ESIF 服务、ACPI 设备 INT3404/INT3400、相关驱动，判断 DPTF 栈是否加载。 |
| **poll** | 高频率轮询 `_FST`（默认每 200ms），将时间戳与 FAND 写入 CSV，持续一段时间（默认 60s）。对 CPU 加压时若 CSV 中 FAND 始终不变，可判断 DPTF 未通过 _FSL 写 FAND。 |
| **watch** | 专用于**监控 INT3404 是否发送控扇信号**：轮询 `_FST`，仅在 FAND **发生变化**时在控制台打印（并写 CSV）。若加压过程中出现 “FAND changed: 0xff -> 0x50” 等，说明有对象（多为 INT3404/DPTF）写入了 _FSL；若始终无输出，则 INT3404 未写 _FSL 或 EC 覆盖了写入。 |
| **etw** | 用 logman 采集 DPTF/ESIF 的 ETW（EsifLfEtwProvider 等），记录一段时间后 tracerpt 转 CSV。若已装 Intel DPTF 驱动，可查看是否有风扇/ACPI 相关事件。 |
| **all** | 先 check，再运行 etw（按提示加压后回车停止），最后做 poll 并落盘。 |

用法示例：

```powershell
.\Monitor_DPTF_Fan.ps1 -Mode check
.\Monitor_DPTF_Fan.ps1 -Mode watch -PollSeconds 120 -PollIntervalMs 150   # 监控 INT3404 是否发控扇
.\Monitor_DPTF_Fan.ps1 -Mode poll -PollSeconds 120 -PollIntervalMs 150
.\Monitor_DPTF_Fan.ps1 -Mode etw
.\Monitor_DPTF_Fan.ps1 -Mode all
```

结论解读：若 **poll** 阶段在负载下 FAND 始终不变，且 **check** 未见 DPTF 设备/服务，则当前系统未通过 DPTF 发送风扇控制信号；若 ETW 中有相关事件，可进一步对照 DPTF 文档看是否包含 _FSL 调用。

- 要主动退回 EC 自动控扇，可以写 **0xff 或 >100**（例如 0x80）：
  ```powershell
  ectest -acpi \_SB.ECT0._FSL 0xff # 或 0x80 等 >100
  ectest -acpi \_SB.ECT0._FST      # FAND 应回到 0xff
  ```

---

## 7. 总结

1. Puff/Kaisa 的 EC 只有一颗板载 thermistor（`TEMP_SENSOR_CORE`），所有 EC 自动温控与关机/限频都基于这一路。
2. coreboot + Chrome EC 已经在 ACPI/DPTF 层实现了完整的 FAN 接口（TFN1._FST/_FSL）：
   - `_FSL(level)` → 写入 `EC_ACPI_MEM_FAN_DUTY` → `dptf_set_fan_duty_target(level)`；
   - `_FST()` → 回读当前 FAND 与实际 RPM。
3. EC 明确定义了 fan duty 的语义：
   - **0–100**：DPTF 直接指定 duty，EC 关闭 thermal 自动控扇；
   - **0xff 或越界**：退出 DPTF duty 模式，交回 EC 自动控扇，FAND 显示为 0xff。
4. Windows 下已枚举到 INT3400/INT3404：在设备管理器中分别显示为 **Intel(R) Dynamic Tuning Manager**（INT3400）与 **Intel(R) Dynamic Tuning Fan Participant**（INT3404），设备实例路径为 `ACPI\INT3400\0`、`ACPI\INT3404\0`，说明 **DPTF 风扇控制器栈与 ACPI 风扇设备都是存在的**。
5. 实测轮询 `\_SB.ECT0._FST` 时，FAND 只在手动 `_FSL(x)` 时改变，负载/温度变化本身并不会让 DPTF 自动写入 FAND；结合 INT3404 存在但 FAND 不随温度变化，可以判断：当前固件/策略仍以 **EC 自动曲线为主控，DPTF 风扇参与者更多处于观察/可选控制状态**。
6. “`_FSL(0x80)` 后 FAND 一直 0xff” 是因为 0x80>100，被 EC 解读为 “放弃 DPTF 覆盖、恢复 EC 自动”，而非链路未接通。
7. 选择 EC 控扇还是 DPTF 控扇，只需在 coreboot defconfig 中切换：
   - EC 控扇：`CONFIG_MINIPC_EC_FULL_FAN_CONTROL=y` + `CONFIG_DRIVERS_INTEL_DPTF_DISABLE_ACTIVE_FAN=y`；
   - DPTF 控扇：两者都不设，并确保 Windows 中 DPTF 驱动工作正常。

### 7.1 固件 20260224034907 配置确认（DPTF 控扇固件）

- **固件**：`20260224034907` 目录下为 `coreboot_edk2-kaisa-mrchromebox_20260224.rom` 的构建产物，含 `.config`、`build.log`。
- **.config 中与风扇控制相关的项**：
  - `# CONFIG_MINIPC_EC_FULL_FAN_CONTROL is not set` → EC **非**全权控扇，主机可写 FAND；
  - `# CONFIG_DRIVERS_INTEL_DPTF_DISABLE_ACTIVE_FAN is not set` → DPTF 主动风扇策略**开启**；
  - `CONFIG_DRIVERS_INTEL_DPTF_ECTST_FAND_DEBUG=y` → 暴露 ECT0 调试设备，可读/写 FAND。
- **结论**：该固件为 **DPTF 控扇** 配置，风扇应由 DPTF 通过 _FSL 写 FAND，EC 按 FAND 执行。
- **与实测的差异**：在 Windows 下用 `Monitor_DPTF_Fan.ps1 -Mode watch` 观察，CPU 升温时 **FAND 从未变化**（无 “FAND changed”），说明 **DPTF 驱动/策略没有在按温度调用 _FSL**。问题在 **Windows/DPTF 侧**，不在固件是否为 DPTF 控扇。
- **建议**：在 Windows 中检查电源/热管理是否有 “Intel DPTF” 或 “平台热管理” 并确认已启用；从 Microsoft Update Catalog 或 OEM 安装/更新 “Intel Dynamic Platform and Thermal Framework” 驱动后，再以 watch 模式观察负载下 FAND 是否变化。

### 7.2 Windows 电源/热管理检查步骤（驱动已确认时）

硬件与 DPTF 驱动（INT3400/INT3404、esifsvc）已确认正常时，若 FAND 仍不随温度变化，可逐项检查电源与热管理是否“关掉”了 DPTF 控扇：

| 步骤 | 位置 | 检查内容 |
|------|------|----------|
| 1 | **设置 → 系统 → 电源** | 查看当前“电源模式”（平衡/最佳性能等）；部分机型在此有“热管理”或“Intel 图形/平台”相关项，确认未选“静音/省电”导致不拉高风扇。 |
| 2 | **控制面板 → 电源选项 → 更改计划设置 → 更改高级电源设置** | 在列表中查找 **处理器电源管理**、**Intel**、**Thermal**、**平台热管理** 或 OEM（如 Acer）提供的“风扇/热管理”子项。若有“最大处理器状态”“散热方式”等，可先选“主动/积极散热”或提高最大状态，排除因电源计划限制导致 DPTF 不写 _FSL。 |
| 3 | **设备管理器 → 系统设备 → Intel(R) Dynamic Tuning Fan Participant** | 属性 → 驱动程序：确认设备已启用、无感叹号；若有“电源管理”选项卡，可取消勾选“允许计算机关闭此设备以节约电源”（若存在），避免被省电关闭。 |
| 4 | **OEM 自带软件** | 若装有 Acer Care、Lenovo Vantage、Dell Power Manager 等，在“性能/散热/风扇”类设置中查看是否有“静音模式”“禁用 DPTF”“自定义风扇曲线”等；若有且设为静音或禁用 DPTF，改为平衡/性能或启用 DPTF 后再用 watch 观察。 |
| 5 | **当前电源方案** | 管理员 PowerShell：`powercfg /getactivescheme` 查看当前方案；必要时切换为“高性能”或“卓越性能”后再次运行 `Monitor_DPTF_Fan.ps1 -Mode watch`，看负载下是否出现 “FAND changed”。 |

脚本 `Monitor_DPTF_Fan.ps1 -Mode check` 会输出当前电源方案及上述 1～4 的手动检查提示，便于逐项核对。

这份笔记即为当前 Puff/Kaisa 上温控与 EC/DPTF 行为的整理，可作为后续调整 EC 曲线或 DPTF 策略时的参考。
# 温控与 EC 传感器分析笔记

本文档记录 Chromebox 刷 coreboot 后，Windows 热关机、Linux 温控、EC 温度源及 I2C 设备识别相关的有用信息。

---

## 1. 问题背景

- **现象**：Windows 下出现热事件关机；EC 控扇仅依赖板载温度传感器，延迟与偏差大，导致风扇响应滞后。
- **根因**：EC 只有一路 ADC 热敏电阻（“Core”），且该点滞后于 CPU 实际温度，Windows 负载/功耗较高时易触发过热关机。

---

## 2. 热区与 EC 的关系（Linux 视角）

- **thermal_zone**（如 TCPU、x86_pkg_temp）：内核/CPU 热区，数据不经过 EC。
- **EC 获取 CPU trip 的方式**：
  - **硬件**：THERMTRIP#、PROCHOT# 等引脚由 CPU 拉低，EC 直接检测。
  - **软件**：ACPI Notify（thermal zone critical 等）可通知 EC。
- **直接连到 EC 的温度**：cros_ec 上报的 “Core” = EC 自己读的 ADC 热敏电阻；INT3400 与 EC 策略/关机链路相关。

---

## 3. Linux 温控 vs Windows DPTF

| 项目       | Linux 温控              | Windows DPTF                    |
|------------|--------------------------|---------------------------------|
| 策略       | 内核 governor / thermald | OEM 策略引擎 + ACPI             |
| 应用感知   | 一般无                   | 有（游戏/办公等不同策略）      |
| 风扇       | 内核 cooling 或 fancontrol | 常由 EC 独管，DPTF 不控扇      |

DPTF 未真正控扇常见原因：风扇权在 EC；或 OEM 未把风扇暴露给 DPTF；或 Windows 无 EC 风扇驱动。

---

## 4. EC 温度源（以 Puff 板为例）

- **当前**：仅 **1 路** 温度 —— ADC 热敏电阻（`ADC_TEMP_SENSOR_1` → `TEMP_SENSOR_CORE`），读函数 `get_temp_3v3_30k9_47k_4050b`。
- **无 I2C 温度传感器**：board.c 里 temp_sensors[] 只有上述 ADC 项；EC 的 I2C 上接的是 INA3221、PPC、TCPC、POWER、EEPROM 等，无温感芯片。
- **增加温度源的可能**：若硬件有预留（空余 ADC 通道或 EC I2C 上接温感），可在 EC 源码里加 temp_sensor 配置；否则需改硬件。

---

## 5. 主机 I2C 与 EC I2C 是两套总线

- **主机侧**（`i2cdetect -l` 的 i2c-0～i2c-11）：CPU/PCH 的 SMBus、i915 等，由 Linux 枚举；扫描用 `i2c_scan.sh`（调用 i2cdetect）。
- **EC 侧**：EC 固件里 `i2c_ports[]` 定义的 GPIO_I2C0～I2C7，设备在 board.c 中定义。
- **结论**：主机 I2C 扫描到的地址（如 0x08、0x44、0x52…）**不会**出现在 EC 的 board.c 里；EC 能扫的只是自己那几条总线。

---

## 6. 本机 EC I2C 扫描结果（ectool-cec i2cxfer）

| EC Port | 扫到地址     | 用途/推断 |
|---------|--------------|-----------|
| 1       | 0x40         | 电流/功率类，非标准 INA3221 |
| 3       | 0x2c 0x38 0x39 0x3d 0x3f 0x42 | 见下表 |
| 5       | 0x20         | EEPROM (24cxx) |

### Port 3 各地址识别摘要

| Addr | reg 0x00 / 0x80 等 | 可能型号/类型 |
|------|--------------------|----------------|
| 0x2c | 0x77 0x79…；index/data 访问 | Nuvoton Super I/O / I2C 多功能（如 NCT5532D、NCT5577D、NCT38xx）；**可能带温度，需 index/data 读** |
| 0x38 | 0x30 0x30 (ASCII) 等 | GPIO/IO 扩展或显示 |
| 0x39 | 全 0 | 未初始化或空 |
| 0x3d | 全 0 | 可能 SSD1306 或未初始化 |
| 0x3f | 0x80 = 0x5A 0x5E | 某 PMIC/传感器厂商 Device ID；**可能带温度，需查 datasheet** |
| 0x42 | 全 0 | 可能 INA3221 未使能或它用 |

---

## 7. 常见芯片 ID 参考（用于 ec_i2c_identify）

- **0x80 = 0x54 0x49**：TI INA3221/INA219（电流/功率）。
- **0x80 = 0x5A 0x5E**：某厂商 Device ID，多见于 PMIC/传感器，具体型号需查该厂商手册。
- **0x2c 总线、首字节 0x77 等**：Nuvoton NCT55xx/NCT5577D/NCT38xx 等；访问多为 index/data，直接读“reg 0”未必对应真实寄存器。
- **0x20 + 数据区大段 0xff**：常见 EEPROM (24c02 等)。
- **0x38 读得 0x30 0x30**：常见 GPIO/IO 扩展（如 PCA9555）。
- **0x3c/0x3d 全 0**：常见 SSD1306 等 OLED 未初始化。

---

## 8. 哪个可能是我们要找的温度传感器？

- **首选候选：Port 3, 0x2c**  
  Nuvoton NCT 系常带硬件监控温度；需在 EC 内按 **index/data** 协议和该芯片 datasheet 的温度寄存器 index 读取。

- **次选候选：Port 3, 0x3f (0x5A5E)**  
  可能是带温度通道的 PMIC/传感器；需找到对应 datasheet 确认是否有温度寄存器及地址/格式。

- **其余**（0x40/0x42 INA 类、0x38 GPIO、0x39/0x3d、0x20 EEPROM）**不视为温度传感器**。

---

## 9. 脚本与工具

| 脚本/命令 | 作用 |
|-----------|------|
| `linux_collect_sensors.sh` | 收集 Linux 下 thermal zone、hwmon、lm-sensors、ectool temps、dmesg、CPU 信息；报告存当前目录或 /tmp。 |
| `i2c_scan.sh` | 主机侧 I2C 扫描（i2cdetect），扫 i2c-0～i2c-N。 |
| `ec_i2c_scan.sh` | EC 侧 I2C 扫描，用 ectool-cec 的 i2cxfer 对指定 port 扫 0x08～0x77。**须用 ectool-cec**，系统 ectool 无 i2cxfer。 |
| `ec_i2c_identify.sh` | 对指定 port:addr 读 reg 0x00/0x80/0xFE/0xFF/0x0F，并给出可能型号推断。 |

### 使用注意

- 脚本行尾须为 **LF**；若出现 `$'\r': 未找到命令` 等，执行：`sed -i 's/\r$//' 脚本名.sh`。
- EC 扫描/识别需 **sudo**，且 **ECTOOL** 指向 ectool-cec，例如：  
  `ECTOOL=/home/jack/bin/ectool-cec sudo ./ec_i2c_scan.sh`

---

## 10. 后续可做

- 在 EC 源码中查 0x2c 对应芯片的 datasheet，用 **index/data** 读温度寄存器，并在 temp_sensor/thermal 里增加一路。
- 若有 0x5A5E 对应型号的 datasheet，确认是否带温度通道及寄存器，再在 EC 中实现读取。
- Windows 侧可先通过限 CPU 功耗/电源计划降低热负载，减轻 EC 单路温控滞后带来的热关机。

---

## 11. Puff/Kaisa 上增加一路温度传感器的可行性

### 11.1 地址与硬件对应关系（Puff）

- **I2C Port 3（TCPC0）上的 0x2c**：在 Puff 板为 **AN7447 TCPC**（`AN7447_TCPC0_I2C_ADDR_FLAGS = 0x2C`），不是独立温感芯片，不能当第二路温度源使用。
- **0x3f**：同颗 AN7447 的 SPI 转 I2C 接口（`AN7447_SPI0_I2C_ADDR_FLAGS = 0x3F`），读到的 0x5A5E 等为 AN7447 相关，**不是**独立 I2C 温度传感器。
- **结论**：当前 Puff 板 EC 可见的 I2C 总线上，**没有空闲的、可用的 I2C 温度传感器芯片**；笔记中“Port 3 的 0x2c/0x3f 可能是温感”的推断在本板不成立。

### 11.2 可行方向

| 方向 | 说明 |
|------|------|
| **A. 第二路 ADC 热敏电阻** | 若原理图有未用的 ADC 通道 + 热敏电阻，在 `board.h` 增加 `ADC_TEMP_SENSOR_2` 与对应 `enum`，在 `board.c` 的 `adc_channels[]`、`temp_sensors[]`、`thermal_params[]` 各加一项，并用现有 `get_temp_3v3_30k9_47k_4050b` 或对应 thermistor 读函数。 |
| **B. 新增 I2C 温感芯片** | 若硬件在某一 I2C 总线上**新接**温感（如 TMP112/TMP432 等），需：该总线在 `i2c_ports[]` 中、地址不与现有设备冲突；在 EC 中启用对应 driver（如 `CONFIG_TEMP_SENSOR_TMP112`）、在 `board.h` 增加 `TEMP_SENSOR_xxx` 与 `TEMP_SENSOR_COUNT`，在 `board.c` 中增加 `temp_sensors[]` 与 `thermal_params[]`。 |
| **C. 确认 0x5A5E 芯片** | 若某板型在其它 I2C 端口上有独立 0x5A5E 芯片且 datasheet 标明带温度寄存器，可为该芯片写专用 driver（index/data 或普通 I2C 读），再按 B 的方式挂到 `temp_sensors[]`。 |

### 11.3 EC 侧增加一路温度传感器的实现步骤（通用）

1. **board.h**  
   - 增加 `enum adc_channel` 或 I2C 温感用的 `enum`（若用现有 driver，通常只需 `temp_sensor_id`）。  
   - 在 `enum temp_sensor_id` 中增加新 ID（如 `TEMP_SENSOR_BOARD2`），并保证 `TEMP_SENSOR_COUNT` 正确。

2. **board.c**  
   - **ADC 热敏电阻**：在 `adc_channels[]` 增加一路 ADC；在 `temp_sensors[]` 增加一项（`name`、`type`、`read`、`idx`）；在 `thermal_params[]` 增加对应 `ec_thermal_config`。  
   - **I2C 温感**：若为现有 driver（如 TMP112），在 `temp_sensors[]` 增加一项，`read` 指向 driver 的 `get_val`，`idx` 为 channel/index；同样在 `thermal_params[]` 增加一项。  
   - 若需参与控扇：在 `setup_thermal()` 等逻辑中为新 sensor 选择/绑定 thermal table。

3. **Kconfig / 构建**  
   - 若用 I2C 温感 driver，在对应 board 的 `Kconfig` 或 `board.h` 中启用 `CONFIG_TEMP_SENSOR_xxx` 及该 driver 所需的 `I2C_PORT_xxx`。

4. **thermal 策略**  
   - 若希望新传感器参与风扇控制，需在 thermal 逻辑中把新 sensor 的读数纳入（例如与现有 `TEMP_SENSOR_CORE` 取 max，或单独阈值），并保证 `thermal_params[新ID]` 的 `temp_fan_off` / `temp_fan_max` 等已配置。

### 11.4 小结

- **不改硬件**：Puff 上仅能依赖现有 1 路 ADC 热敏电阻（Core）；无法在现有 I2C 设备（0x2c/0x3f 均为 AN7447）上“多出一路”温度传感器。  
- **改硬件**：增加第二路 ADC 热敏电阻，或新接 I2C 温感芯片并接在已有或新增 I2C 总线上，再按 11.3 在 EC 中增加一项 temp_sensor 与 thermal 配置即可。

---

## 12. DPTF 控制风扇的可行性（Puff/Kaisa）

### 12.1 固件侧已支持 DPTF 控扇

- Puff 的 **DPTF 设计本来就是“DPTF 控扇”**：  
  - `baseboard/acpi/dptf.asl` 中定义了 `DPTF_ENABLE_FAN_CONTROL`、DFPS（Fan Performance States）、DART（风扇对 CPU/TSR 的影响）。  
  - Kaisa 的 `overridetree.cb` 里配置了 **Active Policy**：`policies.active[0]` = DPTF_CPU，`policies.active[1]` = DPTF_TEMP_SENSOR_0，即 **CPU 温度 + 板载温感（EC 上报）共同驱动风扇**；另有 `controls.fan_perf[]`、`fine_grained_control`、`step_size` 等。  
  - 注释写明："Active Policy: CPU drives fan (DPTF controls via FAND)"。  
- 风扇档位由 DPTF 通过 ACPI 写 **FAND** 下发给 EC，EC 按 FAND 驱动 PWM；固件表和 devicetree 已具备完整策略，**从固件角度看 DPTF 控扇是可行的**。

### 12.2 当前 Kaisa 配置为何是 EC 控扇

- 为规避“Windows 下无人写 FAND、风扇卡在固定转速”的问题，当前 defconfig 改为 **EC 完全控扇**：  
  - `CONFIG_MINIPC_EC_FULL_FAN_CONTROL=y`：隐藏 DPTF 风扇设备，EC 在 _REG 时写 FAND=0xFF（EC 自动控扇）。  
  - `CONFIG_DRIVERS_INTEL_DPTF_DISABLE_ACTIVE_FAN=y`：关闭 DPTF Active Policy，DPTF 不再写 FAND。  
- 这样 Windows 即使没有 DPTF 驱动，EC 也会按自身 thermistor 控扇，避免“既不用 DPTF 也不写 0xFF”导致的卡死。

### 12.3 若改为 DPTF 控扇

| 项目 | 说明 |
|------|------|
| **固件配置** | 取消 EC 全权控扇、恢复 DPTF 控扇：`CONFIG_MINIPC_EC_FULL_FAN_CONTROL=n`（或不设），`CONFIG_DRIVERS_INTEL_DPTF_DISABLE_ACTIVE_FAN=n`。重新编译刷写后，DPTF 风扇设备可见，Active Policy 生效。 |
| **温度源** | DPTF 使用 **CPU 温度**（\_SB.PCI0.TCPU）+ **EC 上报的板载温感**（TSR0 = TEMP_SENSOR_0，即 Core）。CPU 温度由 OS/驱动提供，响应比单路 EC thermistor 快，有利于提前拉高转速。 |
| **Windows 依赖** | **必须安装 Intel DPTF 相关驱动**（如 INT3400、INT3404 等），否则 OS 不会根据 DPTF 表写 FAND，风扇仍可能不随负载变化。驱动可从 Microsoft Update Catalog 或 OEM 包获取。 |
| **Linux** | 若使用内核 thermal + DPTF ACPI，需相应驱动/用户态配合写 cooling_device；常见做法仍是 EC 控扇或 fancontrol。 |

### 12.4 小结

- **DPTF 控扇在 Puff/Kaisa 上固件可行**：表与策略已就绪，只需改 defconfig 并确保 Windows 有 DPTF 驱动。  
- **EC 控扇**：不依赖 Windows 驱动，适合“通用 Windows/无 DPTF”场景，但仅有一路板载温感，响应偏慢。  
- **二选一**：要么 EC 全权控扇（当前配置），要么 DPTF 控扇（改配置 + 装 Windows DPTF 驱动），不可同时“DPTF 可见但不写 FAND、EC 也不写 0xFF”，否则会再现风扇卡死。

---

## 13. 监视 FAND 与“DPTF 未改变 FAND”的排查

### 13.1 概念：DPTF 如何写风扇

- DPTF 控扇时，OS 驱动调用 ACPI 方法 **\_FSL**（Fine-grained Set Level），ACPI 里把参数写入 EC 的 **FAND** 字段；EC 固件读 FAND 驱动 PWM。
- **FAND**：EC ACPI 中 8 位字段（Fan Duty），在 `ec.asl` 的 ERAM 里；0xFF 表示 EC 自动控扇。
- **\_FSL(Arg0)**：DPTF 风扇设备（如 TFN1）上的方法，实现为 `Store(Arg0, EC0.FAND)`。
- 无法直接“hook \_FSL”，监视 \_FSL 的效果 = **轮询读取 FAND**，看其是否随负载/温度变化。

### 13.2 如何监视 FAND

- 固件开启 **CONFIG_DRIVERS_INTEL_DPTF_ECTST_FAND_DEBUG=y** 时，会暴露调试设备 `\_SB.ECT0`：
  - `\_SB.ECT0._FST()`：读当前 FAND（与 TFN1._FST 一致）；
  - `\_SB.ECT0._FSL(x)`：写 FAND（与 DPTF 写路径一致）。
- **Windows**：安装 ec-test-app（OpenDevicePartnership ectest）后，在管理员 PowerShell 中轮询：
  ```powershell
  while ($true) {
      ectest -acpi \_SB.ECT0._FST
      Start-Sleep -Seconds 1
  }
  ```
- **Linux**：若 ectool 支持读 FAND 或 EC RAM 中对应偏移，可写脚本轮询；或通过 cros_ec 接口读 thermal/风扇相关节点（视内核暴露而定）。

### 13.3 “监视过 FAND，但 DPTF 似乎没有改变 FAND”的排查

| 检查项 | 说明 |
|--------|------|
| **1. 当前是否为 DPTF 控扇配置** | 若固件为 **EC 全权控扇**（`CONFIG_MINIPC_EC_FULL_FAN_CONTROL=y` 且 `CONFIG_DRIVERS_INTEL_DPTF_DISABLE_ACTIVE_FAN=y`），DPTF 风扇设备被隐藏（_STA=0），Windows **不会**调用 \_FSL，FAND 仅由 EC 在写 0xFF 后按自身 thermistor 变化。此时“DPTF 没改 FAND”是预期行为。若要验证 DPTF 控扇，需先改为 DPTF 控扇配置并重新刷写。 |
| **2. Windows 是否识别 DPTF 设备** | 设备管理器中查看是否有 **Intel Dynamic Platform and Thermal Framework** 或 ACPI 下的 **INT3400、INT3404** 等。若无 INT3404/DPTF 风扇设备，说明驱动未加载或 ACPI 未暴露，DPTF 不会写 FAND。 |
| **3. 是否安装 DPTF 驱动** | 从 Microsoft Update Catalog 搜索 “Intel DPTF” 或 “Dynamic Platform Thermal”，或从 OEM（如 Acer）下载该机型的 DPTF/热管理驱动并安装。未安装时 OS 不会根据 DPTF 表调用 \_FSL。 |
| **4. 电源/热管理策略** | Windows 电源选项中是否有“Intel DPTF”或“平台热管理”相关项；部分 OEM 软件会关闭 DPTF 控扇或固定为静音策略，导致不写 FAND。可切换电源方案（平衡/高性能）后再观察 FAND。 |
| **5. 负载下观察** | 在确认固件为 DPTF 控扇、且设备管理器中有 INT3404 的前提下，对 CPU 施加负载（如压力测试），每隔数秒读一次 `\_SB.ECT0._FST`。若 FAND 始终不变，可判断为 DPTF 驱动未调用 \_FSL 或策略未生效。 |

### 13.4 小结

- 监视 \_FSL = 轮询读 FAND（通过 ECT0._FST 或等效接口）。
- FAND 不变时：先确认是 **EC 控扇** 还是 **DPTF 控扇** 的固件；若为 DPTF 控扇则检查 Windows 是否安装并加载 DPTF 驱动、INT3404 是否存在、电源/热管理策略是否启用 DPTF 控扇。

### 13.5 如何检查 \_SB.ECT0._FST 是否暴露给系统

`\_SB.ECT0` 仅在固件开启 **CONFIG_DRIVERS_INTEL_DPTF_ECTST_FAND_DEBUG=y** 时存在；未开启则 ACPI 里没有该设备，无法读 _FST。

**方法一：直接尝试执行（最直接）**

- **Windows**：安装 [ec-test-app](https://github.com/OpenDevicePartnership/ec-test-app)（ectest），在**管理员** PowerShell 中执行：
  ```powershell
  ectest -acpi \_SB.ECT0._FST
  ```
  - 若返回数值（如 FAND 0–255）→ 已暴露。
  - 若报错 “object not found” / “method does not exist” / 无法解析路径 → 未暴露或固件未开上述 CONFIG。

- **Linux**：用 ACPI 调试接口（需 root）：
  ```bash
  # 若内核有 ACPI 调试，可尝试（部分内核未启用）
  echo '\_SB.ECT0._FST' > /sys/kernel/debug/acpi/custom_method
  cat /sys/kernel/debug/acpi/custom_method
  ```
  或使用 **acpi_call** 等模块/工具调用 ACPI 方法（若已安装）。

**方法二： dump DSDT/SSDT 看是否有 ECT0 与 _FST**

- **Windows**：
  1. 用 [SSDTTime](https://github.com/corpnewt/SSDTTime) 选 “Dump DSDT” 得到 DSDT.aml；或用 [ACPICA acpidump](https://acpica.org/downloads/binary-tools)：`acpidump -b -n DSDT` 得到 DSDT.dat（改名为 DSDT.aml）。
  2. 用 [iasl](https://acpica.org/downloads/binary-tools) 反编译：`iasl -d DSDT.aml`，得到 DSDT.dsl。
  3. 在 DSDT.dsl 中搜索 `ECT0`、`_FST`：若在 `Scope (\_SB)` 下存在 `Device (ECT0)` 且其内有 `Method (_FST, ...)`，则固件已暴露该对象（是否可用还取决于 _STA 等）。

- **Linux**：
  ```bash
  sudo cat /sys/firmware/acpi/tables/DSDT > DSDT.aml
  iasl -d DSDT.aml
  grep -n "ECT0\|_FST" DSDT.dsl
  ```

**方法三：设备/驱动侧（辅助）**

- **Windows**：设备管理器中查看 ACPI 设备列表，是否有与 “ECT” 或 “DPTF ECT” 相关的设备（名称因 OEM 而异，不一定叫 ECT0）。
- 若固件未开 `CONFIG_DRIVERS_INTEL_DPTF_ECTST_FAND_DEBUG`，DSDT 中不会出现 ECT0，方法一、二都会得到“未暴露”的结论。

### 13.6 实测：ECT0.\_FSL 写入未生效的情况

- 环境：当前这台 Chromebox 刷入的 coreboot 配置为 **EC 全权控扇**（推测存在 `CONFIG_MINIPC_EC_FULL_FAN_CONTROL=y` 之类），同时打开了 DPTF ECT 调试接口（`CONFIG_DRIVERS_INTEL_DPTF_ECTST_FAND_DEBUG=y`）。  
- 实测命令：

  ```powershell
  # 1）读当前 FAND
  ectest -acpi \_SB.ECT0._FST
  # Argument[1] = 0xff （EC 自动控扇）

  # 2）写入 0x80
  ectest -acpi \_SB.ECT0._FSL 0x80

  # 3）再读
  ectest -acpi \_SB.ECT0._FST
  # Argument[1] 仍为 0xff
  ```

- 同样逻辑用 `Test_ECT0_FST_FSL.ps1` 自动化验证时，效果一致：  
  - `[1] Current FAND from _FST:  FAND = 0xff`  
  - `[2] Writing FAND via _FSL(0x80) ...` 执行成功，ACPI 返回 Arg0=0x80；  
  - `[3] Read-back FAND after _FSL:  FAND = 0xff`，后续轮询 `_FST` 仍为 0xff。

**对 `_FST/_FSL` 返回值的具体解读：**

- **[1] `_FST` = 0xff**  
  - `_FST` 返回包里的 `Argument[1] = 0xff`，表示 EC 侧 **当前 FAND=0xFF**，即“自动控扇模式”。
- **[2] `_FSL(0x80)` 返回 0x80**  
  - 这里的 `Argument[0] = 0x80` 只是这次 `_FSL` 调用把参数“原样回显”，说明 ACPI 方法被成功执行，**并不等于 EC 里的 FAND 已经变成 0x80**。
- **[3] 再次 `_FST` 仍然 0xff**  
  - 再读 `_FST` 时 `Argument[1]` 还是 `0xff`，说明 **EC 看到的 FAND 一直没有从 0xFF 变成 0x80**，要么 `_FSL` 根本没写到 EC.FAND，要么写了但被 EC 逻辑立即覆盖回 0xFF。
- **[4] 持续监控 `_FST` 也一直是 0xff**  
  - 说明在一段时间内 FAND 从未被真正设为 0x80，EC 自始至终都工作在自动控扇模式。

**结论（就当前固件配置）：**

1. 虽然 ACPI 中存在 `\_SB.ECT0._FST / _FSL`，但 `_FSL` 调用并**没有真正改掉 EC 侧的 FAND 字段**；  
2. 更可能的实现是：coreboot 的 ACPI 里为调试方便加了 `_FST/_FSL` 方法，但在 EC 全权控扇配置下，`\_FSL` 要么只是“回显参数”（`Return(Arg0)`），要么即便临时写入 FAND，也被 EC 策略立即覆盖回 0xFF；  
3. 因为 FAND 始终为 0xFF，EC 始终工作在“自动控扇”模式，DPTF/ECT0 这条路径**实际处于旁路状态**。

---

*文档由分析过程整理，便于后续改 EC 或排查温控时查阅。*
### 13.6 实测：ECT0._FSL 写入 0x80 后 FAND 始终为 0xFF 的根因

- 环境：当前 Chromebox 上已启用 DPTF + ECT0（`CONFIG_DRIVERS_INTEL_DPTF_ECTST_FAND_DEBUG=y`），通过 `ECT0._FST/_FSL` 读写 FAND。  
- 实测命令（节选自 `logs.txt`）：
