第4章 UFS设备探测初始化流程:主机侧与设备侧的启动顺序、复位与唤醒、VCC/VCCQ/VCCQ2上电时序要求
4.1 原理说明
UFS设备探测初始化流程是主机(Host)与设备(Device)建立通信链路的第一阶段,涉及电源管理、复位控制、时钟供给和UniPro/M-PHY子系统协同启动。主机侧与设备侧必须按照严格的时序交互,任何顺序偏差都会导致链路训练失败或设备不可见。
4.1.1 主机侧与设备侧的启动顺序
启动顺序遵循「主机先供能,设备后响应」的基本原则。主机侧首先完成自身控制器初始化,依次使能VCC/VCCQ/VCCQ2电源轨、提供REF_CLK参考时钟、释放RST_n硬件复位信号;设备侧在检测到电源和时钟稳定后,开始UniPro协议栈初始化,继而启动M-PHY链路训练,最后进入待探测状态。整个过程中主机处于驱动主导地位,设备处于响应跟随地位。
4.1.2 复位与唤醒机制
UFS设备支持两种复位方式:
- 硬件复位(Hardware Reset):通过拉低RST_n引脚至少1 µs,强制设备回到初始状态,所有寄存器和状态机清零。
- 软件复位(Software Reset):通过UniPro DME_RESET命令实现,用于链路层复位而不影响电源域。
唤醒机制用于设备从低功耗模式(如睡眠模式或深度睡眠模式)返回活动状态。主机通过恢复REF_CLK或发送PA_ACTIVATE请求触发设备重新进入HS-Gear模式。唤醒延迟通常需满足t_WAKEUP < 10 ms,否则链路会超时断开。
4.1.3 VCC/VCCQ/VCCQ2上电时序要求
UFS设备依赖三组独立电源轨,各自承担不同的供电角色:
| 电源轨 | 供电对象 | 电压范围 | 典型值 | 上电顺序 | 下电顺序 |
|---|---|---|---|---|---|
| VCC | NAND闪存阵列 | 2.7 V – 3.6 V | 3.3 V | ③ 最后上电或与VCCQ同时 | ① 最先下电 |
| VCCQ | 控制器数字核心 | 1.7 V – 1.95 V | 1.8 V | ① 最先上电 | ③ 最后下电 |
| VCCQ2 | M-PHY / UniPro I/O | 1.7 V – 1.95 V | 1.8 V | ② 紧随VCCQ或同时 | ② 与VCCQ同时或稍后 |
⚠ 时序红线:所有电源轨必须在RST_n释放前达到标称电压的90%以上,且稳定时间 ≥ 100 µs。VCC若先于VCCQ上电,可能导致设备闩锁损坏或初始化失败。
4.2 设备探测初始化流程总览
下图完整展示了从主机侧供电到设备探测完成的时序与状态流转,分为主机域、设备域和交互域三个阶段:
4.3 实现流程与关键配置
以下按步骤描述UFS设备探测初始化的完整操作序列,并给出主机侧的代码配置示例。
- 电源轨使能:依次使能VCCQ(1.8 V)、VCCQ2(1.8 V),最后使能VCC(3.3 V),每路间隔 ≥ 1 ms 等待稳压器输出稳定。
- 参考时钟供给:输出19.2 MHz或26 MHz REF_CLK,时钟抖动应 ≤ 100 ps RMS。
- 硬件复位释放:将RST_n从低电平拉高,拉低时间不少于1 µs,释放后等待设备完成内部上电复位(一般需 5-10 ms)。
- UniPro初始化:设备自动执行DME_RESET序列,主机可通过UICR命令查询DME_LINK_STATE确认链路状态。
- M-PHY链路训练:设备发起PA_ACTIVATE请求,协商Gear和速率,主机侧需配置PA_TX_GEAR和PA_RX_GEAR匹配。
- 设备探测命令:主机发送NOP_OUT检查设备是否就绪,随后发送READ_DESCRIPTOR读取Device Descriptor,获取厂商信息和容量。
💡 实用建议:在量产板上建议在RST_n释放后加入10 ms固定延时再发起任何UICR命令,避免设备内部POR未完成导致命令超时。
4.3.1 主机侧上电与复位配置示例
以下代码演示了在嵌入式系统中通过GPIO和Regulator框架控制UFS电源与复位:
/* UFS设备上电与复位初始化序列 */
void ufs_power_on_sequence(struct ufs_hba *hba) {
int ret;
/* 1. VCCQ 先上电 (1.8V) */
ret = regulator_set_voltage(hba->vccq_reg, 1800000, 1800000);
ret |= regulator_enable(hba->vccq_reg);
mdelay(2);
/* 2. VCCQ2 上电 (1.8V) */
ret = regulator_set_voltage(hba->vccq2_reg, 1800000, 1800000);
ret |= regulator_enable(hba->vccq2_reg);
mdelay(2);
/* 3. VCC 最后上电 (3.3V) */
ret = regulator_set_voltage(hba->vcc_reg, 3300000, 3300000);
ret |= regulator_enable(hba->vcc_reg);
mdelay(5);
/* 4. 提供REF_CLK (19.2 MHz) */
clk_set_rate(hba->ref_clk, 19200000);
clk_enable(hba->ref_clk);
mdelay(1);
/* 5. 释放RST_n (低电平保持2 µs后拉高) */
gpiod_set_value(hba->rst_gpio, 0);
udelay(2);
gpiod_set_value(hba->rst_gpio, 1);
/* 6. 等待设备内部初始化完成 */
msleep(10);
}
4.3.2 设备探测命令序列示例
主机通过UFS HCI发送NOP_OUT和READ_DESCRIPTOR命令,检查设备是否可达并读取描述符:
/* 设备探测:发送NOP_OUT检查设备就绪 */
int ufs_device_probe(struct ufs_hba *hba) {
u32 resp;
/* 发送NOP_OUT UTP命令 */
ufshcd_send_command(hba, UTP_NOP_OUT, &resp);
if (resp != UTP_NOP_OUT_RESP) {
dev_err(hba->dev, "NOP_OUT 失败, 设备未响应\n");
return -ENODEV;
}
dev_info(hba->dev, "NOP_OUT 成功, 设备已就绪\n");
/* 读取Device Descriptor (长度0x40字节) */
u8 desc_buf[0x40];
int ret = ufshcd_read_descriptor(hba, DEVICE_DESC_ID, 0, desc_buf, 0x40);
if (ret) {
dev_err(hba->dev, "读取Device Descriptor失败\n");
return ret;
}
/* 解析厂商ID和产品名称 */
u16 vendor_id = desc_buf[8] | (desc_buf[9] << 8);
char prod_name[17];
memcpy(prod_name, &desc_buf[16], 16);
prod_name[16] = '\0';
dev_info(hba->dev, "探测到UFS设备: VID=0x%04x, 产品=%s\n", vendor_id, prod_name);
return 0;
}
4.4 调试日志分析
以下摘录自实际嵌入式平台UFS驱动启动时的内核日志,分为正常序列与异常序列:
4.4.1 正常初始化日志
[ 1.234