跳到主要内容

DSMC 开发指南

本文档基于瑞芯微官方文档 Rockchip_Developer_Guide_DSMC_CN.pdf(V1.0.0, 2024-06-14)整理,介绍 Rockchip DSMC(Double Data Rate Serial Memory Controller,双倍速率串行存储器控制器)的驱动配置与使用方法。

适用范围
  • 芯片平台:RK3576
  • 内核版本:kernel 6.10
  • 读者对象:技术支持工程师、软件开发工程师

一、名称解释

缩写全称说明
DSMCDouble Data Rate Serial Memory Controller双倍速率串行存储器控制器
PSRAMPseudo Static Random Access Memory伪静态随机存储器
DPRAMDual Port Random Access Memory双向端口随机存取存储器

二、概述

DSMC(双倍速率串行存储器控制器)通过命令、地址、数据线分时复用,数据上下沿传输,具有少引脚数、高带宽的特点。

关键特性:

  • 数据线位宽支持 x8、x16
  • 最多支持 4 个 chip select(CS0~CS3)
  • 传输协议支持:
    • Hyperbus PSRAM
    • Xccela PSRAM
    • Local bus(从设备需使用 RK 开发的 slave 模型或协议相同)

PSRAM 支持厂家: Winbond、AP Memory、Cypress、ISSI 等。


三、DSMC 驱动

3.1 驱动文件

文件路径说明
drivers/memory/rockchip/dsmc-host.c主要驱动程序
drivers/memory/rockchip/dsmc-controller.cDSMC 控制器行为配置
drivers/memory/rockchip/dsmc-lb-device.cDSMC Local bus 设备

3.2 DTS 节点配置

控制器节点

dsmc: dsmc@2a280000 {
...
clock-frequency = <100000000>; // DSMC 接口频率设置
...
rockchip,ranges = <0x0 0x10000000 0x0 0x2000000>;
rockchip,slave-dev = <&dsmc_slave>;

dsmc_slave: dsmc_slave {
compatible = "rockchip,dsmc-slave";
rockchip,clk-mode = <0>; // clk 模式,仅限 Local bus
status = "disabled";

// DQS DLL 延迟参数(4 个 CS,每个 CS 有 DQS0/DQS1)
rockchip,dqs-dll = <0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20>;
...
};
};

rockchip,ranges 含义:

  • 配置从设备内存空间的基地址和大小
  • 若外设是 PSRAM:每个 CS 分配对应大小的内存空间
  • 若外设是 Local Bus:每个 region 分配对应大小的内存空间
  • 不同 CS 内存空间大小不同时,配置最大的那个

PSRAM 从设备

psram {
psram0 { status = "disabled"; }; // CS0 接 PSRAM 时设为 okay
psram1 { status = "disabled"; }; // CS1 接 PSRAM 时设为 okay
psram2 { status = "disabled"; }; // CS2 接 PSRAM 时设为 okay
psram3 { status = "disabled"; }; // CS3 接 PSRAM 时设为 okay
};

驱动自动识别是 Hyperbus 还是 Xccela PSRAM。

Local Bus 从设备

每个从设备片选 CS 的访问空间可分成 1/2/4 个 region(均分):

lb-slave {
dsmc_lb_slave0: lb-slave0 { // CS0 Local bus 设备
status = "disabled";
dsmc_p0_region: region {
dsmc_p0_region0: region0 {
rockchip,attribute = "Merged FIFO"; // FIFO 模式
rockchip,ca-addr-width = <0>; // 0: 32bit, 1: 16bit
rockchip,dummy-clk-num = <1>;
rockchip,cs0-be-ctrled = <0>;
rockchip,cs0-ctrl = <0>;
status = "disabled";
};
dsmc_p0_region1: region1 {
rockchip,attribute = "No-Merge FIFO"; // 非合并 FIFO
...
status = "disabled";
};
dsmc_p0_region2: region2 {
rockchip,attribute = "DPRA"; // DPRAM 模式
...
status = "disabled";
};
dsmc_p0_region3: region3 {
rockchip,attribute = "Register"; // 寄存器模式
...
status = "disabled";
};
};
};
// lb-slave1 / lb-slave2 / lb-slave3(CS1/2/3)...
};

Region 属性类型:

属性说明
Merged FIFO可合并 FIFO
No-Merge FIFO不可合并 FIFO
DPRA双端口 RAM
Register寄存器空间

