UFS复位机制详解:硬件复位、软件复位与局部复位
复位,说白了就是让UFS设备回到一个已知的初始状态。但不同的复位方式,清扫的深度和范围完全不同。我个人习惯把复位分成三个等级:硬件复位是“一键清空”,软件复位是“重启服务”,局部复位则是“定点清除”。
搞清楚了这三种复位,很多启动链路问题就能迎刃而解。我们来逐个盘一盘。
硬件复位:最彻底的“一键还原”
硬件复位,也就是拉低nRESET引脚。这是UFS设备最底层的复位方式,直接作用于芯片的电源域和复位树。
触发方式很简单:Host控制器把nRESET信号拉到低电平,并保持至少tNRST时间(通常1us左右),再释放。
tRSTPWRON等待时间(我查过规范,一般25ms左右),用于内部模拟PLL锁定和数字逻辑复位。如果这个时间给短了,设备可能直接“死掉”。
内部状态影响:硬件复位会把所有寄存器都恢复到默认值。包括:
- UFS Protocol Layer (UPL):完全重置,所有任务终止,待处理命令全部丢失。
- Device Manager (DM):重置到初始态,之前的配置参数都没了。
- Unipro Layer:链路层状态机重置,PHY也回到初始。
- M-PHY:模拟部分复位,PLL失锁。
我在调试早期开发板时,遇到过好几次设备不响应的问题。最后发现是nRESET的时序没给够,释放后MCU就开始发命令,设备其实还没准备好。嗯,这里要注意。
软件复位:协议层的“软重启”
软件复位,是通过UFU命令来触发的。不需要动硬件引脚,完全在协议层面完成。
触发方式:Host发送QUERY REQUEST,设置fDeviceInit或fPowerOnWP等标志位,设备收到后执行内部复位流程。
我个人觉得,软件复位是调试中最常用的方法。因为它不依赖硬件引脚,而且复位后可以指定一些保留参数。
内部状态影响:
- UPL和DM:重置,但一些关键参数(比如
dExtendedUECapacity)可以保留。 - Unipro:触发链路重启,但不是从头开始,可以复用一些之前协商好的参数。
- M-PHY:不直接复位,但链路重启会造成PHY重新训练。
| 对比维度 | 硬件复位 | 软件复位 |
|---|---|---|
| 触发源 | 外部nRESET引脚 | UFU命令 |
| 作用范围 | 全芯片,包括模拟部分 | 数字逻辑,不直接复位PHY |
| 寄存器恢复 | 全部恢复到默认 | 部分保留 |
| 链路影响 | 完全断链,需要全流程重启 | 链路重启,但可保留部分配置 |
实践建议:一般在调试阶段,我会先用软件复位。如果软件复位后设备仍然异常,再考虑硬件复位。这样可以缩小排查范围。
局部复位:精细化的“定点清除”
局部复位,别称“Deferred Interrupt Reset”或“Partial Reset”。这个机制比较高级,它允许你只复位UFS设备内部的某个模块,而不影响其他模块的工作。
举个例子:我假设你正在做写操作,突然发现Read Data Buffer的CRC校验失败了。这时候,你不需要重启整个链路,只需要复位对应的Data Block部分即可。
内部状态影响:
- 受影响的模块:寄存器清零,状态机回初始态。
- 未受影响的模块:继续正常运行,不收丝毫影响。
- 链路状态:链路不中断!这是和前面两种复位最大的区别。
我记得有个项目,客户要求系统在遇到非致命错误时不能掉盘(不能重启链路)。我那时候正好用到了局部复位。把错误的数据缓冲区清掉,其他任务正常运转,完美解决问题。
三类复位对比总结
这三类复位,覆盖了从全盘清扫到定点修复的所有场景。我做了个总结表,可以直接参考:
| 复位类型 | 触发源 | 内部状态影响 | 链路影响 | 典型应用场景 |
|---|---|---|---|---|
| 硬件复位 | nRESET引脚 | 全部模块重置,寄存器归零 | 完全断链 | 首次上电、严重故障恢复 |
| 软件复位 | UFU命令 | UPL/DM重置,部分参数保留 | 链路重启 | 日常调试、非致命错误恢复 |
| 局部复位 | HCI寄存器 | 仅目标模块重置 | 链路维持 | 模块级错误修复、在线恢复 |
避坑指南:我曾经因为软件复位后没有等待设备初始化完成就发命令,导致链路训练失败。后来我加了一个轮询fDeviceInit完成状态的逻辑,问题才得以解决。记住:复位不是瞬间完成的,设备有自己的初始化流程。
小提示:你琢磨一下,硬件复位后从链路启动开始走,软件复位从Restart Link开始走,局部复位直接从某个中间步骤切入。搞清楚这三个起点,调试效率能提升一大截。