tpu-sg2002 0.1.0

TPU driver in Rust for SG2002 SoC.
Documentation
  • Coverage
  • 30.49%
    100 out of 328 items documented0 out of 51 items with examples
  • Size
  • Source code size: 105.16 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 11.59 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 41s Average build duration of successful builds.
  • all releases: 41s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Repository
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • elliott10

SG2002 TPU Device Driver

SG2002 TPU 设备的Rust驱动。

使用 Rust 最小化设备层实现,去除操作系统内核依赖,保留硬件操作逻辑,便于在裸机或自研RustOS上集成运行。

特性

  • KernelFns 抽象层:隔离系统相关能力(日志、时间、时钟控制、缓存同步)
  • 硬件操作:TDMA/TIU 寄存器访问与控制流程
  • DMA 缓冲区执行:支持描述符模式和 PIO 模式
  • 挂起/恢复:支持电源管理
  • 结构对齐:IOCTL 结构体使用 #[repr(C)] 保证 ABI 兼容

代码结构

src/
├── lib.rs          # 库入口,类型导出,TpuError 定义
├── types.rs        # 数据类型 (DmaHeader, CpuSyncDesc, TpuConfig, TpuTdmaPioInfo)
├── device.rs       # TPU 设备核心实现 (TpuDevice)
├── kernel_fns.rs   # 内核函数抽象 trait (KernelFns)
├── platform.rs     # 平台相关结构 (TdmaReg, TpuRegBackup, 状态解析)
├── pmu.rs          # PMU 性能监控 (TpuPmu, PmuSummary)
├── registers.rs    # TDMA/TIU 硬件寄存器常量
└── ioctrl.rs       # IOCTL 参数结构定义

调用流程

本库的 API 设计参照 Linux 驱动模块的生命周期:

Linux 驱动 vs Rust 库对照

维度 Linux 驱动实现 Rust 库实现 StarryOS 适配层
设备生命周期 cvi_tpu_probe/open/remove + platform_tpu_* TpuDevice::new/open/platform_init/platform_deinit /dev/cvi-tpu0 设备对象中持有 TpuDevice
提交入口 CVITPU_SUBMIT_DMABUF -> cvi_tpu_submit() -> worker -> platform_run_dmabuf() 直接 run_dmabuf() ioctl(CVITPU_SUBMIT_DMABUF) 同步调用 run_dmabuf()
等待入口 CVITPU_WAIT_DMABUF -> wait_event_interruptible(done_list) 库不管理 OS 等待队列 wait_dmabuf 在适配层按 seq_no 查询 done_list
缓存同步 CVITPU_DMABUF_FLUSH/INVLD(_FD) KernelFns::dma_sync_for_* 抽象 StarryOS 用 fence/ion 信息做同步
描述符解析 内核直接按 C 结构体解析 dma_hdr_t + cvi_cpu_sync_desc_t[] parse_dmabuf_view() 统一解析与边界检查 适配层调用 parse_dmabuf_view(),不再手写解析
TDMA 完成等待 中断完成 + completion 等待 wait_tdma_done() 紧凑轮询 + 超时 由库内部处理,适配层仅接收结果
超时恢复 platform_tpu_reset() reset() run_dmabuf 超时后可由上层执行 reset
挂起恢复 platform_tpu_suspend/resume suspend()/resume() 可由系统电源管理路径调用

常用 ioctl 对照(用户态视角):

ioctl Linux 语义 StarryOS 当前语义
CVITPU_SUBMIT_DMABUF (_IOC(_IOC_WRITE, 0x70, 0x1, 0x8)) 提交任务入队 同步执行一次 run_dmabuf 并记录 seq_no 结果
CVITPU_WAIT_DMABUF (`_IOC(_IOC_READ _IOC_WRITE, 0x70, 0x6, 0x8)`) seq_no 阻塞等待完成
CVITPU_DMABUF_FLUSH (nr=0x4) CPU -> Device cache sync 调用 dma_sync_for_device
CVITPU_DMABUF_INVLD (nr=0x5) Device -> CPU cache sync 调用 dma_sync_for_cpu

在Rust OS中的调用序列

