Skip to main content

strat9_bus_drivers/
omap_l3_noc.rs

1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3use core::sync::atomic::{AtomicU64, Ordering};
4
5const L3_TARG_STDERRLOG_MAIN: usize = 0x48;
6const L3_TARG_STDERRLOG_HDR: usize = 0x4C;
7const L3_TARG_STDERRLOG_MSTADDR: usize = 0x50;
8const L3_TARG_STDERRLOG_INFO: usize = 0x58;
9const L3_TARG_STDERRLOG_SLVOFSLSB: usize = 0x5C;
10const L3_TARG_STDERRLOG_CINFO_INFO: usize = 0x64;
11const L3_TARG_STDERRLOG_CINFO_MSTADDR: usize = 0x68;
12const L3_TARG_STDERRLOG_CINFO_OPCODE: usize = 0x6C;
13
14const L3_FLAGMUX_REGERR0: usize = 0x0C;
15const L3_FLAGMUX_MASK0: usize = 0x08;
16
17const CLEAR_STDERR_LOG: u32 = 1 << 31;
18const CUSTOM_ERROR: u32 = 0x2;
19const STANDARD_ERROR: u32 = 0x0;
20
21const MAX_L3_MODULES: usize = 3;
22
23const COMPATIBLE: &[&str] = &[
24    "ti,omap4-l3-noc",
25    "ti,omap5-l3-noc",
26    "ti,dra7-l3-noc",
27    "ti,am4372-l3-noc",
28];
29
30pub struct L3TargetData {
31    pub offset: u32,
32    pub name: &'static str,
33}
34
35pub struct L3FlagmuxData {
36    pub offset: u32,
37    pub targets: &'static [L3TargetData],
38    pub mask_app_bits: u32,
39    pub mask_dbg_bits: u32,
40}
41
42pub struct L3MasterData {
43    pub id: u32,
44    pub name: &'static str,
45}
46
47pub struct OmapL3Noc {
48    modules: [MmioRegion; MAX_L3_MODULES],
49    num_modules: usize,
50    error_count: AtomicU64,
51    power_state: PowerState,
52    saved_mask_app: [u32; MAX_L3_MODULES],
53    saved_mask_dbg: [u32; MAX_L3_MODULES],
54}
55
56impl OmapL3Noc {
57    /// Creates a new instance.
58    pub fn new() -> Self {
59        Self {
60            modules: [MmioRegion::new(), MmioRegion::new(), MmioRegion::new()],
61            num_modules: 0,
62            error_count: AtomicU64::new(0),
63            power_state: PowerState::Off,
64            saved_mask_app: [0; MAX_L3_MODULES],
65            saved_mask_dbg: [0; MAX_L3_MODULES],
66        }
67    }
68
69    /// Initializes module.
70    pub fn init_module(&mut self, index: usize, base: usize, size: usize) {
71        if index < MAX_L3_MODULES {
72            self.modules[index].init(base, size);
73            if index >= self.num_modules {
74                self.num_modules = index + 1;
75            }
76        }
77    }
78
79    /// Handles target error.
80    pub fn handle_target_error(
81        &self,
82        module: usize,
83        target_offset: usize,
84    ) -> Result<ErrorInfo, BusError> {
85        if module >= self.num_modules || !self.modules[module].is_valid() {
86            return Err(BusError::InvalidArgument);
87        }
88
89        let base_offset = target_offset;
90        let main = self.modules[module].read32(base_offset + L3_TARG_STDERRLOG_MAIN);
91        let hdr = self.modules[module].read32(base_offset + L3_TARG_STDERRLOG_HDR);
92        let mstaddr = self.modules[module].read32(base_offset + L3_TARG_STDERRLOG_MSTADDR);
93
94        let err_type = if (hdr & 0xFF) == CUSTOM_ERROR {
95            ErrorType::Custom
96        } else {
97            ErrorType::Standard
98        };
99
100        let info = match err_type {
101            ErrorType::Standard => {
102                let slave_addr =
103                    self.modules[module].read32(base_offset + L3_TARG_STDERRLOG_SLVOFSLSB);
104                ErrorInfo {
105                    err_type,
106                    master_addr: mstaddr,
107                    slave_addr,
108                    header: hdr,
109                    main_reg: main,
110                }
111            }
112            ErrorType::Custom => {
113                let cinfo = self.modules[module].read32(base_offset + L3_TARG_STDERRLOG_CINFO_INFO);
114                ErrorInfo {
115                    err_type,
116                    master_addr: mstaddr,
117                    slave_addr: cinfo,
118                    header: hdr,
119                    main_reg: main,
120                }
121            }
122        };
123
124        self.modules[module].write32(base_offset + L3_TARG_STDERRLOG_MAIN, CLEAR_STDERR_LOG);
125
126        Ok(info)
127    }
128
129    /// Reads flagmux.
130    pub fn read_flagmux(&self, module: usize, inttype: usize) -> u32 {
131        if module >= self.num_modules || !self.modules[module].is_valid() {
132            return 0;
133        }
134        self.modules[module].read32(L3_FLAGMUX_REGERR0 + (inttype << 3))
135    }
136
137    /// Performs the mask target operation.
138    pub fn mask_target(&self, module: usize, target_bit: u32, inttype: usize) {
139        if module >= self.num_modules || !self.modules[module].is_valid() {
140            return;
141        }
142        let mask_offset = L3_FLAGMUX_MASK0 + (inttype << 3);
143        self.modules[module].set_bits32(mask_offset, 1 << target_bit);
144    }
145}
146
147#[derive(Debug, Clone, Copy)]
148pub enum ErrorType {
149    Standard,
150    Custom,
151}
152
153#[derive(Debug, Clone)]
154pub struct ErrorInfo {
155    pub err_type: ErrorType,
156    pub master_addr: u32,
157    pub slave_addr: u32,
158    pub header: u32,
159    pub main_reg: u32,
160}
161
162impl BusDriver for OmapL3Noc {
163    /// Performs the name operation.
164    fn name(&self) -> &str {
165        "omap-l3-noc"
166    }
167
168    /// Performs the compatible operation.
169    fn compatible(&self) -> &[&str] {
170        COMPATIBLE
171    }
172
173    /// Performs the init operation.
174    fn init(&mut self, base: usize) -> Result<(), BusError> {
175        self.init_module(0, base, 0x1000);
176        self.power_state = PowerState::On;
177        Ok(())
178    }
179
180    /// Performs the shutdown operation.
181    fn shutdown(&mut self) -> Result<(), BusError> {
182        self.power_state = PowerState::Off;
183        Ok(())
184    }
185
186    /// Performs the suspend operation.
187    fn suspend(&mut self) -> Result<(), BusError> {
188        for i in 0..self.num_modules {
189            if self.modules[i].is_valid() {
190                self.saved_mask_app[i] = self.modules[i].read32(L3_FLAGMUX_MASK0);
191                self.saved_mask_dbg[i] = self.modules[i].read32(L3_FLAGMUX_MASK0 + 8);
192            }
193        }
194        self.power_state = PowerState::Suspended;
195        Ok(())
196    }
197
198    /// Performs the resume operation.
199    fn resume(&mut self) -> Result<(), BusError> {
200        for i in 0..self.num_modules {
201            if self.modules[i].is_valid() {
202                self.modules[i].write32(L3_FLAGMUX_MASK0, self.saved_mask_app[i]);
203                self.modules[i].write32(L3_FLAGMUX_MASK0 + 8, self.saved_mask_dbg[i]);
204            }
205        }
206        self.power_state = PowerState::On;
207        Ok(())
208    }
209
210    /// Reads reg.
211    fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
212        if self.num_modules == 0 || !self.modules[0].is_valid() {
213            return Err(BusError::InitFailed);
214        }
215        Ok(self.modules[0].read32(offset))
216    }
217
218    /// Writes reg.
219    fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
220        if self.num_modules == 0 || !self.modules[0].is_valid() {
221            return Err(BusError::InitFailed);
222        }
223        self.modules[0].write32(offset, value);
224        Ok(())
225    }
226
227    /// Performs the error count operation.
228    fn error_count(&self) -> u64 {
229        self.error_count.load(Ordering::Relaxed)
230    }
231
232    /// Handles irq.
233    fn handle_irq(&mut self) -> bool {
234        self.error_count.fetch_add(1, Ordering::Relaxed);
235        true
236    }
237}