eMCP 软件设计规范
编制日期 2026-09-25 | 版本号 V1.0
面向 eMMC 5.0/5.1 + LPDDR3/4/4X 合封(221 / 254 / 297-ball FBGA)的固件与底层软件设计约定 —— 覆盖 双器件独立初始化、不可颠倒的冷启动链路、LPDDR 训练流水线、五路电源与复位协同、 继电保护、热耦合温控 与 休眠 / 唤醒,逐条给出可落地的序列、判据、超时预算与失败处置。
| 文档编号 | eMCP-SW-SPEC-001 |
|---|---|
| 版本 / 状态 | V1.0 · 正式发布 |
| 适用器件 | JEDEC 标准 eMCP:eMMC 5.0 / 5.1(HS200 / HS400)+ LPDDR3 / LPDDR4 / LPDDR4X;封装 221-ball / 254-ball / 297-ball FBGA,0.5 mm pitch |
| 参考标准 | JESD84-B50/B51(eMMC 5.0/5.1)· JESD209-4C(LPDDR4/4X)· JEDEC No.21 · SoC Vendor Bring-up Guide · PMIC Datasheet |
| 容量范围 | eMMC 8 GB ~ 256 GB;LPDDR 4 Gb ~ 64 Gb(4 Gb ~ 8 GB) |
| 配套文档 | eMCP_电路设计指南.html(电源 / 上电时序 / Layout / 热设计 / 焊接) |
0. 目的与范围
本规范约束 eMCP 器件(eMMC + LPDDR 合封)在固件与底层驱动中的软件行为: 启动链路分工、两侧初始化序列、训练流程与判据、电源与复位协同、读写规范、掉电保护、休眠唤醒、热管理与寿命监控。 凡本文与器件 datasheet 或 SoC BootROM 手册冲突,以器件 datasheet 与 SoC 手册为准。
- 统一启动链路:固化「BootROM → eMMC 取 SPL → SPL 初始化 LPDDR → 加载 bootloader / OS」这条不可颠倒的顺序,并给出每一跳的检查点与超时。
- 统一两侧初始化:eMMC 侧走标准 CMD 序列 + EXT_CSD 配置;LPDDR 侧走电源 → 时钟 → 解复位 → MRW → ZQ → 训练的流水线。
- 统一电源与复位语义:明确五路电源的归属、软件可观测性与可控制点,禁止用一根复位线同时复位两侧。
- 统一掉电与休眠协议:给出写窗口、提交协议、flush 顺序与自刷新进出序列。
- 统一热与健康管理:给出温度采样点、分级温控动作、寿命字段阈值与巡检周期。
一句话结论:eMCP 的软件难点不在「怎么读写」,而在「两颗异质器件怎么协同」 ——
封装内一侧是要 CMD CMD1 轮询、忙态可达百毫秒以上的存储,另一侧是要 tINIT 等待、
ZQ 校准、多级训练之后才敢跑的内存。
没取到 SPL 就先初始化 DRAM,会卡在只有 SRAM 可跑的状态里;DRAM 没训练通过就切高主频,会在高低温随机崩;
eMMC 没 flush 就进自刷新会让未落盘的数据永远丢失。
文档使用说明
- 本文是《eMCP 电路设计指南》的软件配套篇:硬件篇解决「五路电源怎么上、0.5 mm 球怎么扇、热量怎么散」,本文解决「驱动怎么写、序列怎么排、训练怎么验、异常怎么救」。
- 命令码、EXT_CSD 偏移、时序值取自 JESD84-B51(eMMC 5.1) 与 JESD209-4C(LPDDR4/4X);不同厂商 / 不同世代器件(尤其是 LPDDR3 与 LPDDR4X)差异很大,移植前必须逐条核对 datasheet。
- 文中 C 代码为协议骨架伪代码,用于表达流程、判据与超时预算,而非某平台上可直接编译的完整实现;
mmc_send_cmd()、dwc_ddrphy_*、pmic_set_voltage()、now_ms()等均为平台相关底层。 - 凡标注 硬性 的条款为不可协商项;标注 建议 的条款可按项目剪裁,但剪裁结果必须写入项目《Bring-up 记录》。
① 先存储、后内存:BootROM 只能用片内 SRAM,必须先把 SPL 从 eMMC 取出来,才有代码去初始化 DRAM; ② 训练不过一律降速重试,绝不「跳过训练直接跑」:常温能跑不代表四角能跑; ③ busy / training 未就绪一律等待或超时报错,绝不用固定 sleep 代替状态轮询:触发内部 GC 或高磨损时的单次写耗时随使用情况增长; ④ 任何进入低功耗的动作之前,先 flush,再进自刷新:顺序反了会丢数据。
1 · 器件定位与双总线架构
eMCP 把「一颗完整 eMMC(NAND 阵列 + 控制器 + 片内 FTL)」和「一颗低功耗 DRAM」封进同一个 BGA。 它对外暴露的是两套互不相干的总线、五路电源和两组复位。软件的第一要务,是把这两套东西当作 两个独立器件各写一套驱动,再在上面加一层协调层,而不是试图找一个「统一设备模型」。
1.1 器件定位与关键参数
| 项目 | eMMC 侧 | LPDDR 侧 |
|---|---|---|
| 协议基础 | JESD84-B51(eMMC 5.1),向后兼容 5.0 / 4.5 | JESD209-4C(LPDDR4 / 4X),部分器件为 JESD209-3(LPDDR3) |
| 对外总线 | CMD + CLK + DAT[7:0](11 根信号) | CK_t/c、CS_n、CA[5:0]、DQ[x]、DQS_t/c、DMI、RESET_n、CKE(约 40~60 根) |
| 数据宽度 | 1 / 4 / 8 bit | ×16 或 ×32(每通道) |
| 最高速率 | HS400:DDR 200 MHz,理论 400 MB/s | LPDDR4X-4266:4266 Mbps/pin |
| 访问粒度 | 512 B 扇区(逻辑区块地址) | 字节地址,突发长度 16 / 32 |
| 寻址方式 | 主机给 LBA,器件内 FTL 转换为物理页 | 主机(控制器)给 bank / row / col,线性地址由 SoC 转换 |
| 易失性 | 非易失,掉电保留(写入窗口内的除外) | 易失,掉电全丢 |
| 坏管理 / ECC | 器件内 FTL 全权负责,主机不可见 | 部分 SoC 支持 DRAM ECC(若使能则主机可见) |
| 典型时延 | 读 ~0.1 ms 量级;写 busy 可达数十 ~ 数百 ms | 几十 ns 量级(对软件近似于「立即」) |
| 容量范围 | 8 GB ~ 256 GB | 4 Gb ~ 64 Gb(512 MB ~ 8 GB) |
| 电源轨 | VCC(NAND 核心)、VCCQ(I/O) | VDD1、VDD2、VDDQ |
1.2 合封内部结构与对外接口
封装内的两颗 die 没有任何内部互联总线:eMMC 不知道 DRAM 的存在,DRAM 也不知道旁边有颗 NAND。 它们只共享三样东西 —— 封装基板、接地(VSS)与工作环境温度。由此直接推出三条软件结论:
1.3 两套总线的地址空间差异
同一份 SoC 地址映射表里,这两块资源的语义完全不同。软件最容易犯的错误,是把内存的用法搬到存储上、或反过来。
| 维度 | eMMC(块设备) | LPDDR(内存) |
|---|---|---|
| CPU 可见性 | 不可直接按地址访问,只能通过 DMA / 寄存器搬运 | 可直接 load / store(有 Cache 参与) |
| 写的最小单位 | 512 B 扇区;内部实际按页 / 块操作 | 1 B(但推荐按 cacheline 对齐) |
| 写是否立即生效 | 返回 ≠ 落盘(可能还在 cache / cache buffer) | 返回 = 已进 DRAM |
| 是否需要擦除 | 不需要显式擦(Trim / Discard 即可) | 不适用 |
| 越界访问后果 | 返回 errors,器件不受损 | 可能覆写其它数据或触发总线错误 |
| 顺序性保证 | 只有发出 barrier / flush 后才保证 | 同一个核上有程序序,弱内存序架构需显式 barrier |
往 DRAM 写完(甚至只是进了 Cache)就可以认为数据在当前供电周期内是可见的; 往 eMMC 写完(哪怕是命令成功返回)也不能认为数据已经持久。只有 flush 成功返回、且器件确认 cache 已清空之后,才可以宣告一次提交完成。
1.4 相对分立方案的关键差异(移植必读)
从「分立式 eMMC + 分立式 DRAM」移植过来的项目,下面几项是必然会变的,其余基本可以按原驱动直接复用。
| 维度 | 分立方案 | eMCP 合封 | 软件要改什么 |
|---|---|---|---|
| 上电顺序 | 由各自的 PMIC 轨独立控制,容错宽 | 受 boot 链路约束,VCC / VCCQ 必须先于或同时于 DRAM 侧就绪 | PMIC 初始化脚本必须重写并实测 |
| 复位线 | 各自独立,通常也只对一侧供电复位 | 球位密集,易被 Layout 「合并」 | 确认原理图上 RST_n 与 RESET_n 不是同一网络 |
| 热环境 | 两颗芯片分置,热量各自散掉 | 11.5 × 13 mm 封装内互相加热 | 新增温控策略与刷新率动态调节 |
| 替换与调试 | 可单独换器件、单独飞线测量 | 不可单独替换,问题器件只能连整颗一起换 | 必须依赖日志与寄存器读数做远程诊断 |
| 软件初始化 | 顺序相对自由 | 强依赖:先从 eMMC 取 SPL,才有代码初始化 DRAM | SPL 的生成、打包、烧录位置必须按 BootROM 要求 |
| 驱动本体 | 标准 eMMC 驱动 + 标准 DDR 驱动 | 同样那两套驱动,不需改写 | 几乎不用改,改的是上层编排 |
eMCP 移植基本不需要动两个外围驱动的本体,改的是三件事:① 电源编排脚本;② 启动阶段的顺序与分工;③ 温控与调度策略。 把这三件事做成独立模块,同一个 SDK 就能同时支持分立与合封两种形态。
2 · 术语与缩写
2.1 接口与协议术语
| 缩写 | 全称 / 含义 | 在本规范中的所指 |
|---|---|---|
| eMCP | embedded Multi-Chip Package | eMMC + LPDDR 合封器件,本文对象 |
| FTL | Flash Translation Layer | 位于 eMCP 内部 eMMC die 上,负责坏块、磨损均衡、映射;主机不可见 |
| EXT_CSD | Extended CSD | eMMC 的 512 B 扩展配置寄存器,通过 CMD8 读取、CMD6 写入 |
| RCA | Relative Card Address | eMMC 的 16 bit 相对地址,由 CMD3 分配 |
| HS200 / HS400 | High Speed 200 / 400 | eMMC 高速模式;HS400 需 prior HS200 tuning 并启用 DS |
| DS | Data Strobe | HS400 下由器件返回的选通信号,替代主机采样时钟 |
| RPMB | Replay Protected Memory Block | 带 MAC 校验的安全分区,密钥一次性烧写 |
| BKOPS | Background Operation | 器件内部后台操作,需主机留出空闲窗口 |
| PON | Power Off Notification | 主机提前告知器件即将下电,让器件有时间收尾 |
| MRW / MRR | Mode Register Write / Read | LPDDR 的模式寄存器写入 / 读取命令 |
| ZQ | ZQ Calibration | 以 240 Ω ±1% 外置电阻为基准的输出阻抗校准 |
| CA Training | Command/Address Bus Training | 校准 VREF(CA) 并把 CA/CS 与 CK 对齐 |
| Write Leveling | — | 补偿 CK 到 DQS 的飞行时间差异 |
| DQS Gate | — | 在读前导期间确定 DQS 的有效采样窗 |
| tINIT1/2/4/5 | 初始化定时参数 | LPDDR 上电后解复位、时钟稳定、发 MRS 之前必须等待的时间 |
| SR / Self Refresh | Self Refresh | DRAM 自刷新状态,休眠期间数据保持的最低必要条件 |
| PVT | Process / Voltage / Temperature | 训练结果有效性的三个影响因素 |
| DVFS | Dynamic Voltage and Frequency Scaling | DRAM 频率切换,常需重建 params 或重训 |
| barrier / flush | — | barrier 保证命令顺序;flush 保证数据离开器件 cache 落到介质 |
2.2 本文书写约定
- 数值中的
k / M / G按器件惯例:eMMC 容量用十进制(GB),DRAM 容量用二进制位宽(Gb / GB)。 - 命令一律写成
CMDn形式,扩展区的写入统一写作CMD6(ACCESS=WRITE_BYTE, index=..., value=...)。 - 时间参数统一按
tXXX引用 JEDEC 原文;本规范只给出「谁更大」「谁必须先满足」的关系,具体数值以 datasheet 为准。 - “存储侧”“eMMC 侧”指 eMMC die;“内存侧”“DRAM 侧”指 LPDDR die;两者合称「两侧」。
3 · 软件分层与冷启动链路
eMCP 的启动有一个物理上不可颠倒的顺序,它直接决定了电源时序与软件框架的分层: BootROM 只能用片内 SRAM,必须先把 SPL 从 eMMC 读出来,才有代码去初始化 DRAM。
3.1 分层职责
| 层级 | 运行位置 | 必须完成的事 | 禁止做的事 |
|---|---|---|---|
| BootROM | SoC 片内固件 SRAM | 配置最简引脚、跑 400 kHz 以下的 MMC 总线、从 Boot 分区读 SPL 到片内 SRAM、校验后跳转 | 不要尝试初始化 DRAM(代码放不下,且没必要) |
| SPL | 片内 SRAM | 再补齐 PMIC 各轨、打开必要的电源、完成 LPDDR 全部初始化与训练、把下一级镜像载入 DRAM | 不要做复杂业务;SRAM 有限,日志要极简(UART 轮询模式即可) |
| bootloader | DRAM | 切换到高速(HS200/HS400)、读分区表、做镜像 A/B 选择、加载内核、把约定格式的参数传给内核 | 不要在此时做全量文件系统 fsck(会很慢) |
| Kernel | DRAM | 挂载文件系统、跑掉电恢复、启动健康巡检与温控守护、管理休闲 / 休眠 | 不要在不知道之前发生过什么的情况下直接写业务数据 |
有人会问:能不能把 DRAM 初始化放到 bootloader 里?答案是不能 —— bootloader 本身就在 DRAM 里跑,构成循环依赖。 唯一能打破循环的,就是「必须在 SRAM 里跑完 DRAM 初始化」的 SPL。SPL 越小、越不做多余的事,Bring-up 越好调。
3.2 冷启动全链路
- 电源编排:SPL / PMU 固件按 §6.2 的顺序开放五路电源,实测每路达到目标值且保持稳定后才继续。
- BootROM 取 SPL:SoC 固件驱动 MMC 总线(≤ 400 kHz),从 Boot 分区读取 SPL 到片内 SRAM,验证签名/CRC 后跳转。
- SPL 补齐时钟与引脚:配置 DRAM PHY 相关 IO、PLL,使能 DRAM 侧时钟。
- DRAM 初始化与训练:按 §5 的流水线走完 ZQ、CA、Write Leveling、DQS Gate、读写训练,做一次全内存回校。
- 切换到 DRAM 栈运行:设置堆栈与重定位,跳到 bootloader。
- eMMC 提速:bootloader 阶段读 EXT_CSD、切 8 bit、切 HS200 并 tuning,必要时再进 HS400。
- 分区与分区选择:读取分区表 / A/B 槽位元数据,选择有效槽位。
- 加载内核并移交:把设备树 / 内存布局 / 训练参数摘要通过约定方式交给内核。
SPL 里哪怕只有一个轮询模式的 UART 打印,Bring-up 的调试成本也能下降一个数量级。建议在 SPL 最开头就初始化串口,并把「已进入 XXX 阶段、等待 XXX bit/令牌」逐句打出来。 DRAM 训练失败而没有日志,是最难排查的一类问题。
3.3 Bring-up 阶段判据与降级
| 阶段 | 通过判据 | 失败后的降级 / 处置 | 是否允许继续 |
|---|---|---|---|
| S0 · 电源 | 五路电压实测在窗口内、斜升单调、纹波达标 | 停止,检查 PMIC 配置与原理图的上电编排 | 否 |
| S1 · eMMC 低速枚举 | CMD1 就绪、CID/CSD 读到、能读 Boot 分区 | 重试 N 次后进下载模式 | 否 |
| S2 · eMMC 提速 | HS200 tuning 通过且回读一致 | 停在 HS / Default Speed,性能降级但可用 | 降级继续 |
| S3 · DRAM 训练 | 全阶段训练通过 + 全内存回校通过 | 降速重试 ≥ 3 次,仍失败则停并告警 | 否 |
| S4 · OS 启动 | 挂上文件系统、自检通过、守护进程起来 | 进入恢复系统 / 换 A/B 槽重试 | 回滚重试 |
DRAM 训练失败却选择「继续跑」,表现出来会是位置完全随机的崩溃(某一处、某一次、某块数据),极难与 DRAM 关联起来。 宁可停在下载模式点灯,也不要带病运行。
4 · eMMC 侧初始化
eMMC 侧的行为完全由 JEDEC 定义,主机能做的裁量不多:照标准序列走、把 EXT_CSD 读全、把该配的配上。 真正的差异体现在失败时的降级策略和稳态之外的掉电处理。
4.1 标准命令序列
- CMD0(GO_IDLE_STATE):复位到 Idle。硬件复位使能时也可走
RST_n信号。 - CMD1(SEND_OP_COND):带工作电压条件轮询,直到 busy bit 置位表示 ready。轮询间隔 10 ms 级,总额度建议 ≥ 1 s。
- CMD2(ALL_SEND_CID):读 128 bit CID(厂商、产品名、版本、序列号)。
- CMD3(SET_RELATIVE_ADDR):分配 RCA,进入 Standby。
- CMD9(SEND_CSD):读 CSD,得到容量、擦除组大小等关键参数。
- CMD7(SELECT_CARD):选中器件进入 Transfer 状态 —— 之后才允许数据命令。
- CMD8(SEND_EXT_CSD):读 512 B EXT_CSD,这是后续所有配置的依据。
- CMD6 配置:总线宽度(
BUS_WIDTH[183])、高速时序(HS_TIMING[185])、分区(PARTITION_CONFIG[179])等。 - 提速 + tuning:HS200 / HS400 模式下执行 tuning 流程,并回读校验。
/* eMMC 初始化骨架(协议示意,非平台实现) */
int emmc_init(host_t *h)
{
mmc_send_cmd(h, CMD0, 0, 0); /* 进 Idle */
uint32_t ocr = OCR_VDD_27_36 | OCR_ACCESS_MODE_HS; /* 按板卡供电别写死 */
for (int i = 0; i < 100; i++) {
uint32_t r3 = mmc_send_cmd(h, CMD1, ocr, /* busy check */ 1);
if (r3 & OCR_BUSY) break; /* ready */
mdelay(10);
if (i == 99) return -ETIMEDOUT; /* 超时必须上报 */
}
cid = mmc_send_cmd(h, CMD2, 0, 0);
rca = mmc_send_cmd(h, CMD3, 1, 0) >> 16;
csd = mmc_send_cmd(h, CMD9, rca << 16, 0);
mmc_send_cmd(h, CMD7, rca << 16, 0); /* 选中 */
ext_csd = mmc_read_ext_csd(h); /* CMD8 + 数据块 */
return emmc_apply_config(h, ext_csd); /* CMD6 系列 */
}
常见缺陷是把 CMD1 的 OCR 电压窗口硬编码成别的项目的取值,而不是跟随板卡的实际供电: VCCQ 走 1.8 V 的板子和走 3.3 V 的板子,OCR 必须不同。OCR 不匹配的表现是 CMD1 永远等不到 ready,且没有任何其它报错,排查时会完全无从下手。
4.2 EXT_CSD 必读字段
| 字段 | 偏移 | 初始化阶段为何必须读 |
|---|---|---|
| EXT_CSD_REV | 192 | 判断器件版本,决定后续哪些字段有效 |
| CARD_TYPE | 196 | 判断支持 HS200 / HS400 及所需驱动强度 |
| SEC_COUNT | 212:215 | 实际可用扇区总数,不能只依赖 CSD 推算 |
| BUS_WIDTH | 183 | 当前总线宽度,配置前后都要确认 |
| HS_TIMING | 185 | 当前速率模式,切档后再读回验证 |
| PARTITION_CONFIG | 179 | Boot 分区使能、BOOT_ACK、当前访问分区 |
| BOOT_SIZE_MULTI | 226 | Boot 分区实际大小,决定 SPL 能写多大 |
| RPMB_SIZE_MULT | 168 | RPMB 大小,安全方案必须知道 |
| CACHE_SIZE | 249:252 | 非空说明 Cache 存在且可能已使能,决定 flush 策略 |
| BKOPS_EN / BKOPS_START | 163 / 164 | 后台操作的自动 / 手动开关 |
| DEVICE_LIFE_TIME_EST_TYP / A / B | 268 / 269 / 270 | 寿命估计,健康监控数据来源 |
| PRE_EOL_INFO | 267 | 寿命预警,达到 Warning / Urgent 必须上报 |
4.3 总线宽度与速率模式
| 模式 | 总线宽度 | 时钟 | 理论带宽 | 要求 |
|---|---|---|---|---|
| Backward Compatible | 1/4/8 | ≤ 26 MHz | ≤ 26 MB/s | 无特殊要求 |
| High Speed | 1/4/8 | ≤ 52 MHz | ≤ 52 MB/s | VCCQ 稳定 |
| HS200 | 4/8(SDR) | ≤ 200 MHz | ≤ 200 MB/s | 必须 tuning,VCCQ 1.8 V |
| HS400 | 8(DDR) | ≤ 200 MHz | ≤ 400 MB/s | 先切 HS200 并 tuning,再启用 DS 进 HS400 |
必须 缺省 → HS → HS200(tuning)→ HS400(启用 DS)。直接写 HS400 到 HS_TIMING 会失败,部分器件的表现为莫名其妙的数据错误而非报错。
若平台对稳定性要求高于峰值带宽,停在 HS200 是完全可以接受的工程选择:200 MB/s 与 400 MB/s 在多数嵌入式场景里不构成瓶颈,而 HS400 对等长与参考平面的要求严苛得多。
4.4 分区、Boot 与 RPMB
| 区域 | 用途 | 软件约束 |
|---|---|---|
| Boot1 / Boot2 | 存放 SPL / 一级引导 | 通过 PARTITION_CONFIG[179] 的 BOOT_PARTITION_ENABLE 位选择;支持双份冗余时建议 A/B 轮换 |
| RPMB | 安全数据、防回滚计数 | Auth Key 一次性烧写,写错不可挽回;Write Counter 必须与掉电保护一起设计 |
| GPP(通用分区) | 可选,RTOS / Recovery / 日志等 | 分区一旦建好,改动需要擦除,产线流程要确认 |
| User Area | 文件系统主区域 | 容量使用率约束见 §13.2 |
上电初期器件自动指向 Boot 分区供 BootROM 读取;BootROM 结束后,软件需要显式切换分区(写 PARTITION_CONFIG 的 PARTITION_ACCESS 位)才能访问 User Area。
忘记切换的表现是「能启动、但挂载文件系统失败」。
4.5 初始化失败与降级路径
| 失败点 | 现象 | 处置 |
|---|---|---|
| CMD1 等不到 ready | 初始化卡在第一句 | 核对 OCR 电压窗口;确认 VCC/VCCQ;继续应 insure SRAM→SPL 已成功,否则板子本身不通 |
| CMD2 / CMD3 超时 | CID 读不到 | CMD 线上拉缺失或时钟极慢;示波器看波形 |
| EXT_CSD 读回全 0 / 全 FF | 配置无从下手 | 多为供电不足或时序裕量不够,降速重试 |
| 切 8 bit 后读写错误 | 低速行、高速不行 | 退回 4 bit 或 1 bit,检查 DAT1~DAT3 等长 |
| HS200 tuning 失败 | 提速即错 | 停在 HS / Default Speed 降级使用,同时记录门限用于后续分析 |