Skip to main content

tpu_sg2002/
types.rs

1//! TPU data types and structures.
2
3use crate::{PhysAddr, TpuError, registers::CPU_ENGINE_DESCRIPTOR_NUM};
4use crate::platform::TPU_DMABUF_HEADER_M;
5
6/// DMA buffer header used by the TPU firmware.
7#[repr(C)]
8#[derive(Debug, Clone, Copy, Default)]
9pub struct DmaHeader {
10    pub dmabuf_magic_m: u16,
11    pub dmabuf_magic_s: u16,
12    pub dmabuf_size: u32,
13    pub cpu_desc_count: u32,
14    pub bd_desc_count: u32,
15    pub tdma_desc_count: u32,
16    pub tpu_clk_rate: u32,
17    pub pmubuf_size: u32,
18    pub pmubuf_offset: u32,
19    pub arraybase_0_l: u32,
20    pub arraybase_0_h: u32,
21    pub arraybase_1_l: u32,
22    pub arraybase_1_h: u32,
23    pub arraybase_2_l: u32,
24    pub arraybase_2_h: u32,
25    pub arraybase_3_l: u32,
26    pub arraybase_3_h: u32,
27    pub arraybase_4_l: u32,
28    pub arraybase_4_h: u32,
29    pub arraybase_5_l: u32,
30    pub arraybase_5_h: u32,
31    pub arraybase_6_l: u32,
32    pub arraybase_6_h: u32,
33    pub arraybase_7_l: u32,
34    pub arraybase_7_h: u32,
35    pub reserve: [u32; 8],
36}
37
38impl DmaHeader {
39    pub const MAGIC: u16 = TPU_DMABUF_HEADER_M;
40
41    pub fn is_valid(&self) -> bool {
42        // Keep compatibility with the original C driver, which validates only magic_m.
43        self.dmabuf_magic_m == Self::MAGIC
44    }
45
46    pub fn arraybase(&self, idx: usize) -> u64 {
47        let (lo, hi) = match idx {
48            0 => (self.arraybase_0_l, self.arraybase_0_h),
49            1 => (self.arraybase_1_l, self.arraybase_1_h),
50            2 => (self.arraybase_2_l, self.arraybase_2_h),
51            3 => (self.arraybase_3_l, self.arraybase_3_h),
52            4 => (self.arraybase_4_l, self.arraybase_4_h),
53            5 => (self.arraybase_5_l, self.arraybase_5_h),
54            6 => (self.arraybase_6_l, self.arraybase_6_h),
55            7 => (self.arraybase_7_l, self.arraybase_7_h),
56            _ => (0, 0),
57        };
58        (lo as u64) | ((hi as u64) << 32)
59    }
60
61    pub fn arraybase_l(&self) -> [u32; 8] {
62        [
63            self.arraybase_0_l, self.arraybase_1_l, self.arraybase_2_l, self.arraybase_3_l,
64            self.arraybase_4_l, self.arraybase_5_l, self.arraybase_6_l, self.arraybase_7_l,
65        ]
66    }
67}
68
69/// Borrowed view of a TPU command DMA buffer.
70#[derive(Debug, Clone, Copy)]
71pub struct DmabufView<'a> {
72    pub header: &'a DmaHeader,
73    pub descs: &'a [CpuSyncDesc],
74}
75
76/// Parse a TPU command DMA buffer from a raw CPU-accessible pointer.
77///
78/// # Safety
79///
80/// Caller must ensure `dmabuf_vaddr` points to readable memory of length
81/// `dmabuf_len` for the entire returned lifetime.
82pub unsafe fn parse_dmabuf_view<'a>(dmabuf_vaddr: *const u8, dmabuf_len: usize) -> Result<DmabufView<'a>, TpuError> {
83    if dmabuf_vaddr.is_null() {
84        return Err(TpuError::InvalidParameter);
85    }
86
87    let header_size = core::mem::size_of::<DmaHeader>();
88    if dmabuf_len < header_size {
89        return Err(TpuError::InvalidParameter);
90    }
91
92    let header = unsafe { &*(dmabuf_vaddr as *const DmaHeader) };
93    let desc_count = header.cpu_desc_count as usize;
94    let desc_bytes = desc_count
95        .checked_mul(core::mem::size_of::<CpuSyncDesc>())
96        .ok_or(TpuError::InvalidParameter)?;
97    let required = header_size
98        .checked_add(desc_bytes)
99        .ok_or(TpuError::InvalidParameter)?;
100    if required > dmabuf_len {
101        return Err(TpuError::InvalidParameter);
102    }
103
104    let desc_ptr = unsafe { dmabuf_vaddr.add(header_size) as *const CpuSyncDesc };
105    let descs = unsafe { core::slice::from_raw_parts(desc_ptr, desc_count) };
106
107    Ok(DmabufView { header, descs })
108}
109
110/// CPU sync descriptor embedded in command buffers.
111#[repr(C)]
112#[derive(Debug, Clone, Copy)]
113pub struct CpuSyncDesc {
114    pub op_type: u32,
115    pub num_bd: u32,
116    pub num_gdma: u32,
117    pub offset_bd: u32,
118    pub offset_gdma: u32,
119    pub reserved: [u32; 2],
120    pub str_data: [u8; (CPU_ENGINE_DESCRIPTOR_NUM - 7) * core::mem::size_of::<u32>()],
121}
122
123impl Default for CpuSyncDesc {
124    fn default() -> Self {
125        Self {
126            op_type: 0,
127            num_bd: 0,
128            num_gdma: 0,
129            offset_bd: 0,
130            offset_gdma: 0,
131            reserved: [0; 2],
132            str_data: [0; (CPU_ENGINE_DESCRIPTOR_NUM - 7) * core::mem::size_of::<u32>()],
133        }
134    }
135}
136
137impl CpuSyncDesc {
138    pub fn bd_count(&self) -> u32 { self.num_bd & 0xFFFF }
139    pub fn tdma_count(&self) -> u32 { self.num_gdma & 0xFFFF }
140}
141
142/// TPU device configuration.
143#[derive(Debug, Clone, Copy, Default)]
144pub struct TpuConfig {
145    pub pmu_buf_size: u32,
146    pub pmu_buf_paddr: PhysAddr,
147}
148
149/// TDMA PIO submission info.
150#[repr(C)]
151#[derive(Debug, Clone, Copy, Default)]
152pub struct TpuTdmaPioInfo {
153    pub paddr_src: u64,
154    pub paddr_dst: u64,
155    pub h: u32,
156    pub w_bytes: u32,
157    pub stride_bytes_src: u32,
158    pub stride_bytes_dst: u32,
159    pub enable_2d: u32,
160    pub leng_bytes: u32,
161}
162
163impl TpuTdmaPioInfo {
164    pub fn is_2d(&self) -> bool { self.enable_2d != 0 }
165}