tpu-sg2002 0.1.0

TPU driver in Rust for SG2002 SoC.
Documentation
# 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` 阻塞等待完成 |`seq_no` 轮询 done_list 直到完成或超时 |
| `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](https://github.com/elliott10/StarryOS/tree/sg2002-dev/api/src/vfs/dev/cvi_tpu.rs) 实际运行于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()`

### 适配的示例代码

```rust

// 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 快路径不是必需;已调整为默认空实现,用于降低接入方实现负担。

```rust
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) {}
}
```


## 编译

```bash
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 (安全执行环境)