基于 YOLOv8 on StarryOS 实际运行于SG2002硬件平台的建议集成流程:

  1. 系统初始化阶段

    • 创建 TpuDevice::new(...)
    • 调用 probe_setting()
    • 在设备初始化阶段调用一次 platform_init()
  2. 用户态准备阶段(/dev/ion + /dev/cvi-tpu0

    • ION_IOC_ALLOC 分配 dmabuf
    • mmap 映射 ion buffer 到用户态
    • CVITPU_DMABUF_INVLD / CVITPU_DMABUF_FLUSH 做缓存同步
  3. 提交执行阶段(核心热路径)

    • CVITPU_SUBMIT_DMABUF
    • 驱动侧通过 parse_dmabuf_view() 解析 header/descs
    • 调用 run_dmabuf(paddr, header, descs)
  4. 等待完成阶段

    • CVITPU_WAIT_DMABUF
    • 使用与 submit 一致的 seq_no 获取结果
  5. 可选收尾

    • 继续下一帧提交(推荐)
    • 设备长时间空闲时再 platform_deinit()

适配的示例代码


// 1. 实现 KernelFns trait
struct MyKernelFns {
    // 可包含时钟控制器、复位控制器的引用
}

impl KernelFns for MyKernelFns {
    fn sleep_ms(&self, ms: u32) {
        // 实现毫秒级延时
    }
    
    fn now_us(&self) -> TimeStamp {
        // 返回微秒级单调时间戳
        0
    }
    
    fn log(&self, level: LogLevel, msg: &str) {
        // 日志输出
    }
    
    fn enable_clocks(&self) {
        // 使能 clk_tpu_axi, clk_tpu_fab
    }
    
    fn disable_clocks(&self) {
        // 关闭 TPU 时钟
    }
    
    fn reset(&self) {
        // 触发 res_tdma, res_tpu, res_tpusys 复位
    }
    
    fn dma_sync_for_device(&self, paddr: PhysAddr, size: usize) {
        // 刷新 CPU cache 到内存 (DMA_TO_DEVICE)
    }
    
    fn dma_sync_for_cpu(&self, paddr: PhysAddr, size: usize) {
        // 使 CPU cache 无效化 (DMA_FROM_DEVICE)
    }
}

// 2. 设备探测阶段 (probe)
fn tpu_probe() -> Result<TpuDevice<MyKernelFns>, TpuError> {
    // 从设备树获取寄存器地址
    let tdma_base = NonNull::new(0x0C00_0000 as *mut u8).unwrap();
    let tiu_base = NonNull::new(0x0C01_0000 as *mut u8).unwrap();
    
    let config = TpuConfig {
        pmu_buf_size: 0,      // PMU 缓冲区大小,0 表示禁用
        pmu_buf_paddr: 0,     // PMU 缓冲区物理地址
    };
    
    let kfns = MyKernelFns { /* ... */ };
    
    let mut tpu = TpuDevice::new(tdma_base, tiu_base, config, kfns);
    tpu.probe_setting();
    
    Ok(tpu)
}

// 3. 中断处理函数
fn tpu_irq_handler(tpu: &mut TpuDevice<MyKernelFns>) {
    let status = tpu.irq_handle();
    // 根据 status 处理中断
}

// 4. 执行一次 dmabuf 提交(StarryOS 驱动热路径)
fn submit_one_dmabuf(
    tpu: &mut TpuDevice<MyKernelFns>,
    dmabuf_vaddr: *const u8,
    dmabuf_len: usize,
    dmabuf_paddr: PhysAddr,
) -> Result<(), TpuError> {
    // dmabuf 结构解析已下沉到 tpu_sg2002
    let parsed = unsafe { parse_dmabuf_view(dmabuf_vaddr, dmabuf_len) }?;

    // 直接执行,header/descs 为零拷贝借用
    let result = tpu.run_dmabuf(dmabuf_paddr, parsed.header, parsed.descs);

    if let Err(TpuError::Timeout) = result {
        tpu.reset()?;
    }

    result
}

// 5. 电源管理(可选)
fn tpu_suspend(tpu: &mut TpuDevice<MyKernelFns>) -> Result<(), TpuError> {
    tpu.suspend()
}

fn tpu_resume(tpu: &mut TpuDevice<MyKernelFns>) -> Result<(), TpuError> {
    tpu.resume()
}

// 6. 用户态 ioctl 的典型顺序(伪代码)
fn user_ioctl_sequence_example() {
    // open("/dev/cvi-tpu0")
    // open("/dev/ion")
    // ION_IOC_ALLOC + mmap
    // ioctl(CVITPU_DMABUF_INVLD)
    // fill command buffer
    // ioctl(CVITPU_DMABUF_FLUSH)
    // ioctl(CVITPU_SUBMIT_DMABUF)
    // ioctl(CVITPU_WAIT_DMABUF)
}

KernelFns Trait

实现此 trait 以适配不同运行环境:

精简评估结论:

  • now_us 是硬性必需(超时与轮询逻辑核心依赖)。
  • enable_clocks/disable_clocks/reset 保留为可选钩子,符合不同 SoC 的电源域差异。
  • dma_sync_for_device/dma_sync_for_cpu 保留为可选钩子,用于兼容有 cache 维护要求的平台。
  • sleep_ms 在当前 SG2002 快路径不是必需;已调整为默认空实现,用于降低接入方实现负担。
pub trait KernelFns {
    /// 毫秒级睡眠
    fn sleep_ms(&self, _ms: u32) {}
    
    /// 获取微秒级单调时间戳
    fn now_us(&self) -> TimeStamp;
    
    /// 日志输出
    fn log(&self, level: LogLevel, msg: &str);
    
    /// 使能 TPU 时钟(可选)
    fn enable_clocks(&self) {}
    
    /// 关闭 TPU 时钟(可选)
    fn disable_clocks(&self) {}
    
    /// 复位 TPU 硬件(可选)
    fn reset(&self) {}

    // DMA 内存申请相关的函数

    /// DMA 缓存同步(可选)
    fn dma_sync_for_device(&self, _paddr: PhysAddr, _size: usize) {}
    fn dma_sync_for_cpu(&self, _paddr: PhysAddr, _size: usize) {}
}

编译

cargo build --target=riscv64gc-unknown-none-elf

参考

  • 原始 C 驱动的Linux 内核版本:5.10.4
  • HAL 实现:hal/mars(Mars 平台)
  • 设备树兼容字符串:cvitek,tpu

SG2002 硬件信息

资源 描述
TDMA 寄存器 设备树 tdma 资源
TIU 寄存器 设备树 tiu 资源
中断 平台中断 1 (TDMA)
时钟 clk_tpu_axi, clk_tpu_fab
复位 res_tdma, res_tpu, res_tpusys

说明

  • 需要实现 KernelFns trait 以提供平台相关功能
  • run_dmabuf 实现了 hal/mars 的核心提交流程
  • 该库不包含 Linux 设备模型与中断注册逻辑,由 RustOS 操作系统驱动框架提供
  • 不支持 TEE (安全执行环境)