第一章 RK平台存储接口全景概览

做RK平台存储驱动开发,第一件事不是翻芯片手册,而是搞清楚整个存储子系统长什么样。我见过不少工程师上来就啃eMMC协议,结果连DDR配置都没摸对,折腾两周发现是时钟树配错了。所以这一章,我们先搭个全局框架。

1.1 RK存储子系统架构

RK的存储子系统,说白了就是一条数据通路:CPU发指令,经过总线,到达存储控制器,再跟物理介质打交道。中间每一层都可能成为瓶颈。

核心分层(从上到下):

  • VFS层 — 虚拟文件系统,屏蔽底层差异
  • 块设备层 — 处理IO调度、合并、排队
  • MTD/NAND层 — 专为NAND Flash设计的中间件
  • 主机控制器驱动 — 直接操作寄存器,发命令
  • 物理接口 — eMMC/SD/NAND/SPI Nor的电气协议

我个人习惯把控制器驱动看作"翻译官"——它把上层标准命令翻译成物理接口能懂的时序。RK的存储控制器集成在SoC内部,不同系列(RK33xx、RK35xx)的寄存器布局差异不小,但设计思想一脉相承。

RK平台存储子系统架构图 用户空间 (应用程序/文件系统) VFS 虚拟文件系统层 块设备层 (IO调度/合并) MTD / NAND 中间件层 主机控制器驱动 (DW_mmc / NANDC / SPI) 物理接口层 eMMC 5.1 | SD 3.0 | NAND Flash | SPI Nor Flash 说明:RK35xx系列在块设备层和控制器驱动之间增加了DMA引擎,数据搬运效率更高

1.2 主流存储接口对比

RK平台常见的存储介质有四种:eMMC、SD卡、NAND Flash、SPI Nor Flash。它们各有各的脾气。我整理了一张对比表,方便你快速选型。

特性 eMMC SD卡 NAND Flash SPI Nor Flash
接口协议 MMC 5.1 / HS400 SD 3.0 / UHS-I ONFI / Toggle SPI / QSPI / OSPI
最大速率 400 MB/s (HS400) 104 MB/s (SDR104) ~400 MT/s (DDR) ~200 MB/s (OSPI DDR)
坏块管理 内置 内置 驱动层处理 无(需应用层处理)
寿命管理 内置磨损均衡 内置 驱动层实现 无
典型容量 4GB ~ 256GB 2GB ~ 1TB 128MB ~ 8GB 1MB ~ 256MB
启动支持 支持(Boot分区) 不支持 支持(需Boot ROM配合) 支持(XIP执行)
驱动复杂度 中等 中等 高 低

选型建议:

  • 量产产品首选eMMC,省心,坏块和磨损均衡都帮你管好了
  • 低成本方案用NAND,但驱动工作量翻倍,我踩过不少坑
  • SPI Nor只适合存固件或配置文件,别拿它当主存储
  • SD卡适合调试阶段或消费类产品,工业场景慎用(接触可靠性问题)

1.3 RK芯片存储控制器特性

RK的存储控制器不是自己从头造的,而是集成了DesignWare IP。嗯,这里要注意:不同系列用的IP版本不一样,寄存器偏移和功能位有差异。

1.3.1 eMMC/SD控制器 (DW_mmc)

RK33xx和RK35xx都用的Synopsys DesignWare移动存储主机控制器。我最早在RK3288上调试eMMC时,被它的FIFO阈值配置坑过一次——默认值在HS400模式下会溢出。

  • 时钟范围: 100kHz ~ 200MHz(取决于分频配置)
  • 数据宽度: 1/4/8位,支持DDR模式
  • DMA支持: IDMAC(内部DMA)或GDMA(通用DMA)
  • 命令队列: 支持CMD Queue(eMMC 5.1)
  • 电压: 1.8V / 3.3V 双电压

避坑指南: 我曾经在RK3399上遇到eMMC初始化失败,查了三天发现是时钟相位没调好。DW_mmc的时钟延迟链(Delay Chain)需要根据PCB走线长度做校准,别偷懒用默认值。

1.3.2 NAND控制器 (NANDC)

RK的NAND控制器相对"原始",不像eMMC那么智能。它只负责发命令、传数据,坏块管理和ECC都得驱动层自己干。

  • 支持类型: SLC/MLC/TLC,ONFI 2.0/3.0
  • ECC: 硬件BCH引擎(最多72bit/1KB)
  • 页大小: 2KB/4KB/8KB/16KB
  • 随机读: 约25μs(典型值)
  • 编程时间: 约500μs ~ 2ms(取决于工艺)

说实话,NAND驱动是RK平台里最考验功力的部分。我见过不少团队直接拿公版驱动改,结果量产三个月后坏块率飙升——因为没做动态坏块映射。

1.3.3 SPI控制器

SPI Nor的控制器相对简单,但RK在RK35xx系列里加入了QSPI和OSPI支持,速率提升明显。

模式 数据线 最大时钟 理论带宽
SPI 1条 50MHz 6.25 MB/s
Dual SPI 2条 50MHz 12.5 MB/s
Quad SPI (QSPI) 4条 50MHz 25 MB/s
Octal SPI (OSPI) 8条 100MHz (DDR) 200 MB/s

关键寄存器概览(以DW_mmc为例):

// 控制器版本寄存器
#define DW_MMC_CTRL          0x000   // 控制寄存器
#define DW_MMC_CLKDIV        0x00C   // 时钟分频
#define DW_MMC_CMD           0x010   // 命令寄存器
#define DW_MMC_RESP0         0x014   // 响应寄存器0
#define DW_MMC_RESP1         0x018   // 响应寄存器1
#define DW_MMC_RINTSTS       0x01C   // 原始中断状态
#define DW_MMC_INTMASK       0x020   // 中断掩码
#define DW_MMC_FIFOTH        0x028   // FIFO阈值
#define DW_MMC_BLKSIZ        0x04C   // 块大小
#define DW_MMC_BYTCNT        0x050   // 字节计数
#define DW_MMC_DBADDR        0x058   // DMA描述符地址

你想想看,这些寄存器就是你和硬件对话的"电话"。每个bit都对应一个硬件行为。我调试时习惯先把RINTSTS寄存器打印出来,看中断状态位就知道卡在哪一步了。

1.4 小结

这一章我们搭好了RK存储接口的知识框架。记住三点:

  1. 存储子系统是分层结构,问题定位要逐层排查
  2. 四种接口各有适用场景,eMMC最省心,NAND最折腾
  3. 控制器寄存器是调试的入口,先读状态寄存器再动手