Skip to main content

strat9_bus_drivers/
vexpress_config.rs

1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3
4const SYS_MISC: usize = 0x00;
5const SYS_MISC_MASTERSITE: u32 = 1 << 14;
6
7const SYS_PROCID0: usize = 0x24;
8const SYS_PROCID1: usize = 0x28;
9const SYS_HBI_MASK: u32 = 0xFFF;
10
11const SYS_CFGDATA: usize = 0x40;
12const SYS_CFGCTRL: usize = 0x44;
13const SYS_CFGCTRL_START: u32 = 1 << 31;
14const SYS_CFGCTRL_WRITE: u32 = 1 << 30;
15const SYS_CFGSTAT: usize = 0x48;
16const SYS_CFGSTAT_ERR: u32 = 1 << 1;
17const SYS_CFGSTAT_COMPLETE: u32 = 1 << 0;
18
19const SITE_MB: u32 = 0;
20const SITE_DB1: u32 = 1;
21const SITE_DB2: u32 = 2;
22const SITE_MASTER: u32 = 0xF;
23
24const MAX_POLL_TRIES: u32 = 100;
25
26const COMPATIBLE: &[&str] = &["vexpress-syscfg"];
27
28/// Performs the cfg ctrl dcc operation.
29fn cfg_ctrl_dcc(n: u32) -> u32 {
30    (n & 0xF) << 26
31}
32/// Performs the cfg ctrl func operation.
33fn cfg_ctrl_func(n: u32) -> u32 {
34    (n & 0x3F) << 20
35}
36/// Performs the cfg ctrl site operation.
37fn cfg_ctrl_site(n: u32) -> u32 {
38    (n & 0x3) << 16
39}
40/// Performs the cfg ctrl position operation.
41fn cfg_ctrl_position(n: u32) -> u32 {
42    (n & 0xF) << 12
43}
44/// Performs the cfg ctrl device operation.
45fn cfg_ctrl_device(n: u32) -> u32 {
46    n & 0xFFF
47}
48
49pub struct VexpressConfig {
50    regs: MmioRegion,
51    master_site: u32,
52    power_state: PowerState,
53}
54
55impl VexpressConfig {
56    /// Creates a new instance.
57    pub fn new() -> Self {
58        Self {
59            regs: MmioRegion::new(),
60            master_site: SITE_MASTER,
61            power_state: PowerState::Off,
62        }
63    }
64
65    /// Performs the detect master site operation.
66    fn detect_master_site(&mut self) {
67        let misc = self.regs.read32(SYS_MISC);
68        self.master_site = if misc & SYS_MISC_MASTERSITE != 0 {
69            SITE_DB2
70        } else {
71            SITE_DB1
72        };
73    }
74
75    /// Reads procid.
76    pub fn read_procid(&self, site: u32) -> u32 {
77        let offset = if site == SITE_DB1 {
78            SYS_PROCID0
79        } else {
80            SYS_PROCID1
81        };
82        self.regs.read32(offset)
83    }
84
85    /// Performs the hbi operation.
86    pub fn hbi(&self) -> u32 {
87        let id = self.read_procid(self.master_site);
88        id & SYS_HBI_MASK
89    }
90
91    /// Performs the config read operation.
92    pub fn config_read(
93        &self,
94        site: u32,
95        position: u32,
96        dcc: u32,
97        function: u32,
98        device: u32,
99    ) -> Result<u32, BusError> {
100        let command = self.regs.read32(SYS_CFGCTRL);
101        if command & SYS_CFGCTRL_START != 0 {
102            return Err(BusError::Timeout);
103        }
104
105        let real_site = if site == SITE_MASTER {
106            self.master_site
107        } else {
108            site
109        };
110
111        let cmd = SYS_CFGCTRL_START
112            | cfg_ctrl_dcc(dcc)
113            | cfg_ctrl_site(real_site)
114            | cfg_ctrl_position(position)
115            | cfg_ctrl_func(function)
116            | cfg_ctrl_device(device);
117
118        self.regs.write32(SYS_CFGDATA, 0xDEAD_BEEF);
119        self.regs.write32(SYS_CFGSTAT, 0);
120        self.regs.write32(SYS_CFGCTRL, cmd);
121        crate::mmio::memory_barrier();
122
123        for _ in 0..MAX_POLL_TRIES {
124            let status = self.regs.read32(SYS_CFGSTAT);
125            if status & SYS_CFGSTAT_ERR != 0 {
126                return Err(BusError::IoError);
127            }
128            if status & SYS_CFGSTAT_COMPLETE != 0 {
129                return Ok(self.regs.read32(SYS_CFGDATA));
130            }
131        }
132
133        Err(BusError::Timeout)
134    }
135
136    /// Performs the config write operation.
137    pub fn config_write(
138        &self,
139        site: u32,
140        position: u32,
141        dcc: u32,
142        function: u32,
143        device: u32,
144        data: u32,
145    ) -> Result<(), BusError> {
146        let command = self.regs.read32(SYS_CFGCTRL);
147        if command & SYS_CFGCTRL_START != 0 {
148            return Err(BusError::Timeout);
149        }
150
151        let real_site = if site == SITE_MASTER {
152            self.master_site
153        } else {
154            site
155        };
156
157        let cmd = SYS_CFGCTRL_START
158            | SYS_CFGCTRL_WRITE
159            | cfg_ctrl_dcc(dcc)
160            | cfg_ctrl_site(real_site)
161            | cfg_ctrl_position(position)
162            | cfg_ctrl_func(function)
163            | cfg_ctrl_device(device);
164
165        self.regs.write32(SYS_CFGDATA, data);
166        self.regs.write32(SYS_CFGSTAT, 0);
167        self.regs.write32(SYS_CFGCTRL, cmd);
168        crate::mmio::memory_barrier();
169
170        for _ in 0..MAX_POLL_TRIES {
171            let status = self.regs.read32(SYS_CFGSTAT);
172            if status & SYS_CFGSTAT_ERR != 0 {
173                return Err(BusError::IoError);
174            }
175            if status & SYS_CFGSTAT_COMPLETE != 0 {
176                return Ok(());
177            }
178        }
179
180        Err(BusError::Timeout)
181    }
182}
183
184impl BusDriver for VexpressConfig {
185    /// Performs the name operation.
186    fn name(&self) -> &str {
187        "vexpress-config"
188    }
189
190    /// Performs the compatible operation.
191    fn compatible(&self) -> &[&str] {
192        COMPATIBLE
193    }
194
195    /// Performs the init operation.
196    fn init(&mut self, base: usize) -> Result<(), BusError> {
197        self.regs.init(base, 0x100);
198        self.detect_master_site();
199        self.power_state = PowerState::On;
200        Ok(())
201    }
202
203    /// Performs the shutdown operation.
204    fn shutdown(&mut self) -> Result<(), BusError> {
205        self.power_state = PowerState::Off;
206        Ok(())
207    }
208
209    /// Reads reg.
210    fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
211        if !self.regs.is_valid() {
212            return Err(BusError::InitFailed);
213        }
214        Ok(self.regs.read32(offset))
215    }
216
217    /// Writes reg.
218    fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
219        if !self.regs.is_valid() {
220            return Err(BusError::InitFailed);
221        }
222        self.regs.write32(offset, value);
223        Ok(())
224    }
225}