strat9_bus_drivers/
vexpress_config.rs1use crate::{BusChild, BusDriver, BusError, PowerState, mmio::MmioRegion};
2use alloc::{string::String, vec::Vec};
3use core::sync::atomic::{AtomicBool, Ordering};
4
5const SYS_MISC: usize = 0x00;
6const SYS_MISC_MASTERSITE: u32 = 1 << 14;
7
8const SYS_PROCID0: usize = 0x24;
9const SYS_PROCID1: usize = 0x28;
10const SYS_HBI_MASK: u32 = 0xFFF;
11
12const SYS_CFGDATA: usize = 0x40;
13const SYS_CFGCTRL: usize = 0x44;
14const SYS_CFGCTRL_START: u32 = 1 << 31;
15const SYS_CFGCTRL_WRITE: u32 = 1 << 30;
16const SYS_CFGSTAT: usize = 0x48;
17const SYS_CFGSTAT_ERR: u32 = 1 << 1;
18const SYS_CFGSTAT_COMPLETE: u32 = 1 << 0;
19
20const SITE_MB: u32 = 0;
21const SITE_DB1: u32 = 1;
22const SITE_DB2: u32 = 2;
23const SITE_MASTER: u32 = 0xF;
24
25const MAX_POLL_TRIES: u32 = 100;
26
27const DCC_CTRL_REG: usize = 0x0;
31const DCC_CTRL_ENABLE: u32 = 1 << 0;
33const DCC_CTRL_DIV_MASK: u32 = 0xFF << 8;
35
36pub const DCC_TARGET_FREQ_MHZ: u32 = 50;
38pub const DCC_REF_FREQ_MHZ: u32 = 100;
40
41fn dcc_ctrl_divider(div: u32) -> u32 {
42 ((div.max(1)) << 8) & DCC_CTRL_DIV_MASK
43}
44
45const COMPATIBLE: &[&str] = &["vexpress-syscfg"];
46
47fn cfg_ctrl_dcc(n: u32) -> u32 {
49 (n & 0xF) << 26
50}
51fn cfg_ctrl_func(n: u32) -> u32 {
53 (n & 0x3F) << 20
54}
55fn cfg_ctrl_site(n: u32) -> u32 {
57 (n & 0x3) << 16
58}
59fn cfg_ctrl_position(n: u32) -> u32 {
61 (n & 0xF) << 12
62}
63fn cfg_ctrl_device(n: u32) -> u32 {
65 n & 0xFFF
66}
67
68pub struct VexpressConfig {
69 regs: MmioRegion,
70 dcc_regs: MmioRegion,
73 dcc_initialized: AtomicBool,
76 master_site: u32,
77 power_state: PowerState,
78}
79
80impl VexpressConfig {
81 pub fn new() -> Self {
83 Self {
84 regs: MmioRegion::new(),
85 dcc_regs: MmioRegion::new(),
86 dcc_initialized: AtomicBool::new(false),
87 master_site: SITE_MASTER,
88 power_state: PowerState::Off,
89 }
90 }
91
92 pub fn init_dcc_regs(&mut self, base: usize) {
96 self.dcc_regs.init(base, 0x10);
97 }
98
99 fn ensure_dcc_ready(&self) -> Result<(), BusError> {
102 if self.dcc_initialized.load(Ordering::Acquire) {
103 return Ok(());
104 }
105 if !self.dcc_regs.is_valid() {
106 return Err(BusError::InitFailed);
107 }
108 let div = (DCC_REF_FREQ_MHZ / DCC_TARGET_FREQ_MHZ).max(1);
109 self.dcc_regs
110 .write32(DCC_CTRL_REG, DCC_CTRL_ENABLE | dcc_ctrl_divider(div));
111 let rb = self.dcc_regs.read32(DCC_CTRL_REG);
113 if rb != (DCC_CTRL_ENABLE | dcc_ctrl_divider(div)) {
114 return Err(BusError::BusFault);
115 }
116 self.dcc_initialized.store(true, Ordering::Release);
117 Ok(())
118 }
119
120 fn detect_master_site(&mut self) {
122 let misc = self.regs.read32(SYS_MISC);
123 self.master_site = if misc & SYS_MISC_MASTERSITE != 0 {
124 SITE_DB2
125 } else {
126 SITE_DB1
127 };
128 }
129
130 pub fn read_procid(&self, site: u32) -> u32 {
132 let offset = if site == SITE_DB1 {
133 SYS_PROCID0
134 } else {
135 SYS_PROCID1
136 };
137 self.regs.read32(offset)
138 }
139
140 pub fn hbi(&self) -> u32 {
142 let id = self.read_procid(self.master_site);
143 id & SYS_HBI_MASK
144 }
145
146 pub fn config_read(
148 &self,
149 site: u32,
150 position: u32,
151 dcc: u32,
152 function: u32,
153 device: u32,
154 ) -> Result<u32, BusError> {
155 self.ensure_dcc_ready()?;
156
157 let command = self.regs.read32(SYS_CFGCTRL);
158 if command & SYS_CFGCTRL_START != 0 {
159 return Err(BusError::Timeout);
160 }
161
162 let real_site = if site == SITE_MASTER {
163 self.master_site
164 } else {
165 site
166 };
167
168 let cmd = SYS_CFGCTRL_START
169 | cfg_ctrl_dcc(dcc)
170 | cfg_ctrl_site(real_site)
171 | cfg_ctrl_position(position)
172 | cfg_ctrl_func(function)
173 | cfg_ctrl_device(device);
174
175 self.regs.write32(SYS_CFGDATA, 0xDEAD_BEEF);
176 self.regs.write32(SYS_CFGSTAT, 0);
177 self.regs.write32(SYS_CFGCTRL, cmd);
178 crate::mmio::memory_barrier();
179
180 for _ in 0..MAX_POLL_TRIES {
181 let status = self.regs.read32(SYS_CFGSTAT);
182 if status & SYS_CFGSTAT_ERR != 0 {
183 return Err(BusError::IoError);
184 }
185 if status & SYS_CFGSTAT_COMPLETE != 0 {
186 return Ok(self.regs.read32(SYS_CFGDATA));
187 }
188 }
189
190 Err(BusError::Timeout)
191 }
192
193 pub fn config_write(
195 &self,
196 site: u32,
197 position: u32,
198 dcc: u32,
199 function: u32,
200 device: u32,
201 data: u32,
202 ) -> Result<(), BusError> {
203 self.ensure_dcc_ready()?;
204
205 let command = self.regs.read32(SYS_CFGCTRL);
206 if command & SYS_CFGCTRL_START != 0 {
207 return Err(BusError::Timeout);
208 }
209
210 let real_site = if site == SITE_MASTER {
211 self.master_site
212 } else {
213 site
214 };
215
216 let cmd = SYS_CFGCTRL_START
217 | SYS_CFGCTRL_WRITE
218 | cfg_ctrl_dcc(dcc)
219 | cfg_ctrl_site(real_site)
220 | cfg_ctrl_position(position)
221 | cfg_ctrl_func(function)
222 | cfg_ctrl_device(device);
223
224 self.regs.write32(SYS_CFGDATA, data);
225 self.regs.write32(SYS_CFGSTAT, 0);
226 self.regs.write32(SYS_CFGCTRL, cmd);
227 crate::mmio::memory_barrier();
228
229 for _ in 0..MAX_POLL_TRIES {
230 let status = self.regs.read32(SYS_CFGSTAT);
231 if status & SYS_CFGSTAT_ERR != 0 {
232 return Err(BusError::IoError);
233 }
234 if status & SYS_CFGSTAT_COMPLETE != 0 {
235 return Ok(());
236 }
237 }
238
239 Err(BusError::Timeout)
240 }
241}
242
243impl BusDriver for VexpressConfig {
244 fn name(&self) -> &str {
246 "vexpress-config"
247 }
248
249 fn compatible(&self) -> &[&str] {
251 COMPATIBLE
252 }
253
254 fn init(&mut self, base: usize) -> Result<(), BusError> {
256 self.regs.init(base, 0x100);
257 self.detect_master_site();
258 self.power_state = PowerState::On;
259 Ok(())
260 }
261
262 fn shutdown(&mut self) -> Result<(), BusError> {
264 self.power_state = PowerState::Off;
265 Ok(())
266 }
267
268 fn read_reg(&self, offset: usize) -> Result<u32, BusError> {
270 if !self.regs.is_valid() {
271 return Err(BusError::InitFailed);
272 }
273 self.regs.check_user_offset(offset)?;
274 Ok(self.regs.read32(offset))
275 }
276
277 fn write_reg(&mut self, offset: usize, value: u32) -> Result<(), BusError> {
279 if !self.regs.is_valid() {
280 return Err(BusError::InitFailed);
281 }
282 self.regs.check_user_offset(offset)?;
283 self.regs.write32(offset, value);
284 Ok(())
285 }
286}