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 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 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 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 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 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 fn name(&self) -> &str {
165 "omap-l3-noc"
166 }
167
168 fn compatible(&self) -> &[&str] {
170 COMPATIBLE
171 }
172
173 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 fn shutdown(&mut self) -> Result<(), BusError> {
182 self.power_state = PowerState::Off;
183 Ok(())
184 }
185
186 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 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 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 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 fn error_count(&self) -> u64 {
229 self.error_count.load(Ordering::Relaxed)
230 }
231
232 fn handle_irq(&mut self) -> bool {
234 self.error_count.fetch_add(1, Ordering::Relaxed);
235 true
236 }
237}