一 整体概述 1.1 程序文件位置分布 1 2 3 4 5 6 7 8 RTOS中DSMC代码,dsmc-controller.c是控制器初始化代码,dsmc-host.c是主机驱动代码 dsmc-lb-device.c是总线设备用户接口驱动程序,dsmc-lb-slave.c是从机程序 SDK/GA3506_Linux_Source/kernel-6.1 /drivers/memory/rockchip/dsmc-controller.c SDK/GA3506_Linux_Source/kernel-6.1 /drivers/memory/rockchip/dsmc-host.c SDK/GA3506_Linux_Source/kernel-6.1 /drivers/memory/rockchip/dsmc-lb-device.c SDK/GA3506_Linux_Source/kernel-6.1 /drivers/memory/rockchip/dsmc-lb-slave.c
1.2 四个文件整体之间的关系 四个文件尽管分为控制器、主机、接口、从机四部分,但总体来说,从功能上来看只有主机和从机两个部分主机dsmc-host.c依赖dsmc-controller.c和dsmc-lb-device.c完成整体功能从机不依赖其他DSMC文件,只在dsmc-lb-slave.c里写寄存器配置DSMC,处理中断等
1 2 3 4 5 6 7 8 主机端Host dsmc-host.c 注册 platform 驱动,probe 时会: 调用 dsmc-controller.c 的底层初始化接口rockchip_dsmc_ctrller_init,完成控制器硬件初始化 调用 dsmc-lb-device.c 注册 Local Bus 设备,创建 /dev/dsmc/... 字符设备节点,提供用户空间访问接口 注册 DMA 和中断,做好数据搬运准备 用户程序通过 /dev/dsmc/ 下的设备节点,发起 DMA 读写请求open/ioctl ioctl 处理,配置 DMA 参数,调用 dma_memcpy_init/dma_memcpy_trans_start 通过 dsmc-host.c 提供的 ops 接口,最终调用 dsmc-controller.c 的底层 DMA 函数发送出去
1 2 3 4 5 6 7 8 从机端Slave dsmc-lb-slave.c 注册 platform 驱动,probe 时: 解析 dts,获取资源和内存映射 初始化寄存器,配置为 slave 模式 申请中断,等待主机端的中断操作通知 收到中断(如 S2H),进入中断服务函数 rockchip_dsmc_lb_slave_irq 调用 dsmc_lb_slave_dma_trigger(),触发本地 DMA 硬件搬运 搬运完成后清除中断,等待下一次操作
二 控制器驱动代码解析 2.1 控制器驱动初始化 dsmc-controller.c dsmc-controller.c主要负责 DSMC 控制器的底层硬件初始化、PSRAM检测与配置、延迟线训练、DMA 触发、寄存器操作等功能。它是整个 DSMC 总线主控端驱动的底层核心,直接操作硬件寄存器,完成对存储器和总线的初始化和管理。在RTOS中与其对应的是HAL_DSMC_HOST_Init中部分内容
延迟线(DLL)训练:是为总线采样时钟增加适当延时,使得数据到达时间一致性
主要结构体
1 2 3 struct rockchip_dsmc:DSMC控制器的核心结构体,包含寄存器基址、配置参数等 struct dsmc_config_cs:描述每个chip select的配置信息,时序、宽度、延迟等 struct dsmc_map:映射的内存区域信息
下列函数通过 EXPORT_SYMBOL 导出,可以被其他内核模块调用,比如dsmc-host.c等
1 2 3 4 5 6 7 rockchip_dsmc_dll_training:延迟线训练 rockchip_dsmc_lb_dma_trigger_by_host:主控触发 DMA rockchip_dsmc_lb_dma_hw_mode_dis:关闭 DMA 硬件模式 rockchip_dsmc_ctrller_init:主控控制器初始化 rockchip_dsmc_lb_init:本地总线初始化 rockchip_dsmc_psram_reinit:PSRAM 重新初始化 rockchip_dsmc_device_dectect:设备检测
大致调用流程:参考dsmc-host.c
1 2 3 4 1调用rockchip_dsmc_ctrller_init初始化控制器 2调用rockchip_dsmc_device_dectect检测并识别PSRAM 3调用rockchip_dsmc_dll_training进行延迟线训练 4调用rockchip_dsmc_psram_reinit可重新初始化PSRAM参数
三 主机驱动代码解析 3.1 主机驱动初始化代码流向 1 2 3 4 5 6 模块加载 → 驱动注册 → probe资源申请 → dts参数解析 → 控制器/设备初始化 → 内存映射 → DMA/中断注册 → 对外API注册 → 正常工作 → 释放资源 → 注销驱动 rk_dsmc_init -> platform_driver_register(&rk_dsmc_driver) -> rk_dsmc_probe -> dsmc_parse_dt -> dsmc_init -> dsmc_mem_remap ->rockchip_dsmc_dma_request -> priv->ops = &rockchip_dsmc_ops -> 正常工作(上层ops调用等)-> rk_dsmc_remove -> platform_driver_unregister(&rk_dsmc_driver)-> rk_dsmc_exit
3.2 主机驱动代码框架 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 结构体 struct rockchip_dsmc :主控结构体,包含寄存器映射、配置参数、DMA 、中断等struct dsmc_ctrl_config :控制器配置,包括各chip select 的参数struct dsmc_transfer :DMA 传输相关参数与状态rk_dsmc_init ():类与平台驱动注册,创建DSMC 类,通常用于sysfs 、热插拔等管理platform_driver_register ():注册平台驱动,关联 .probe = rk_dsmc_probe,设备树匹配到 compatible 节点后会自动调用 proberk_dsmc_probe () :平台驱动探测函数probe资源申请(malloc ),DMA申请与时钟初始化等dsmc_parse_dt () :dts参数解析,读取slave/psram/lb-slave等节点参数,解析物理内存、时序、属性等dsmc_init () :DSMC控制器初始化,内部会调用dsmc-controller.c里面的函数,实现控制器底层初始化dsmc_mem_remap () :内存空间映射与设备注册,RTS可以直接访问物理地址,Linux下必须做虚拟地址映射priv->ops = &rockchip_dsmc_ops:ops对外操作函数集注册,提供标准的 read、write、copy_from、copy_to 等接口给上层调用 用户获取DSMC设备指针,通过 ops 中的API进行寄存器读写、DMA数据搬运等操作 rk_dsmc_remove:关闭并释放时钟、DMA、内存映射、local bus设备等资源 rk_dsmc_exit:注销平台驱动,销毁DSMC类。
四 DSMC Local Bus(LB)设备驱动代码解析 dsmc-lb-device.c 此文件负责DSMC控制器驱动 Local Bus 的字符设备节点注册、DMA 操作、用户接口的实现,由主驱动调用,用于实现用户空间访问和数据交换。
4.1 驱动初始化代码流向 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 rockchip_dsmc_lb_class_create / rockchip_dsmc_lb_class_destroy 创建/销毁 dsmc_class,用于 device_create。 rockchip_dsmc_register_lb_device / rockchip_dsmc_unregister_lb_device 注册/注销 Local Bus 字符设备节点,分配 cdev,生成 /dev/dsmc/csX/regionY 设备文件。 dsmc_fops:dma操作集 dsmc_ioctl:支持 DMA 配置、启动、获取时间、释放等命令。 dma_memcpy_init:申请并配置 DMA 通道 dma_memcpy_trans_start:提交 DMA 任务,等待完成 dma_cb_isr:DMA 传输完成回调 在 dsmc-host.c 或 dsmc-controller.c 里,初始化 Local Bus 设备时,会调用: rockchip_dsmc_lb_class_create()→ 创建 class rockchip_dsmc_register_lb_device()→ 为每个 cs/region 注册字符设备节点 卸载时调用: rockchip_dsmc_unregister_lb_device() rockchip_dsmc_lb_class_destroy()
4.2 驱动代码调用细节 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 主驱动dsmc-host.c在 probe 时调用rockchip_dsmc_lb_class_create()创建 class,用于后续设备节点挂载 rockchip_dsmc_register_lb_device(dev, cs)为每个 cs(chip select)下的每个 region 注册字符设备节点(/dev/dsmc/csX/regionY) 用户程序通过 /dev/dsmc/csX/regionY 设备节点进行操作如下: open("/dev/dsmc/csX/regionY", ...)//打开设备接口 → 内核调用 dsmc_open() 打开 dsmc 设备,分配DMA ioctl(fd, DMA_MEMCPY_SETUP, ¶ms) 发送参数 → 内核调用 dsmc_ioctl() 从用户空间拷贝参数到 rw_dsmc_params 分配一块 DMA 一致性内存(dma_alloc_coherent) 设置 DMA 源/目的物理地址,虚拟地址等 调用 dma_memcpy_init() 申请并配置 DMA 通道 ioctl(fd, DMA_MEMCPY_START) → 内核调用 dsmc_ioctl(DMA_MEMCPY_START, ...) 调用 dma_memcpy_trans_start() 配置 DMA 描述符 设置回调(dma_cb_isr) 提交并启动 DMA 阻塞等待传输完成(wait_for_completion) ioctl(fd, DMA_MEMCPY_GET_TIME) → 内核调用 dsmc_ioctl(DMA_MEMCPY_GET_TIME, ...) 如果上次 DMA 完成,返回耗时(write_time) fd.close() → 内核调用 dsmc_release() 释放 DMA 结构体
五 从机驱动代码解析dsmc-lb-slave.c 此文件 是 DSMC Local Bus 的Slave端驱动,用于管理从设备的寄存器、时钟和总线协议相关配置
主机端Host通过 DSMC 通道发起 DMA 操作从机端Slave收到中断后,触发硬件 DMA 拷贝,完成数据交互
5.1 系统如何启动驱动? 设备树匹配 → probe 初始化 → 寄存器初始化 → 申请中断 → 中断触发时,启动 DMA 传输 → 中断清除,等待下一次传输
5.2 从机驱动初始化代码流向 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 struct rockchip_dsmc_lb_slave 保存了 slave 端的所有硬件资源指针和内存映射信息 module_platform_driver(rk_dsmc_lb_slave_driver):注册 platform 驱动,驱动入口与设备匹配驱动入口与设备匹配 rk_dsmc_lb_slave_driver:指定 probe/remove、of_match_table rk_dsmc_lb_slave_probe():分配并初始化 rockchip_dsmc_lb_slave 结构体 解析 dts 的 memory-region,获取 slave 端映射内存物理地址和大小 调用 dsmc_lb_slave_init() 做寄存器初始化,申请中断,绑定 rockchip_dsmc_lb_slave_irq dsmc_lb_slave_init():寄存器初始化,使能slave模式 rockchip_dsmc_lb_slave_irq():检查中断状态,调用 dsmc_lb_slave_dma_trigger()触发 DMA 传输,清除所有 H2S 中断 dsmc_lb_slave_dma_trigger():检查 DMA 中断状态,等待清空,通过写寄存器触发 slave 到 host 的 DMA 硬件拷贝 rk_dsmc_lb_slave_remove():关闭并释放时钟