1#![allow(dead_code)]
3#![allow(static_mut_refs)]
4
5use core::sync::atomic::{AtomicBool, Ordering};
6
7const GPIO_BASE: usize = 0x3F20_0000;
9const GPFSEL4: *mut u32 = (GPIO_BASE + 0x10) as *mut u32;
10const GPFSEL5: *mut u32 = (GPIO_BASE + 0x14) as *mut u32;
11const GPPUD: *mut u32 = (GPIO_BASE + 0x94) as *mut u32;
12const GPPUDCLK1: *mut u32 = (GPIO_BASE + 0x9C) as *mut u32;
13
14const SDHOST_BASE: usize = 0x3F20_2000;
16
17const SDCMD: *mut u32 = SDHOST_BASE as *mut u32;
18const SDARG: *mut u32 = (SDHOST_BASE + 0x04) as *mut u32;
19const SDTOUT: *mut u32 = (SDHOST_BASE + 0x08) as *mut u32;
20const SDCDIV: *mut u32 = (SDHOST_BASE + 0x0C) as *mut u32;
21const SDRSP0: *mut u32 = (SDHOST_BASE + 0x10) as *mut u32;
22const SDRSP1: *mut u32 = (SDHOST_BASE + 0x14) as *mut u32;
23const SDRSP2: *mut u32 = (SDHOST_BASE + 0x18) as *mut u32;
24const SDRSP3: *mut u32 = (SDHOST_BASE + 0x1C) as *mut u32;
25const SDHSTS: *mut u32 = (SDHOST_BASE + 0x20) as *mut u32;
26const SDVDD: *mut u32 = (SDHOST_BASE + 0x30) as *mut u32;
27const SDEDM: *mut u32 = (SDHOST_BASE + 0x34) as *mut u32;
28const SDHCFG: *mut u32 = (SDHOST_BASE + 0x38) as *mut u32;
29const SDHBCT: *mut u32 = (SDHOST_BASE + 0x3C) as *mut u32;
31const SDDATA: *mut u32 = (SDHOST_BASE + 0x40) as *mut u32;
32const SDHBLC: *mut u32 = (SDHOST_BASE + 0x50) as *mut u32;
40
41const SDCMD_NEW_CMD: u32 = 0x8000;
60const SDCMD_FAIL_ERROR: u32 = 0x4000;
61const SDCMD_BUSYWAIT: u32 = 0x0800;
62const SDCMD_NO_RESPONSE: u32 = 0x0400;
63const SDCMD_LONG_RESPONSE: u32 = 0x0200;
64const SDCMD_WRITE: u32 = 0x0080;
68const SDCMD_READ: u32 = 0x0040;
70
71const SDCMD_RESP_NONE: u32 = SDCMD_NO_RESPONSE;
73const SDCMD_RESP_48: u32 = 0x0000;
74const SDCMD_RESP_136: u32 = SDCMD_LONG_RESPONSE;
75
76const SDHCFG_REL_CMD_LINE: u32 = 0x0001;
78const SDHCFG_WIDE_INT_BUS: u32 = 0x0002;
80const SDHCFG_WIDE_EXT_BUS: u32 = 0x0004;
83const SDHCFG_SLOW_CARD: u32 = 0x0008;
84const SDHCFG_DATA_IRPT_EN: u32 = 0x0010;
85
86const SDEDM_WRITE_THRESHOLD_SHIFT: u32 = 9;
88const SDEDM_READ_THRESHOLD_SHIFT: u32 = 14;
89const SDEDM_THRESHOLD_MASK: u32 = 0x1F;
90const FIFO_READ_THRESHOLD: u32 = 4;
91const FIFO_WRITE_THRESHOLD: u32 = 4;
92
93const SDHSTS_FIFO_ERROR: u32 = 0x0001;
106const SDHSTS_CRC7_ERROR: u32 = 0x0002;
107const SDHSTS_CRC16_ERROR: u32 = 0x0004;
108const SDHSTS_CMD_TIME_OUT: u32 = 0x0008;
109const SDHSTS_REW_TIME_OUT: u32 = 0x0010;
110const SDHSTS_DATA_FLAG: u32 = 0x0100;
112const SDHSTS_BLOCK_IRPT: u32 = 0x0200;
113const SDHSTS_BUSY: u32 = 0x0400;
114const SDHSTS_ERROR: u32 = SDHSTS_FIFO_ERROR
116 | SDHSTS_CRC7_ERROR
117 | SDHSTS_CRC16_ERROR
118 | SDHSTS_CMD_TIME_OUT
119 | SDHSTS_REW_TIME_OUT;
120
121static SD_INITIALIZED: AtomicBool = AtomicBool::new(false);
123static mut RCA: u32 = 0;
124static mut CARD_SECTORS: usize = 0;
125
126fn delay_us(us: u32) {
128 let start = crate::kernel::timer::get_system_time_us();
129 while crate::kernel::timer::get_system_time_us() - start < us as u64 {
130 core::hint::spin_loop();
131 }
132}
133
134fn setup_gpio() {
136 unsafe {
137 let mut fsel4 = core::ptr::read_volatile(GPFSEL4);
140 fsel4 &= !(0b111 << 24); fsel4 |= 0b100 << 24; fsel4 &= !(0b111 << 27); fsel4 |= 0b100 << 27; core::ptr::write_volatile(GPFSEL4, fsel4);
145
146 let mut fsel5 = core::ptr::read_volatile(GPFSEL5);
149 for pin in 50..=53 {
150 let shift = (pin - 50) * 3;
151 fsel5 &= !(0b111 << shift);
152 fsel5 |= 0b100 << shift;
153 }
154 core::ptr::write_volatile(GPFSEL5, fsel5);
155
156 core::ptr::write_volatile(GPPUD, 2); delay_us(10);
159 core::ptr::write_volatile(GPPUDCLK1, (1 << (48 - 32)) | (1 << (49 - 32)) | (1 << (50 - 32)) | (1 << (51 - 32)) | (1 << (53 - 32)));
160 delay_us(10);
161 core::ptr::write_volatile(GPPUD, 0);
162 core::ptr::write_volatile(GPPUDCLK1, 0);
163
164 core::ptr::write_volatile(GPPUD, 1); delay_us(10);
166 core::ptr::write_volatile(GPPUDCLK1, 1 << (52 - 32)); delay_us(10);
168 core::ptr::write_volatile(GPPUD, 0);
169 core::ptr::write_volatile(GPPUDCLK1, 0);
170 }
171}
172
173fn send_command(cmd_idx: u32, arg: u32, resp_type: u32) -> Result<[u32; 4], &'static str> {
175 unsafe {
176 let mut timeout = 100000;
178 while (core::ptr::read_volatile(SDCMD) & SDCMD_NEW_CMD) != 0 {
179 timeout -= 1;
180 if timeout == 0 {
181 return Err("SDHOST: send_command previous timeout");
182 }
183 core::hint::spin_loop();
184 }
185
186 core::ptr::write_volatile(SDARG, arg);
188
189 let cmd = (cmd_idx & 0x3F) | resp_type | SDCMD_NEW_CMD;
191 core::ptr::write_volatile(SDCMD, cmd);
192
193 timeout = 100000;
195 while (core::ptr::read_volatile(SDCMD) & SDCMD_NEW_CMD) != 0 {
196 timeout -= 1;
197 if timeout == 0 {
198 return Err("SDHOST: command execution timeout");
199 }
200 core::hint::spin_loop();
201 }
202
203 let cmd_status = core::ptr::read_volatile(SDCMD);
204 if (cmd_status & SDCMD_FAIL_ERROR) != 0 {
205 return Err("SDHOST: command execution failed");
206 }
207
208 let mut resp = [0u32; 4];
210 resp[0] = core::ptr::read_volatile(SDRSP0);
211 if resp_type == SDCMD_RESP_136 {
212 resp[1] = core::ptr::read_volatile(SDRSP1);
213 resp[2] = core::ptr::read_volatile(SDRSP2);
214 resp[3] = core::ptr::read_volatile(SDRSP3);
215 }
216
217 Ok(resp)
218 }
219}
220
221fn set_clock(hz: u32) {
223 unsafe {
224 let host_clk = 250_000_000;
226 let mut div = host_clk / hz;
227 if div < 2 {
228 div = 2;
229 }
230 let cdiv = if div >= 2 { (div / 2) - 1 } else { 0 };
232 core::ptr::write_volatile(SDCDIV, cdiv & 0x7FF);
233 delay_us(100);
234 }
235}
236
237pub fn init() -> Result<(), &'static str> {
239 if SD_INITIALIZED.load(Ordering::SeqCst) {
240 return Ok(());
241 }
242
243 crate::info!("[SD] Initializing BCM2835 SDHOST controller...");
244
245 setup_gpio();
246
247 unsafe {
248 core::ptr::write_volatile(SDVDD, 1); core::ptr::write_volatile(SDTOUT, 0xF00000); core::ptr::write_volatile(SDHSTS, 0x7F); core::ptr::write_volatile(SDHCFG, 0); }
254
255 set_clock(400_000);
257
258 delay_us(10000);
260
261 let _ = send_command(0, 0, SDCMD_RESP_NONE);
263 delay_us(5000);
264
265 let has_hc = match send_command(8, 0x1AA, SDCMD_RESP_48) {
267 Ok(resp) => (resp[0] & 0xFF) == 0xAA,
268 Err(_) => false,
269 };
270
271 let mut ocr = 0x0010_0000; if has_hc {
274 ocr |= 0x4000_0000; }
276
277 let mut ready = false;
278 for _ in 0..100 {
279 if send_command(55, 0, SDCMD_RESP_48).is_err() {
281 continue;
282 }
283 if let Ok(resp) = send_command(41, ocr, SDCMD_RESP_48) {
284 if (resp[0] & 0x8000_0000) != 0 {
285 ready = true;
286 ocr = resp[0];
287 break;
288 }
289 }
290 delay_us(10000);
291 }
292
293 if !ready {
294 return Err("SDHOST: Card initialization failed (ACMD41 timeout)");
295 }
296
297 let is_sdhc = (ocr & 0x4000_0000) != 0;
298 crate::info!("[SD] Card detected: SDHC={}", is_sdhc);
299
300 let _cid = send_command(2, 0, SDCMD_RESP_136)?;
302
303 let resp3 = send_command(3, 0, SDCMD_RESP_48)?;
305 let rca = resp3[0] & 0xFFFF_0000;
306 unsafe {
307 RCA = rca;
308 }
309
310 let csd = send_command(9, rca, SDCMD_RESP_136)?;
312 parse_csd(csd)?;
313
314 let _ = send_command(7, rca, SDCMD_RESP_48)?;
316
317 let _ = send_command(16, 512, SDCMD_RESP_48)?;
319
320 let _ = send_command(55, rca, SDCMD_RESP_48)?;
322 let _ = send_command(6, 2, SDCMD_RESP_48)?; set_clock(25_000_000);
326
327 unsafe {
346 core::ptr::write_volatile(SDHCFG, SDHCFG_WIDE_INT_BUS | SDHCFG_WIDE_EXT_BUS);
347
348 let mut edm = core::ptr::read_volatile(SDEDM);
355 edm &= !((SDEDM_THRESHOLD_MASK << SDEDM_READ_THRESHOLD_SHIFT)
356 | (SDEDM_THRESHOLD_MASK << SDEDM_WRITE_THRESHOLD_SHIFT));
357 edm |= (FIFO_READ_THRESHOLD << SDEDM_READ_THRESHOLD_SHIFT)
358 | (FIFO_WRITE_THRESHOLD << SDEDM_WRITE_THRESHOLD_SHIFT);
359 core::ptr::write_volatile(SDEDM, edm);
360 }
361
362 SD_INITIALIZED.store(true, Ordering::SeqCst);
363 unsafe {
364 crate::info!("[SD] SDCard initialization success. Capacity: {} sectors ({} MiB)", CARD_SECTORS, (CARD_SECTORS * 512) / (1024 * 1024));
365 }
366
367 Ok(())
368}
369
370fn parse_csd(csd: [u32; 4]) -> Result<(), &'static str> {
372 let csd_structure = (csd[0] >> 30) & 0x3;
380
381 if csd_structure == 1 {
382 let c_size_upper = csd[1] & 0x3F;
388 let c_size_lower = csd[2] >> 16;
389 let c_size = (c_size_upper << 16) | c_size_lower;
390
391 let capacity_kb = (c_size + 1) * 512;
393 let sectors = (capacity_kb * 1024) / 512;
394 unsafe {
395 CARD_SECTORS = sectors as usize;
396 }
397 } else {
398 let c_size = ((csd[1] & 0x3FF) << 2) | ((csd[2] >> 30) & 0x3);
401 let c_size_mult = (csd[2] >> 15) & 0x7;
402 let read_bl_len = csd[1] & 0xF;
403
404 let mult = 1 << (c_size_mult + 2);
405 let block_len = 1 << read_bl_len;
406 let capacity_bytes = (c_size + 1) * mult * block_len;
407 unsafe {
408 CARD_SECTORS = (capacity_bytes / 512) as usize;
409 }
410 }
411
412 Ok(())
413}
414
415pub fn get_total_sectors() -> usize {
417 unsafe { CARD_SECTORS }
418}
419
420pub fn read_sector(lba: usize, buf: &mut [u8]) -> Result<(), &'static str> {
422 if !SD_INITIALIZED.load(Ordering::SeqCst) {
423 return Err("SDHOST: not initialized");
424 }
425 if buf.len() < 512 {
426 return Err("SDHOST: read buffer too small");
427 }
428
429 unsafe {
430 core::ptr::write_volatile(SDHBCT, 512);
433 core::ptr::write_volatile(SDHBLC, 1);
434
435 let arg = lba as u32;
438 send_command(17, arg, SDCMD_RESP_48 | SDCMD_READ)?;
441
442 let mut words_read = 0;
444 let mut timeout = 500000;
445 let buf_u32 = buf.as_mut_ptr() as *mut u32;
446
447 while words_read < 128 {
448 let hsts = core::ptr::read_volatile(SDHSTS);
449 if (hsts & SDHSTS_DATA_FLAG) != 0 {
450 let data = core::ptr::read_volatile(SDDATA);
451 core::ptr::write_volatile(buf_u32.add(words_read), data);
452 words_read += 1;
453 } else if (hsts & SDHSTS_FIFO_ERROR) != 0 {
454 return Err("SDHOST: FIFO error during read");
455 } else {
456 timeout -= 1;
457 if timeout == 0 {
458 return Err("SDHOST: read timeout waiting for FIFO data");
459 }
460 core::hint::spin_loop();
461 }
462 }
463
464 timeout = 100000;
466 while (core::ptr::read_volatile(SDHSTS) & SDHSTS_BUSY) != 0 {
467 timeout -= 1;
468 if timeout == 0 {
469 return Err("SDHOST: read busy timeout");
470 }
471 core::hint::spin_loop();
472 }
473
474 let hsts = core::ptr::read_volatile(SDHSTS);
476 if (hsts & SDHSTS_ERROR) != 0 {
477 core::ptr::write_volatile(SDHSTS, SDHSTS_ERROR); return Err("SDHOST: read error flag set in host status");
479 }
480 }
481
482 Ok(())
483}
484
485pub fn write_sector(lba: usize, buf: &[u8]) -> Result<(), &'static str> {
487 if !SD_INITIALIZED.load(Ordering::SeqCst) {
488 return Err("SDHOST: not initialized");
489 }
490 if buf.len() < 512 {
491 return Err("SDHOST: write buffer too small");
492 }
493
494 unsafe {
495 core::ptr::write_volatile(SDHBCT, 512);
497 core::ptr::write_volatile(SDHBLC, 1);
498
499 let arg = lba as u32;
501 send_command(24, arg, SDCMD_RESP_48 | SDCMD_WRITE)?;
502
503 let mut words_written = 0;
505 let mut timeout = 500000;
506 let buf_u32 = buf.as_ptr() as *const u32;
507
508 while words_written < 128 {
509 let hsts = core::ptr::read_volatile(SDHSTS);
510 if (hsts & SDHSTS_DATA_FLAG) != 0 {
511 let data = core::ptr::read_volatile(buf_u32.add(words_written));
512 core::ptr::write_volatile(SDDATA, data);
513 words_written += 1;
514 } else if (hsts & SDHSTS_FIFO_ERROR) != 0 {
515 return Err("SDHOST: FIFO error during write");
516 } else {
517 timeout -= 1;
518 if timeout == 0 {
519 return Err("SDHOST: write timeout waiting for FIFO space");
520 }
521 core::hint::spin_loop();
522 }
523 }
524
525 timeout = 100000;
527 while (core::ptr::read_volatile(SDHSTS) & SDHSTS_BUSY) != 0 {
528 timeout -= 1;
529 if timeout == 0 {
530 return Err("SDHOST: write busy timeout");
531 }
532 core::hint::spin_loop();
533 }
534
535 let hsts = core::ptr::read_volatile(SDHSTS);
537 if (hsts & SDHSTS_ERROR) != 0 {
538 core::ptr::write_volatile(SDHSTS, SDHSTS_ERROR); return Err("SDHOST: write error flag set in host status");
540 }
541 }
542
543 Ok(())
544}