第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设备依赖三组独立电源轨,各自承担不同的供电角色:

电源轨供电对象电压范围典型值上电顺序下电顺序
VCCNAND闪存阵列2.7 V – 3.6 V3.3 V③ 最后上电或与VCCQ同时① 最先下电
VCCQ控制器数字核心1.7 V – 1.95 V1.8 V① 最先上电③ 最后下电
VCCQ2M-PHY / UniPro I/O1.7 V – 1.95 V1.8 V② 紧随VCCQ或同时② 与VCCQ同时或稍后
⚠ 时序红线:所有电源轨必须在RST_n释放前达到标称电压的90%以上,且稳定时间 ≥ 100 µs。VCC若先于VCCQ上电,可能导致设备闩锁损坏或初始化失败。

4.2 设备探测初始化流程总览

下图完整展示了从主机侧供电到设备探测完成的时序与状态流转,分为主机域、设备域和交互域三个阶段:

UFS设备探测初始化流程 Host Side(主机侧) Device Side(设备侧) ① 主机 VCC/VCCQ/VCCQ2上电 ② 主机 提供REF_CLK + 释放RST_n ③ 设备 UniPro初始化(DME_RESET) ④ 设备 M-PHY链路训练(PA_ACTIVATE) ⑤ 主机+设备 设备探测与识别 ⑥ 初始化完成 ⏱ 关键时序:VCCQ/VCCQ2先于VCC上电 → RST_n在电源稳定后释放 → REF_CLK必须在RST_n释放前稳定

4.3 实现流程与关键配置

以下按步骤描述UFS设备探测初始化的完整操作序列,并给出主机侧的代码配置示例。

  1. 电源轨使能:依次使能VCCQ(1.8 V)、VCCQ2(1.8 V),最后使能VCC(3.3 V),每路间隔 ≥ 1 ms 等待稳压器输出稳定。
  2. 参考时钟供给:输出19.2 MHz或26 MHz REF_CLK,时钟抖动应 ≤ 100 ps RMS。
  3. 硬件复位释放:将RST_n从低电平拉高,拉低时间不少于1 µs,释放后等待设备完成内部上电复位(一般需 5-10 ms)。
  4. UniPro初始化:设备自动执行DME_RESET序列,主机可通过UICR命令查询DME_LINK_STATE确认链路状态。
  5. M-PHY链路训练:设备发起PA_ACTIVATE请求,协商Gear和速率,主机侧需配置PA_TX_GEAR和PA_RX_GEAR匹配。
  6. 设备探测命令:主机发送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