1use crate::{Error, Result};
2use alloc::vec::Vec;
3use core::time::Duration;
4
5#[derive(Clone, Debug)]
6pub(crate) struct SFDPHeader {
7 pub nph: usize,
8 pub major: u8,
9 pub minor: u8,
10 pub params: Vec<SFDPParameterHeader>,
11}
12
13impl SFDPHeader {
14 pub fn from_bytes(data: &[u8]) -> Result<Self> {
15 log::debug!("Parsing SFDP header from data: {:X?}", data);
16 if &data[0..4] != b"SFDP" {
17 log::error!("Did not read expected SFDP signature");
18 Err(Error::InvalidSFDPHeader)
19 } else if data[7] != 0xFF {
20 log::error!("Unsupported SFDP access protocol {:02X}", data[7]);
21 Err(Error::InvalidSFDPHeader)
22 } else {
23 let minor = data[4];
24 let major = data[5];
25 let nph = data[6] as usize + 1;
26 log::debug!(
27 "Read SFDP header, NPH={} MAJOR={} MINOR={}",
28 nph,
29 major,
30 minor
31 );
32 if data.len() < (nph + 1) * 8 {
33 log::error!(
34 "Did not read enough SFDP bytes: got {}, needed {}",
35 data.len(),
36 (nph + 1) * 8
37 );
38 Err(Error::InvalidSFDPHeader)
39 } else {
40 let params = data[8..]
41 .chunks(8)
42 .map(SFDPParameterHeader::from_bytes)
43 .collect();
44 Ok(SFDPHeader {
45 nph,
46 major,
47 minor,
48 params,
49 })
50 }
51 }
52 }
53}
54
55#[derive(Copy, Clone, Debug)]
56pub(crate) struct SFDPParameterHeader {
57 pub plen: usize,
58 pub major: u8,
59 pub minor: u8,
60 pub parameter_id: u16,
61 pub ptp: u32,
62}
63
64impl SFDPParameterHeader {
65 fn from_bytes(data: &[u8]) -> Self {
66 log::debug!("Reading SFDP parameter header from: {:X?}", data);
67 let parameter_id = u16::from_be_bytes([data[7], data[0]]);
68 let minor = data[1];
69 let major = data[2];
70 let plen = data[3] as usize;
71 let ptp = u32::from_be_bytes([0, data[6], data[5], data[4]]);
72 log::debug!(
73 "Read JEDEC parameter header, plen={} major={} minor={} \
74 ID=0x{:04X} PTP=0x{:06X}",
75 plen,
76 major,
77 minor,
78 parameter_id,
79 ptp
80 );
81 SFDPParameterHeader {
82 plen,
83 major,
84 minor,
85 parameter_id,
86 ptp,
87 }
88 }
89}
90
91#[derive(Copy, Clone, Debug)]
99pub struct FlashParams {
100 pub version_major: u8,
102 pub version_minor: u8,
104
105 pub address_bytes: SFDPAddressBytes,
107 pub density: u64,
109
110 pub legacy_4kb_erase_supported: bool,
113 pub legacy_4kb_erase_inst: u8,
116 pub legacy_volatile_write_en_inst: u8,
119 pub legacy_block_protect_volatile: bool,
124 pub legacy_byte_write_granularity: bool,
127
128 pub erase_insts: [Option<SFDPEraseInst>; 4],
134
135 pub timing: Option<SFDPTiming>,
137
138 pub page_size: Option<u32>,
140
141 pub busy_poll_flag: Option<bool>,
147 pub busy_poll_status: Option<bool>,
150
151 pub reset_inst_f0: Option<bool>,
154 pub reset_inst_66_99: Option<bool>,
156
157 pub status_1_vol: Option<SFDPStatus1Volatility>,
159}
160
161#[derive(Copy, Clone, Debug)]
163pub enum SFDPAddressBytes {
164 Three,
166 ThreeOrFour,
169 Four,
171 Reserved,
173}
174
175impl SFDPAddressBytes {
176 fn from_bits(bits: u32) -> Self {
177 match bits {
178 0b00 => SFDPAddressBytes::Three,
179 0b01 => SFDPAddressBytes::ThreeOrFour,
180 0b10 => SFDPAddressBytes::Four,
181 _ => SFDPAddressBytes::Reserved,
182 }
183 }
184}
185
186#[derive(Copy, Clone, Debug)]
188pub struct SFDPEraseInst {
189 pub opcode: u8,
191 pub size: u32,
193 pub time_typ: Option<Duration>,
195 pub time_max: Option<Duration>,
197}
198
199impl core::fmt::Display for SFDPEraseInst {
200 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
201 write!(f, "Opcode 0x{:02X}: {} bytes", self.opcode, self.size)?;
202 if let Some(typ) = self.time_typ {
203 write!(f, ", typ {:?}", typ)?;
204 }
205 if let Some(max) = self.time_max {
206 write!(f, ", max {:?}", max)?;
207 }
208 Ok(())
209 }
210}
211
212#[derive(Copy, Clone, Debug)]
213pub enum SFDPStatus1Volatility {
214 NonVolatile06,
216 Volatile06,
218 Volatile50,
220 NonVolatile06Volatile50,
224 Mixed06,
227 Reserved,
229}
230
231impl SFDPStatus1Volatility {
232 pub fn from_bits(bits: u32) -> Self {
233 if bits & 0b000_0001 != 0 {
234 SFDPStatus1Volatility::NonVolatile06
235 } else if bits & 0b000_0010 != 0 {
236 SFDPStatus1Volatility::Volatile06
237 } else if bits & 0b000_0100 != 0 {
238 SFDPStatus1Volatility::Volatile50
239 } else if bits & 0b000_1000 != 0 {
240 SFDPStatus1Volatility::NonVolatile06Volatile50
241 } else if bits & 0b001_0000 != 0 {
242 SFDPStatus1Volatility::Mixed06
243 } else {
244 SFDPStatus1Volatility::Reserved
245 }
246 }
247}
248
249#[derive(Copy, Clone, Debug)]
253pub struct SFDPTiming {
254 pub chip_erase_time_typ: Duration,
256 pub chip_erase_time_max: Duration,
258 pub first_byte_prog_time_typ: Duration,
260 pub first_byte_prog_time_max: Duration,
262 pub succ_byte_prog_time_typ: Duration,
264 pub succ_byte_prog_time_max: Duration,
266 pub page_prog_time_typ: Duration,
268 pub page_prog_time_max: Duration,
270}
271
272macro_rules! bits {
276 ($d:expr, $n:expr, $o:expr) => {
277 ($d & (((1 << $n) - 1) << $o)) >> $o
278 };
279}
280
281impl FlashParams {
282 pub fn from_bytes(major: u8, minor: u8, data: &[u8]) -> Result<Self> {
283 log::debug!(
284 "Reading SFDP JEDEC Basic Flash Parameters from: {:X?}",
285 data
286 );
287
288 if data.len() % 4 != 0 {
290 log::error!("SFPD data is not a multiple of 4 bytes.");
291 return Err(Error::InvalidSFDPParams);
292 } else if data.len() < 9 * 4 {
293 log::error!("SFPD data is not long enough for version >= 1.0.");
294 return Err(Error::InvalidSFDPParams);
295 } else if major != 1 {
296 log::error!("Only SFPD major version 1 is supported.");
297 return Err(Error::InvalidSFDPParams);
298 } else if minor > 5 && data.len() < 16 * 4 {
299 log::error!("SFPD data is not long enough for version >= 1.5.");
300 return Err(Error::InvalidSFDPParams);
301 }
302
303 let mut dwords = Vec::new();
305 for bytes in data.chunks(4) {
306 dwords.push(u32::from_be_bytes([bytes[3], bytes[2], bytes[1], bytes[0]]));
307 }
308
309 let mut params = Self::read_jesd216(major, minor, &dwords);
311
312 if minor >= 5 {
314 params.read_jesd216a(&dwords);
315 }
316
317 Ok(params)
322 }
323
324 pub fn capacity_bytes(&self) -> usize {
326 (self.density / 8) as usize
327 }
328
329 pub fn sector_erase(&self) -> Option<(usize, u8)> {
331 let mut size = u32::MAX;
332 let mut opcode = 0u8;
333 for inst in self.erase_insts.iter().flatten() {
334 if inst.size < size {
335 size = inst.size;
336 opcode = inst.opcode;
337 }
338 }
339
340 if size != u32::MAX {
341 Some((size as usize, opcode))
342 } else {
343 None
344 }
345 }
346
347 fn read_jesd216(major: u8, minor: u8, dwords: &[u32]) -> FlashParams {
349 let address_bytes = SFDPAddressBytes::from_bits(bits!(dwords[0], 2, 17));
351 let legacy_4kb_erase_inst = bits!(dwords[0], 8, 8) as u8;
352 let legacy_volatile_write_en_inst = match bits!(dwords[0], 1, 4) {
353 0 => 0x50,
354 1 => 0x06,
355 _ => unreachable!(),
356 };
357 let legacy_block_protect_volatile = bits!(dwords[0], 1, 3) == 1;
358 let legacy_byte_write_granularity = bits!(dwords[0], 1, 2) == 1;
359 let legacy_4kb_erase_supported = bits!(dwords[0], 2, 0) == 0b01;
360
361 let density = if dwords[1] >> 31 == 0 {
363 (dwords[1] as u64) + 1
364 } else {
365 1u64 << (dwords[1] & 0x7FFF_FFFF)
366 };
367
368 let mut erase_insts = [None; 4];
372 let erase_size_1 = bits!(dwords[7], 8, 0);
373 let erase_size_2 = bits!(dwords[7], 8, 16);
374 let erase_size_3 = bits!(dwords[8], 8, 0);
375 let erase_size_4 = bits!(dwords[8], 8, 16);
376 if erase_size_1 != 0 {
377 let opcode = bits!(dwords[7], 8, 8) as u8;
378 if opcode != 0 {
379 erase_insts[0] = Some(SFDPEraseInst {
380 opcode,
381 size: 1 << erase_size_1,
382 time_typ: None,
383 time_max: None,
384 });
385 }
386 }
387 if erase_size_2 != 0 {
388 let opcode = bits!(dwords[7], 8, 24) as u8;
389 if opcode != 0 {
390 erase_insts[1] = Some(SFDPEraseInst {
391 opcode,
392 size: 1 << erase_size_2,
393 time_typ: None,
394 time_max: None,
395 });
396 }
397 }
398 if erase_size_3 != 0 {
399 let opcode = bits!(dwords[8], 8, 8) as u8;
400 if opcode != 0 {
401 erase_insts[2] = Some(SFDPEraseInst {
402 opcode,
403 size: 1 << erase_size_3,
404 time_typ: None,
405 time_max: None,
406 });
407 }
408 }
409 if erase_size_4 != 0 {
410 let opcode = bits!(dwords[8], 8, 24) as u8;
411 if opcode != 0 {
412 erase_insts[3] = Some(SFDPEraseInst {
413 opcode,
414 size: 1 << erase_size_4,
415 time_typ: None,
416 time_max: None,
417 });
418 }
419 }
420
421 FlashParams {
424 version_major: major,
425 version_minor: minor,
426 address_bytes,
427 density,
428 legacy_4kb_erase_supported,
429 legacy_4kb_erase_inst,
430 legacy_volatile_write_en_inst,
431 legacy_block_protect_volatile,
432 legacy_byte_write_granularity,
433 erase_insts,
434 timing: None,
435 page_size: None,
436 busy_poll_flag: None,
437 busy_poll_status: None,
438 reset_inst_f0: None,
439 reset_inst_66_99: None,
440 status_1_vol: None,
441 }
442 }
443
444 fn read_jesd216a(&mut self, dwords: &[u32]) {
446 let erase_scale = bits!(dwords[9], 4, 0);
448 if let Some(inst) = self.erase_insts[0].as_mut() {
449 let typ = bits!(dwords[9], 7, 4);
450 let (typ, max) = Self::sector_erase_durations(typ, erase_scale);
451 inst.time_typ = Some(typ);
452 inst.time_max = Some(max);
453 }
454 if let Some(inst) = self.erase_insts[1].as_mut() {
455 let typ = bits!(dwords[9], 7, 11);
456 let (typ, max) = Self::sector_erase_durations(typ, erase_scale);
457 inst.time_typ = Some(typ);
458 inst.time_max = Some(max);
459 }
460 if let Some(inst) = self.erase_insts[2].as_mut() {
461 let typ = bits!(dwords[9], 7, 18);
462 let (typ, max) = Self::sector_erase_durations(typ, erase_scale);
463 inst.time_typ = Some(typ);
464 inst.time_max = Some(max);
465 }
466 if let Some(inst) = self.erase_insts[3].as_mut() {
467 let typ = bits!(dwords[9], 7, 25);
468 let (typ, max) = Self::sector_erase_durations(typ, erase_scale);
469 inst.time_typ = Some(typ);
470 inst.time_max = Some(max);
471 }
472
473 let typ = bits!(dwords[10], 7, 24);
475 let (chip_erase_time_typ, chip_erase_time_max) =
476 Self::chip_erase_duration(typ, erase_scale);
477 let program_scale = bits!(dwords[10], 4, 0);
478 let typ = bits!(dwords[10], 5, 19);
479 let (succ_byte_prog_time_typ, succ_byte_prog_time_max) =
480 Self::byte_program_duration(typ, program_scale);
481 let typ = bits!(dwords[10], 5, 14);
482 let (first_byte_prog_time_typ, first_byte_prog_time_max) =
483 Self::byte_program_duration(typ, program_scale);
484 let typ = bits!(dwords[10], 6, 8);
485 let (page_prog_time_typ, page_prog_time_max) =
486 Self::page_program_duration(typ, program_scale);
487 self.timing = Some(SFDPTiming {
488 chip_erase_time_typ,
489 chip_erase_time_max,
490 first_byte_prog_time_typ,
491 first_byte_prog_time_max,
492 succ_byte_prog_time_typ,
493 succ_byte_prog_time_max,
494 page_prog_time_typ,
495 page_prog_time_max,
496 });
497 self.page_size = Some(1 << bits!(dwords[10], 4, 4));
498
499 let status_reg_poll = bits!(dwords[13], 6, 2);
503 self.busy_poll_flag = Some((status_reg_poll & 0b00_0010) != 0);
504 self.busy_poll_status = Some((status_reg_poll & 0b00_0001) != 0);
505
506 let reset = bits!(dwords[15], 6, 8);
510 self.reset_inst_f0 = Some((reset & 0b00_1000) != 0);
511 self.reset_inst_66_99 = Some((reset & 0b01_0000) != 0);
512 let vol = bits!(dwords[15], 7, 0);
513 self.status_1_vol = Some(SFDPStatus1Volatility::from_bits(vol));
514 }
515
516 fn sector_erase_durations(typ: u32, max_scale: u32) -> (Duration, Duration) {
520 let scale = match bits!(typ, 2, 5) {
521 0b00 => Duration::from_millis(1),
522 0b01 => Duration::from_millis(16),
523 0b10 => Duration::from_millis(128),
524 0b11 => Duration::from_secs(1),
525 _ => unreachable!(),
526 };
527 let count = bits!(typ, 5, 0);
528 let typ = (count + 1) * scale;
529 let max = 2 * (max_scale + 1) * typ;
530 (typ, max)
531 }
532
533 fn chip_erase_duration(typ: u32, max_scale: u32) -> (Duration, Duration) {
537 let scale = match bits!(typ, 2, 5) {
538 0b00 => Duration::from_millis(16),
539 0b01 => Duration::from_millis(256),
540 0b10 => Duration::from_secs(4),
541 0b11 => Duration::from_secs(64),
542 _ => unreachable!(),
543 };
544 let count = bits!(typ, 5, 0);
545 let typ = (count + 1) * scale;
546 let max = 2 * (max_scale + 1) * typ;
547 (typ, max)
548 }
549
550 fn byte_program_duration(typ: u32, max_scale: u32) -> (Duration, Duration) {
554 let scale = match bits!(typ, 1, 4) {
555 0b0 => Duration::from_micros(1),
556 0b1 => Duration::from_micros(8),
557 _ => unreachable!(),
558 };
559 let count = bits!(typ, 4, 0);
560 let typ = (count + 1) * scale;
561 let max = 2 * (max_scale + 1) * typ;
562 (typ, max)
563 }
564
565 fn page_program_duration(typ: u32, max_scale: u32) -> (Duration, Duration) {
569 let scale = match bits!(typ, 1, 5) {
570 0b0 => Duration::from_micros(8),
571 0b1 => Duration::from_micros(64),
572 _ => unreachable!(),
573 };
574 let count = bits!(typ, 5, 0);
575 let typ = (count + 1) * scale;
576 let max = 2 * (max_scale + 1) * typ;
577 (typ, max)
578 }
579}
580
581impl core::fmt::Display for FlashParams {
582 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
583 writeln!(
584 f,
585 "SFDP JEDEC Basic Flash Parameter Table v{}.{}",
586 self.version_major, self.version_minor
587 )?;
588 writeln!(
589 f,
590 " Density: {} bits ({} KiB)",
591 self.density,
592 self.capacity_bytes() / 1024
593 )?;
594 writeln!(f, " Address bytes: {:?}", self.address_bytes)?;
595 writeln!(f, " Legacy information:")?;
596 writeln!(
597 f,
598 " 4kB erase supported: {}",
599 self.legacy_4kb_erase_supported
600 )?;
601 writeln!(
602 f,
603 " 4kB erase opcode: 0x{:02X}",
604 self.legacy_4kb_erase_inst
605 )?;
606 writeln!(
607 f,
608 " Block Protect always volatile: {}",
609 self.legacy_block_protect_volatile
610 )?;
611 writeln!(
612 f,
613 " Volatile write enable opcode: 0x{:02X}",
614 self.legacy_volatile_write_en_inst
615 )?;
616 writeln!(
617 f,
618 " Writes have byte granularity: {}",
619 self.legacy_byte_write_granularity
620 )?;
621 writeln!(f, " Erase instructions:")?;
622 for i in 0..4 {
623 if let Some(inst) = self.erase_insts[i] {
624 writeln!(f, " {}: {}", i + 1, inst)?;
625 } else {
626 writeln!(f, " {}: Not present", i + 1)?;
627 }
628 }
629 if let Some(timing) = self.timing {
630 writeln!(f, " Timing:")?;
631 writeln!(
632 f,
633 " Chip erase: typ {:?}, max {:?}",
634 timing.chip_erase_time_typ, timing.chip_erase_time_max
635 )?;
636 writeln!(
637 f,
638 " First byte program: typ {:?}, max {:?}",
639 timing.first_byte_prog_time_typ, timing.first_byte_prog_time_max
640 )?;
641 writeln!(
642 f,
643 " Subsequent byte program: typ {:?}, max {:?}",
644 timing.succ_byte_prog_time_typ, timing.succ_byte_prog_time_max
645 )?;
646 writeln!(
647 f,
648 " Page program: typ {:?}, max {:?}",
649 timing.page_prog_time_typ, timing.page_prog_time_max
650 )?;
651 }
652 if let Some(page_size) = self.page_size {
653 writeln!(f, " Page size: {} bytes", page_size)?;
654 }
655 if let Some(busy_poll_flag) = self.busy_poll_flag {
656 writeln!(f, " Poll busy from FSR: {}", busy_poll_flag)?;
657 }
658 if let Some(busy_poll_status) = self.busy_poll_status {
659 writeln!(f, " Poll busy from SR1: {}", busy_poll_status)?;
660 }
661 if let Some(reset_inst_f0) = self.reset_inst_f0 {
662 writeln!(f, " Reset using opcode 0xF0: {}", reset_inst_f0)?;
663 }
664 if let Some(reset_inst_66_99) = self.reset_inst_66_99 {
665 writeln!(f, " Reset using opcodes 0x66, 0x99: {}", reset_inst_66_99)?;
666 }
667 if let Some(status_1_vol) = self.status_1_vol {
668 writeln!(f, " Status register 1 volatility: {:?}", status_1_vol)?;
669 }
670 Ok(())
671 }
672}