Skip to main content

strat9_bus_drivers/
omap_l3_smx.rs

1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3use core::sync::atomic::{AtomicU64, Ordering};
4
5const L3_AGENT_CONTROL: usize = 0x020;
6const L3_AGENT_STATUS: usize = 0x028;
7const L3_ERROR_LOG: usize = 0x058;
8const L3_ERROR_LOG_ADDR: usize = 0x060;
9const L3_SI_FLAG_STATUS_0: usize = 0x510;
10const L3_SI_FLAG_STATUS_1: usize = 0x530;
11
12const L3_AGENT_STATUS_CLEAR_IA: u32 = 0x1000_0000;
13const L3_AGENT_STATUS_CLEAR_TA: u32 = 0x0100_0000;
14
15const L3_ERROR_LOG_MULTI: u32 = 1 << 31;
16const L3_ERROR_LOG_SECONDARY: u32 = 1 << 30;
17const L3_ERROR_LOG_CODE_MASK: u32 = 0x0F00_0000;
18const L3_ERROR_LOG_CODE_SHIFT: u32 = 24;
19const L3_ERROR_LOG_INITID_MASK: u32 = 0x0000_FF00;
20const L3_ERROR_LOG_INITID_SHIFT: u32 = 8;
21const L3_ERROR_LOG_CMD_MASK: u32 = 0x0000_0007;
22
23const COMPATIBLE: &[&str] = &["ti,omap3-l3-smx"];
24
25const L3_ERROR_CODES: &[&str] = &[
26    "no error",
27    "unsupported command",
28    "address hole",
29    "protection violation",
30    "in-band error",
31    "request timeout (not accepted)",
32    "request timeout (no response)",
33];
34
35const L3_APP_BASES: &[usize] = &[
36    0x1400, 0x1800, 0x1C00, 0x4400, 0x4000, 0x5800, 0x5400, 0x4C00, 0x5000, 0x3000,
37];
38
39const L3_DEBUG_BASES: &[usize] = &[0x1400, 0x5C00, 0x1800];
40
41pub struct Omap3L3ErrorInfo {
42    pub code: u32,
43    pub initiator: u32,
44    pub cmd: u32,
45    pub address: u32,
46    pub is_multi: bool,
47    pub is_secondary: bool,
48}
49
50impl Omap3L3ErrorInfo {
51    /// Performs the code str operation.
52    pub fn code_str(&self) -> &'static str {
53        L3_ERROR_CODES.get(self.code as usize).unwrap_or(&"unknown")
54    }
55}
56
57pub struct OmapL3Smx {
58    regs: MmioRegion,
59    error_count: AtomicU64,
60    power_state: PowerState,
61}
62
63impl OmapL3Smx {
64    /// Creates a new instance.
65    pub fn new() -> Self {
66        Self {
67            regs: MmioRegion::new(),
68            error_count: AtomicU64::new(0),
69            power_state: PowerState::Off,
70        }
71    }
72
73    /// Reads error at.
74    pub fn read_error_at(&self, base_offset: usize) -> Omap3L3ErrorInfo {
75        let err_log = self.regs.read32(base_offset + L3_ERROR_LOG);
76        let address = self.regs.read32(base_offset + L3_ERROR_LOG_ADDR);
77
78        let code = (err_log & L3_ERROR_LOG_CODE_MASK) >> L3_ERROR_LOG_CODE_SHIFT;
79        let initiator = (err_log & L3_ERROR_LOG_INITID_MASK) >> L3_ERROR_LOG_INITID_SHIFT;
80        let cmd = err_log & L3_ERROR_LOG_CMD_MASK;
81
82        Omap3L3ErrorInfo {
83            code,
84            initiator,
85            cmd,
86            address,
87            is_multi: (err_log & L3_ERROR_LOG_MULTI) != 0,
88            is_secondary: (err_log & L3_ERROR_LOG_SECONDARY) != 0,
89        }
90    }
91
92    /// Performs the clear error at operation.
93    pub fn clear_error_at(&self, base_offset: usize) {
94        self.regs.write32(
95            base_offset + L3_AGENT_STATUS,
96            L3_AGENT_STATUS_CLEAR_IA | L3_AGENT_STATUS_CLEAR_TA,
97        );
98        self.regs.write32(base_offset + L3_ERROR_LOG, 0);
99    }
100
101    /// Reads flag status.
102    pub fn read_flag_status(&self, irq_type: usize) -> u32 {
103        let offset = if irq_type == 0 {
104            L3_SI_FLAG_STATUS_0
105        } else {
106            L3_SI_FLAG_STATUS_1
107        };
108        self.regs.read32(offset)
109    }
110
111    /// Handles error irq.
112    pub fn handle_error_irq(&mut self, irq_type: usize) -> Option<Omap3L3ErrorInfo> {
113        let status = self.read_flag_status(irq_type);
114        if status == 0 {
115            return None;
116        }
117
118        let source = status.trailing_zeros() as usize;
119        let bases = if irq_type == 0 {
120            L3_APP_BASES
121        } else {
122            L3_DEBUG_BASES
123        };
124
125        if source >= bases.len() {
126            return None;
127        }
128
129        let base = bases[source];
130        let info = self.read_error_at(base);
131        self.clear_error_at(base);
132        self.error_count.fetch_add(1, Ordering::Relaxed);
133        Some(info)
134    }
135}
136
137impl BusDriver for OmapL3Smx {
138    /// Performs the name operation.
139    fn name(&self) -> &str {
140        "omap-l3-smx"
141    }
142
143    /// Performs the compatible operation.
144    fn compatible(&self) -> &[&str] {
145        COMPATIBLE
146    }
147
148    /// Performs the init operation.
149    fn init(&mut self, base: usize) -> Result<(), BusError> {
150        self.regs.init(base, 0x10000);
151        self.power_state = PowerState::On;
152        Ok(())
153    }
154
155    /// Performs the shutdown operation.
156    fn shutdown(&mut self) -> Result<(), BusError> {
157        self.power_state = PowerState::Off;
158        Ok(())
159    }
160
161    /// Reads reg.
162    fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
163        if !self.regs.is_valid() {
164            return Err(BusError::InitFailed);
165        }
166        Ok(self.regs.read32(offset))
167    }
168
169    /// Writes reg.
170    fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
171        if !self.regs.is_valid() {
172            return Err(BusError::InitFailed);
173        }
174        self.regs.write32(offset, value);
175        Ok(())
176    }
177
178    /// Performs the error count operation.
179    fn error_count(&self) -> u64 {
180        self.error_count.load(Ordering::Relaxed)
181    }
182
183    /// Handles irq.
184    fn handle_irq(&mut self) -> bool {
185        let app = self.handle_error_irq(0);
186        let dbg = self.handle_error_irq(1);
187        app.is_some() || dbg.is_some()
188    }
189}