1#![allow(dead_code)]
4
5const SDIO_BASE: usize = 0x3F340000;
8
9const SDHCI_DMA_ADDRESS: *mut u32 = SDIO_BASE as *mut u32;
11const SDHCI_BLOCK_SIZE: *mut u16 = (SDIO_BASE + 0x04) as *mut u16;
12const SDHCI_BLOCK_COUNT: *mut u16 = (SDIO_BASE + 0x06) as *mut u16;
13const SDHCI_ARGUMENT: *mut u32 = (SDIO_BASE + 0x08) as *mut u32;
14const SDHCI_TRANSFER_MODE: *mut u16 = (SDIO_BASE + 0x0C) as *mut u16;
15const SDHCI_COMMAND: *mut u16 = (SDIO_BASE + 0x0E) as *mut u16;
16const SDHCI_RESPONSE: *mut u32 = (SDIO_BASE + 0x10) as *mut u32; const SDHCI_BUFFER: *mut u32 = (SDIO_BASE + 0x20) as *mut u32;
18const SDHCI_PRESENT_STATE: *mut u32 = (SDIO_BASE + 0x24) as *mut u32;
19const SDHCI_HOST_CONTROL: *mut u8 = (SDIO_BASE + 0x28) as *mut u8;
20const SDHCI_POWER_CONTROL: *mut u8 = (SDIO_BASE + 0x29) as *mut u8;
21const SDHCI_BLOCK_GAP_CONTROL: *mut u8 = (SDIO_BASE + 0x2A) as *mut u8;
22const SDHCI_CLOCK_CONTROL: *mut u16 = (SDIO_BASE + 0x2C) as *mut u16;
23const SDHCI_TIMEOUT_CONTROL: *mut u8 = (SDIO_BASE + 0x2E) as *mut u8;
24const SDHCI_SOFTWARE_RESET: *mut u8 = (SDIO_BASE + 0x2F) as *mut u8;
25const SDHCI_INT_STATUS: *mut u32 = (SDIO_BASE + 0x30) as *mut u32;
26const SDHCI_INT_ENABLE: *mut u32 = (SDIO_BASE + 0x34) as *mut u32;
27const SDHCI_SIGNAL_ENABLE: *mut u32 = (SDIO_BASE + 0x38) as *mut u32;
28const SDHCI_CAPABILITIES: *mut u32 = (SDIO_BASE + 0x40) as *mut u32;
29const SDHCI_HOST_VERSION: *mut u16 = (SDIO_BASE + 0xFE) as *mut u16;
30
31const SDHCI_CMD_INHIBIT: u32 = 1 << 0;
33const SDHCI_DATA_INHIBIT: u32 = 1 << 1;
34
35const SDHCI_INT_RESPONSE: u32 = 1 << 0;
37const SDHCI_INT_DATA_END: u32 = 1 << 1;
38const SDHCI_INT_ERROR: u32 = 1 << 15;
39
40const SDHCI_CMD_RESP_MASK: u16 = 0x03;
42const SDHCI_CMD_CRC: u16 = 0x08;
43const SDHCI_CMD_INDEX: u16 = 0x10;
44const SDHCI_CMD_DATA: u16 = 0x20;
45const SDHCI_CMD_RESP_SHORT: u16 = 0x02; const SDHCI_CMD_RESP_LONG: u16 = 0x01; pub const SDIO_FUNC_BUS: u8 = 0;
50pub const SDIO_FUNC_BACKPLANE: u8 = 1;
51pub const SDIO_FUNC_WLAN: u8 = 2;
52
53const CYW43_BACKPLANE_FUNC: u8 = 1;
55const CYW43_WLAN_FUNC: u8 = 2;
56
57const CCCR_SDIO_REVISION: u32 = 0x00;
59const CCCR_CCCR_REVISION: u32 = 0x00;
60const CCCR_IO_ENABLE: u32 = 0x02;
61const CCCR_IO_READY: u32 = 0x03;
62const CCCR_INT_ENABLE: u32 = 0x04;
63const CCCR_BUS_CONTROL: u32 = 0x07;
64const CCCR_CARD_CAPABILITY: u32 = 0x08;
65const CCCR_BUS_WIDTH: u32 = 0x07;
66
67static mut SDIO_INITIALIZED: bool = false;
68
69fn delay_us(us: u32) {
70 for _ in 0..(us * 10) {
71 unsafe { core::arch::asm!("nop") };
72 }
73}
74
75fn delay_ms(ms: u32) {
76 delay_us(ms * 1000);
77}
78
79unsafe fn wait_inhibit(data: bool) -> bool {
80 let mask = if data {
81 SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT
82 } else {
83 SDHCI_CMD_INHIBIT
84 };
85 let mut timeout = 100_000;
86 while (core::ptr::read_volatile(SDHCI_PRESENT_STATE) & mask) != 0 {
87 timeout -= 1;
88 if timeout == 0 {
89 return false;
90 }
91 }
92 true
93}
94
95unsafe fn wait_int(mask: u32) -> bool {
96 let mut timeout = 1_000_000;
97 loop {
98 let ints = core::ptr::read_volatile(SDHCI_INT_STATUS);
99 if (ints & SDHCI_INT_ERROR) != 0 {
100 core::ptr::write_volatile(SDHCI_INT_STATUS, ints);
101 return false;
102 }
103 if (ints & mask) != 0 {
104 core::ptr::write_volatile(SDHCI_INT_STATUS, ints & mask);
105 return true;
106 }
107 timeout -= 1;
108 if timeout == 0 {
109 return false;
110 }
111 }
112}
113
114pub unsafe fn cmd52(fn_num: u8, write: bool, addr: u32, data: u8) -> Option<u8> {
122 if !wait_inhibit(false) {
123 return None;
124 }
125
126 let arg = (((write as u32) << 31)
128 | ((fn_num as u32 & 0x7) << 28)) | ((addr & 0x1FFFF) << 9)
130 | (data as u32);
131
132 core::ptr::write_volatile(SDHCI_ARGUMENT, arg);
133 let cmd = (52 << 8) | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_CRC | SDHCI_CMD_INDEX;
135 core::ptr::write_volatile(SDHCI_COMMAND, cmd);
136
137 if !wait_int(SDHCI_INT_RESPONSE) {
138 return None;
139 }
140 let resp = core::ptr::read_volatile(SDHCI_RESPONSE);
141 Some((resp & 0xFF) as u8)
143}
144
145pub unsafe fn cmd53(fn_num: u8, write: bool, addr: u32, buf: &mut [u8]) -> bool {
152 let len = buf.len();
153 if len == 0 || len > 512 {
154 return false;
155 }
156 if !wait_inhibit(true) {
157 return false;
158 }
159
160 let addr_inc = fn_num != SDIO_FUNC_WLAN;
163 let arg = (((write as u32) << 31)
164 | ((fn_num as u32 & 0x7) << 28)
165 | ((addr_inc as u32) << 26)) | ((addr & 0x1FFFF) << 9)
167 | (len as u32 & 0x1FF);
168
169 core::ptr::write_volatile(SDHCI_BLOCK_SIZE, len as u16);
170 core::ptr::write_volatile(SDHCI_BLOCK_COUNT, 1);
171 core::ptr::write_volatile(SDHCI_ARGUMENT, arg);
172
173 let xfer_mode: u16 = if write { 0x00 } else { 0x10 }; core::ptr::write_volatile(SDHCI_TRANSFER_MODE, xfer_mode);
175
176 let cmd = (53 << 8) | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_CRC | SDHCI_CMD_INDEX | SDHCI_CMD_DATA;
177 core::ptr::write_volatile(SDHCI_COMMAND, cmd);
178
179 if !wait_int(SDHCI_INT_RESPONSE) {
180 return false;
181 }
182
183 if write {
184 let mut i = 0;
186 while i < len {
187 let mut word: u32 = 0;
188 for j in 0..4usize {
189 if i + j < len {
190 word |= (buf[i + j] as u32) << (j * 8);
191 }
192 }
193 core::ptr::write_volatile(SDHCI_BUFFER, word);
194 i += 4;
195 }
196 }
197
198 if !wait_int(SDHCI_INT_DATA_END) {
199 return false;
200 }
201
202 if !write {
203 let mut i = 0;
205 while i < len {
206 let word = core::ptr::read_volatile(SDHCI_BUFFER);
207 for j in 0..4usize {
208 if i + j < len {
209 buf[i + j] = ((word >> (j * 8)) & 0xFF) as u8;
210 }
211 }
212 i += 4;
213 }
214 }
215
216 true
217}
218
219unsafe fn set_clock(khz: u32) {
221 let base_khz = 250_000u32;
223 let divisor = base_khz.div_ceil(khz).next_power_of_two().max(2);
224 let div8 = (divisor >> 1) as u16;
225
226 core::ptr::write_volatile(SDHCI_CLOCK_CONTROL, 0);
228 delay_ms(1);
229
230 let clk_ctrl = (div8 << 8) | 0x01; core::ptr::write_volatile(SDHCI_CLOCK_CONTROL, clk_ctrl);
233
234 let mut timeout = 10000;
236 while (core::ptr::read_volatile(SDHCI_CLOCK_CONTROL) & 0x02) == 0 {
237 timeout -= 1;
238 if timeout == 0 {
239 break;
240 }
241 }
242
243 let clk_ctrl = core::ptr::read_volatile(SDHCI_CLOCK_CONTROL) | 0x04;
245 core::ptr::write_volatile(SDHCI_CLOCK_CONTROL, clk_ctrl);
246 delay_ms(1);
247}
248
249pub fn init() -> bool {
251 unsafe {
252 crate::debug!("[FS] SDIO: Initializing Arasan eMMC2 controller...");
253
254 core::ptr::write_volatile(SDHCI_SOFTWARE_RESET, 0x07);
256 let mut timeout = 100_000;
257 while (core::ptr::read_volatile(SDHCI_SOFTWARE_RESET) & 0x07) != 0 {
258 timeout -= 1;
259 if timeout == 0 {
260 crate::debug!("[FS] SDIO: Reset timeout");
261 return false;
262 }
263 }
264 delay_ms(10);
265
266 core::ptr::write_volatile(SDHCI_POWER_CONTROL, 0x0F); delay_ms(10);
269
270 core::ptr::write_volatile(SDHCI_INT_ENABLE, 0x00FF_00FF);
272 core::ptr::write_volatile(SDHCI_SIGNAL_ENABLE, 0);
273
274 core::ptr::write_volatile(SDHCI_TIMEOUT_CONTROL, 0x0E);
276
277 set_clock(400);
279 delay_ms(5);
280
281 core::ptr::write_volatile(SDHCI_INT_STATUS, 0xFFFF_FFFF);
283 core::ptr::write_volatile(SDHCI_ARGUMENT, 0);
284 core::ptr::write_volatile(SDHCI_COMMAND, 0); delay_ms(2);
286
287 core::ptr::write_volatile(SDHCI_INT_STATUS, 0xFFFF_FFFF);
289 core::ptr::write_volatile(SDHCI_ARGUMENT, 0);
290 core::ptr::write_volatile(SDHCI_COMMAND, (5 << 8) | SDHCI_CMD_RESP_SHORT);
291 if !wait_int(SDHCI_INT_RESPONSE) {
292 crate::debug!("[FS] SDIO: CMD5 failed (no SDIO device?)");
293 return false;
294 }
295 let r4 = core::ptr::read_volatile(SDHCI_RESPONSE);
296 let num_functions = (r4 >> 28) & 0x7;
297 crate::debug!("[FS] SDIO: CMD5 R4=0x{:08X}, {} function(s)", r4, num_functions);
298
299 let ocr = r4 & 0x00FF_FF00;
301 core::ptr::write_volatile(SDHCI_INT_STATUS, 0xFFFF_FFFF);
302 core::ptr::write_volatile(SDHCI_ARGUMENT, ocr);
303 core::ptr::write_volatile(SDHCI_COMMAND, (5 << 8) | SDHCI_CMD_RESP_SHORT);
304 if !wait_int(SDHCI_INT_RESPONSE) {
305 crate::debug!("[FS] SDIO: CMD5 (OCR) failed");
306 return false;
307 }
308 let r4 = core::ptr::read_volatile(SDHCI_RESPONSE);
309 if (r4 & 0x8000_0000) == 0 {
310 crate::debug!("[FS] SDIO: Card not ready (OCR=0x{:08X})", r4);
311 return false;
312 }
313
314 core::ptr::write_volatile(SDHCI_INT_STATUS, 0xFFFF_FFFF);
316 core::ptr::write_volatile(SDHCI_ARGUMENT, 0);
317 core::ptr::write_volatile(
318 SDHCI_COMMAND,
319 (3 << 8) | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_CRC | SDHCI_CMD_INDEX,
320 );
321 if !wait_int(SDHCI_INT_RESPONSE) {
322 crate::debug!("[FS] SDIO: CMD3 failed");
323 return false;
324 }
325 let rca = (core::ptr::read_volatile(SDHCI_RESPONSE) >> 16) as u16;
326 crate::debug!("[FS] SDIO: RCA=0x{:04X}", rca);
327
328 core::ptr::write_volatile(SDHCI_INT_STATUS, 0xFFFF_FFFF);
330 core::ptr::write_volatile(SDHCI_ARGUMENT, (rca as u32) << 16);
331 core::ptr::write_volatile(
332 SDHCI_COMMAND,
333 (7 << 8) | SDHCI_CMD_RESP_SHORT | SDHCI_CMD_CRC | SDHCI_CMD_INDEX,
334 );
335 if !wait_int(SDHCI_INT_RESPONSE) {
336 crate::debug!("[FS] SDIO: CMD7 failed");
337 return false;
338 }
339
340 set_clock(25_000);
342 delay_ms(5);
343
344 cmd52(SDIO_FUNC_BUS, true, CCCR_BUS_WIDTH, 0x02);
346
347 let hc = core::ptr::read_volatile(SDHCI_HOST_CONTROL);
349 core::ptr::write_volatile(SDHCI_HOST_CONTROL, hc | 0x02);
350 delay_ms(2);
351
352 cmd52(SDIO_FUNC_BUS, true, CCCR_IO_ENABLE, 0x06); delay_ms(20);
355
356 let ready = match cmd52(SDIO_FUNC_BUS, false, CCCR_IO_READY, 0) {
357 Some(v) => v,
358 None => {
359 crate::debug!("[FS] SDIO: IO_READY read failed");
360 return false;
361 }
362 };
363 crate::debug!("[FS] SDIO: IO_READY=0x{:02X}", ready);
364 if (ready & 0x06) != 0x06 {
365 crate::debug!("[FS] SDIO: Functions not ready");
366 return false;
367 }
368
369 SDIO_INITIALIZED = true;
370 crate::debug!("[FS] SDIO: Controller initialized successfully.");
371 true
372 }
373}
374
375pub fn is_initialized() -> bool {
376 unsafe { SDIO_INITIALIZED }
377}