clk-mode 时钟行为:

说明
0CS 拉高期间无时钟,拉低期间有时钟(默认)
1无论 CS 如何变化,时钟一直有(作为参考时钟);无法跑高频且 AC timing 可调参数不可用
2CS 拉高和拉低期间都有时钟,但 CS 跳变沿前后会关闭几个时钟

3.3 内核配置

Symbol: ROCKCHIP_DSMC [=y]
Type : bool
Prompt: Rockchip DSMC driver
Location:
-> Device Drivers
-> Memory Controller drivers (MEMORY [=y])
-> Rockchip DSMC driver

四、内核态对 DSMC 从设备内存的访问

4.1 调用驱动接口

驱动提供的操作接口:

struct rockchip_dsmc_device *rockchip_dsmc_find_dev(void);

static struct dsmc_ops rockchip_dsmc_ops = {
.read = dsmc_read,
.write = dsmc_write,
.copy_from = dsmc_copy_from,
.copy_from_state = dsmc_copy_from_state,
.copy_to = dsmc_copy_to,
.copy_to_state = dsmc_copy_to_state,
};

接口说明:

  • read / write — CPU 读写 DSMC 从设备内存
  • copy_from — DMA 读取从设备内存,写入 host 端内存
  • copy_to — DMA 从 host 端内存写入从设备内存

使用示例:

static void test(void)
{
u32 cs;
struct rockchip_dsmc_device *dsmc_dev;

dsmc_dev = rockchip_dsmc_find_device_by_compat(rockchip_dsmc_get_compat(0));
if (!dsmc_dev) {
printk("error: can not find dsmc device\n");
return;
}

for (cs = 0; cs < DSMC_MAX_SLAVE_NUM; cs++) {
if (dsmc_dev->dsmc.cfg.cs_cfg[i].device_type == DSMC_UNKNOWN_DEVICE)
continue;
dsmc_dev->ops->write(dsmc_dev, cs, 0, test_addr, test_data);
}
}

4.2 直接访问

CPU 或 master 可直接访问 DSMC slave memory 空间:

  • 支持 Byte、half-word、word 的随机地址访问
  • 支持 cacheable、uncacheable、write combine 映射方式

五、用户态对 DSMC 的访问

5.1 通过特定节点访问

Local bus 使能时,驱动在 /dev/dsmc/ 下创建设备节点:

/dev/dsmc/cs0/region0   # CS0 的 region0 (Merged FIFO)
/dev/dsmc/cs0/region1 # CS0 的 region1 (No-Merge FIFO)
/dev/dsmc/cs0/region2 # CS0 的 region2 (DPRAM)
/dev/dsmc/cs0/region3 # CS0 的 region3 (Register)
...

访问步骤:

  1. open() 打开对应 region 设备节点
  2. mmap() 将设备内存映射到进程地址空间
  3. 读写设备内存
  4. munmap() 解除映射
  5. close() 关闭文件描述符

代码示例:

const char *device_name = "/dev/dsmc/cs0/region0";
size_t wantbytes = 0x200000;

int memfd = open(device_name, O_RDWR | O_SYNC);
if (memfd == -1) {
fprintf(stderr, "failed to open %s: %s\n", device_name, strerror(errno));
exit(EXIT_FAILURE);
}

// O_SYNC + MAP_LOCKED = uncached 映射
void *buf = mmap(0, wantbytes, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_LOCKED, memfd, 0x0);
if (buf == MAP_FAILED) {
fprintf(stderr, "failed to mmap: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}

// 读写 buf...
munmap(buf, wantbytes);
close(memfd);

5.2 直接访问

(通过物理地址映射等方式)


六、DSMC Slave 内存空间分配

6.1 PSRAM

外接 PSRAM 颗粒时,每个 CS 对应一片独立的 PSRAM 存储空间。

6.2 Local bus

Local bus 模式下,每个 CS 的空间分成多个 region,各 region 有独立属性。


七、DSMC Local Bus Host 与 Slave 的数据交互

7.1 FIFO

通过 FIFO 方式进行数据流传输,支持合并(Merged)和非合并(No-Merge)模式。

7.2 Register

通过寄存器读写进行控制和状态交互。


参考资料

  • 原始文档:Rockchip_Developer_Guide_DSMC_CN.pdf V1.0.0
  • 瑞芯微官网:www.rock-chips.com