diff options
| author | Ian McIntyre <me@mciantyre.dev> | 2025-12-20 16:48:32 -0500 |
|---|---|---|
| committer | Ian McIntyre <me@mciantyre.dev> | 2025-12-21 07:38:02 -0500 |
| commit | b3732747cf52a743d7c4dd4a07479cc533ad5416 (patch) | |
| tree | f59add163dd429f6d46a25649c034cb9de8adde1 /src | |
| parent | a800ee097af0c2334318d39dec2c0a40dbd5c0d9 (diff) | |
Consolidate flash algorithm init
Diffstat (limited to 'src')
| -rw-r--r-- | src/flash/adesto.rs | 7 | ||||
| -rw-r--r-- | src/flash/issi.rs | 124 | ||||
| -rw-r--r-- | src/flash/winbond.rs | 92 | ||||
| -rw-r--r-- | src/imxrt10xx.rs | 28 | ||||
| -rw-r--r-- | src/imxrt11xx.rs | 26 | ||||
| -rw-r--r-- | src/lib.rs | 194 | ||||
| -rw-r--r-- | src/sequences/common.rs | 8 |
7 files changed, 206 insertions, 273 deletions
diff --git a/src/flash/adesto.rs b/src/flash/adesto.rs deleted file mode 100644 index 0c21d8c..0000000 --- a/src/flash/adesto.rs +++ /dev/null @@ -1,7 +0,0 @@ -//! Adesto serial NOR flash. -//! -//! Looks just like a Winbond flash part. - -pub use super::winbond::Winbond as Adesto; - -pub type At25sf128 = Adesto<{ 128 / 8 * 1024 * 1024 }>; diff --git a/src/flash/issi.rs b/src/flash/issi.rs deleted file mode 100644 index 6b517af..0000000 --- a/src/flash/issi.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! ISSI Serial NOR Flash. -//! -//! The same algorithm will query the flash part to differentiate -//! the 3.3V part ("LP") from the 1.8V part ("WP"). Sequences and -//! configurations vary by part. Replace the W and L with 'x'. - -use super::*; -use crate::{ImxrtFlashAlgorithm, sequences::common as sequences}; - -pub type Is25xP128 = Issi<{ 128 / 8 * 1024 * 1024 }>; - -/// An ISSI serial NOR flash driver. -pub struct Issi<const FLASH_CAPACITY_BYTES: usize>; - -const ISSI_WP_MEM_TYPE: u8 = 0x70; -const ISSI_LP_MEM_TYPE: u8 = 0x60; - -impl<const FLASH_CAPACITY_BYTES: usize> ImxrtFlashAlgorithm for Issi<FLASH_CAPACITY_BYTES> { - const FLASH_CAPACITY_BYTES: usize = FLASH_CAPACITY_BYTES; - const FLASH_PAGE_SIZE_BYTES: usize = 256; - const FLASH_SECTOR_SIZE_BYTES: usize = 4096; - - fn initialize(flexspi: imxrt_drivers_flexspi::Instance) { - defmt::assert_eq!( - READ_ID_JEDEC_ID, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - READ_ID_JEDEC_ID.seq_id, - &[sequences::SEQ_READ_ID_JEDEC_ID] - )) - ); - - let jedec_id = super::read_jedec_id(flexspi); - defmt::assert_eq!(jedec_id.mnf_id, 0x9D); - - let (dummy_cycles, set_read_params_data) = match jedec_id.mem_type { - ISSI_WP_MEM_TYPE => (15, 15 << 3), - ISSI_LP_MEM_TYPE => (10, (0b111 << 5) | (0b11) << 3), - _ => defmt::panic!("{=u8:#X}", jedec_id.mem_type), - }; - - defmt::assert_eq!( - READ, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - READ.seq_id, - &[sequences::seq_fast_read_quad_io(dummy_cycles)], - )) - ); - - defmt::assert_eq!( - SET_READ_PARAMS, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - SET_READ_PARAMS.seq_id, - &[sequences::SEQ_SET_READ_PARAMS_VOL] - )) - ); - - defmt::assert_eq!( - WRITE_ENABLE, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - WRITE_ENABLE.seq_id, - &[sequences::SEQ_WRITE_ENABLE] - )) - ); - - defmt::assert_eq!( - ERASE_SECTOR, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - ERASE_SECTOR.seq_id, - &[sequences::SEQ_WRITE_ENABLE, sequences::SEQ_ERASE_SECTOR] - )) - ); - - defmt::assert_eq!( - READ_STATUS, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - READ_STATUS.seq_id, - &[sequences::SEQ_READ_STATUS] - )) - ); - - defmt::assert_eq!( - PAGE_PROGRAM, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - PAGE_PROGRAM.seq_id, - &[ - sequences::SEQ_WRITE_ENABLE, - sequences::SEQ_PAGE_PROGRAM_QUAD_INPUT - ] - )) - ); - - defmt::assert_eq!( - CHIP_ERASE, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - CHIP_ERASE.seq_id, - &[sequences::SEQ_WRITE_ENABLE, sequences::SEQ_ERASE_CHIP] - )) - ); - - defmt::assert_eq!( - RESET, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - RESET.seq_id, - &[sequences::SEQ_RSTEN, sequences::SEQ_RST] - )) - ); - - let set_read_params_data = [set_read_params_data]; - crate::start_ip_cmd(flexspi, SET_READ_PARAMS, 0, &set_read_params_data); - crate::transmit_bytes(flexspi, &set_read_params_data); - crate::wait_for_ip_cmd_done(flexspi); - crate::clear_tx_fifo(flexspi); - crate::wait_for_idle(flexspi); - } -} diff --git a/src/flash/winbond.rs b/src/flash/winbond.rs deleted file mode 100644 index afac605..0000000 --- a/src/flash/winbond.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Winbond Serial NOR Flash. - -use super::*; -use crate::{ImxrtFlashAlgorithm, sequences::common as sequences}; - -pub type W25q64 = Winbond<{ 64 / 8 * 1024 * 1024 }>; - -/// A Winbond serial NOR flash driver. -pub struct Winbond<const FLASH_CAPACITY_BYTES: usize>; - -impl<const FLASH_CAPACITY_BYTES: usize> ImxrtFlashAlgorithm for Winbond<FLASH_CAPACITY_BYTES> { - const FLASH_CAPACITY_BYTES: usize = FLASH_CAPACITY_BYTES; - const FLASH_PAGE_SIZE_BYTES: usize = 256; - const FLASH_SECTOR_SIZE_BYTES: usize = 4096; - - fn initialize(flexspi: imxrt_drivers_flexspi::Instance) { - defmt::assert_eq!( - READ, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - READ.seq_id, - &[sequences::seq_fast_read_quad_io(6)], - )) - ); - - defmt::assert_eq!( - SET_READ_PARAMS, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - SET_READ_PARAMS.seq_id, - &[sequences::SEQ_SET_READ_PARAMS_VOL] - )) - ); - - defmt::assert_eq!( - WRITE_ENABLE, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - WRITE_ENABLE.seq_id, - &[sequences::SEQ_WRITE_ENABLE] - )) - ); - - defmt::assert_eq!( - ERASE_SECTOR, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - ERASE_SECTOR.seq_id, - &[sequences::SEQ_WRITE_ENABLE, sequences::SEQ_ERASE_SECTOR] - )) - ); - - defmt::assert_eq!( - READ_STATUS, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - READ_STATUS.seq_id, - &[sequences::SEQ_READ_STATUS] - )) - ); - - defmt::assert_eq!( - PAGE_PROGRAM, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - PAGE_PROGRAM.seq_id, - &[ - sequences::SEQ_WRITE_ENABLE, - sequences::SEQ_PAGE_PROGRAM_QUAD_INPUT - ] - )) - ); - - defmt::assert_eq!( - CHIP_ERASE, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - CHIP_ERASE.seq_id, - &[sequences::SEQ_WRITE_ENABLE, sequences::SEQ_ERASE_CHIP] - )) - ); - - defmt::assert_eq!( - RESET, - defmt::unwrap!(crate::install_ip_cmd( - flexspi, - RESET.seq_id, - &[sequences::SEQ_RSTEN, sequences::SEQ_RST] - )) - ); - } -} diff --git a/src/imxrt10xx.rs b/src/imxrt10xx.rs index 095b91d..042574c 100644 --- a/src/imxrt10xx.rs +++ b/src/imxrt10xx.rs @@ -17,26 +17,28 @@ pub trait Imxrt10xx: 'static { fn configure_clocks(ccm: ccm::Instance, ccm_analog: ccm_analog::Instance, dcdc: dcdc::Instance); } -pub struct Algorithm<C: Imxrt10xx, F: crate::ImxrtFlashAlgorithm>(PhantomData<(C, F)>); +pub struct Algorithm<C: Imxrt10xx, const FLASH_SIZE_BYTES: usize>(PhantomData<C>); -impl<C: Imxrt10xx, F: crate::ImxrtFlashAlgorithm> Algorithm<C, F> { - pub const fn flash_size_bytes() -> usize { - F::FLASH_CAPACITY_BYTES - } +impl<C: Imxrt10xx, const FLASH_SIZE_BYTES: usize> Algorithm<C, FLASH_SIZE_BYTES> { pub const fn flash_address() -> usize { FLEXSPI1_BASE as _ } - pub const fn sector_size_bytes() -> usize { - F::FLASH_SECTOR_SIZE_BYTES + + pub const fn flash_size_bytes() -> usize { + FLASH_SIZE_BYTES } - pub const fn page_size_bytes() -> usize { - F::FLASH_PAGE_SIZE_BYTES + + pub const fn sector_size_bytes() -> usize { + 4 * 1024 } pub fn initialize() -> Self { C::configure_clocks(C::CCM_INSTANCE, C::CCM_ANALOG_INSTANCE, C::DCDC_INSTANCE); - crate::reset(C::FLEXSPI1_INSTANCE, F::FLASH_CAPACITY_BYTES / 1024, 128); - F::initialize(C::FLEXSPI1_INSTANCE); + crate::flash::initialize( + C::FLEXSPI1_INSTANCE, + FLASH_SIZE_BYTES, + C::FLEXSPI_FIFO_CAPACITY_BYTES, + ); Algorithm(PhantomData) } @@ -53,8 +55,8 @@ impl<C: Imxrt10xx, F: crate::ImxrtFlashAlgorithm> Algorithm<C, F> { } } -impl<C: Imxrt10xx, F: crate::ImxrtFlashAlgorithm> flash_algorithm::FlashAlgorithm - for Algorithm<C, F> +impl<C: Imxrt10xx, const FLASH_SIZE_BYTES: usize> flash_algorithm::FlashAlgorithm + for Algorithm<C, FLASH_SIZE_BYTES> { fn new( _: u32, diff --git a/src/imxrt11xx.rs b/src/imxrt11xx.rs index 7fc9763..75d5020 100644 --- a/src/imxrt11xx.rs +++ b/src/imxrt11xx.rs @@ -157,20 +157,19 @@ pub trait Imxrt11xx: 'static { const FLEXSPI_FIFO_CAPACITY_BYTES: usize; } -pub struct Algorithm<C: Imxrt11xx, F: crate::ImxrtFlashAlgorithm>(PhantomData<(C, F)>); +pub struct Algorithm<C: Imxrt11xx, const FLASH_SIZE_BYTES: usize>(PhantomData<C>); -impl<C: Imxrt11xx, F: crate::ImxrtFlashAlgorithm> Algorithm<C, F> { - pub const fn flash_size_bytes() -> usize { - F::FLASH_CAPACITY_BYTES - } +impl<C: Imxrt11xx, const FLASH_SIZE_BYTES: usize> Algorithm<C, FLASH_SIZE_BYTES> { pub const fn flash_address() -> usize { FLEXSPI1_BASE as _ } - pub const fn sector_size_bytes() -> usize { - F::FLASH_SECTOR_SIZE_BYTES + + pub const fn flash_size_bytes() -> usize { + FLASH_SIZE_BYTES } - pub const fn page_size_bytes() -> usize { - F::FLASH_PAGE_SIZE_BYTES + + pub const fn sector_size_bytes() -> usize { + 4 * 1024 } pub fn initialize() -> Self { @@ -182,12 +181,11 @@ impl<C: Imxrt11xx, F: crate::ImxrtFlashAlgorithm> Algorithm<C, F> { C::PMU_INSTANCE, C::GPC_CPU_INSTANCE, ); - crate::reset( + crate::flash::initialize( C::FLEXSPI1_INSTANCE, - F::FLASH_CAPACITY_BYTES / 1024, + FLASH_SIZE_BYTES, C::FLEXSPI_FIFO_CAPACITY_BYTES, ); - F::initialize(C::FLEXSPI1_INSTANCE); Algorithm(PhantomData) } @@ -204,8 +202,8 @@ impl<C: Imxrt11xx, F: crate::ImxrtFlashAlgorithm> Algorithm<C, F> { } } -impl<C: Imxrt11xx, F: crate::ImxrtFlashAlgorithm> flash_algorithm::FlashAlgorithm - for Algorithm<C, F> +impl<C: Imxrt11xx, const FLASH_SIZE_BYTES: usize> flash_algorithm::FlashAlgorithm + for Algorithm<C, FLASH_SIZE_BYTES> { fn new( _: u32, @@ -12,10 +12,6 @@ pub mod sequences { pub mod flash { use super::{IpCmd, SeqId, flexspi}; - pub mod adesto; - pub mod issi; - pub mod winbond; - /// Conveniently the default AHB read sequence index. const READ: IpCmd = IpCmd::new(SeqId::Seq00, 1).unwrap(); const READ_STATUS: IpCmd = IpCmd::new(SeqId::Seq01, 1).unwrap(); @@ -24,9 +20,8 @@ pub mod flash { const PAGE_PROGRAM: IpCmd = IpCmd::new(SeqId::Seq09, 2).unwrap(); const CHIP_ERASE: IpCmd = IpCmd::new(SeqId::Seq11, 2).unwrap(); - const SET_READ_PARAMS: IpCmd = IpCmd::new(SeqId::Seq02, 1).unwrap(); const READ_ID_JEDEC_ID: IpCmd = IpCmd::new(SeqId::Seq04, 1).unwrap(); - const RESET: IpCmd = IpCmd::new(SeqId::Seq07, 2).unwrap(); + const READ_READ_PARAMS: IpCmd = IpCmd::new(SeqId::Seq02, 1).unwrap(); const PAGE_SIZE_BYTES: usize = 256; @@ -109,15 +104,6 @@ pub mod flash { wait_for_wip_clear(flexspi); } - /// Reset the flash chip. - pub fn reset(flexspi: flexspi::Instance) { - crate::start_ip_cmd(flexspi, RESET, 0, &[]); - crate::wait_for_ip_cmd_done(flexspi); - crate::wait_for_idle(flexspi); - - wait_for_wip_clear(flexspi); - } - #[derive(Debug, Clone, Copy, PartialEq, defmt::Format)] pub struct JedecId { pub mnf_id: u8, @@ -141,6 +127,17 @@ pub mod flash { } } + /// Read the read register parameters. + pub fn read_read_params(flexspi: flexspi::Instance) -> u8 { + let mut buffer = [0_u8; 1]; + crate::start_ip_cmd(flexspi, READ_READ_PARAMS, 0, &buffer); + crate::receive_bytes(flexspi, &mut buffer); + crate::wait_for_ip_cmd_done(flexspi); + crate::clear_rx_fifo(flexspi); + crate::wait_for_idle(flexspi); + buffer[0] + } + /// Produce chunks of bytes suitable for page aligned writing. fn aligned_chunks(start: usize, bytes: &[u8], page_size: usize) -> impl Iterator<Item = &[u8]> { let next_page_start = page_size - (start % page_size); @@ -199,6 +196,165 @@ pub mod flash { assert_eq!(chunks.next(), None); } } + + /// Supported NOR flash parts. + #[derive(Clone, Copy, defmt::Format)] + enum FlashKind { + /// Issi 1.8V + Is25wp, + /// Issi 3.3V + Is25lp, + /// Adesto 3.3V. + At25sf, + /// Winbond. + W25q, + } + + const ISSI_MF_ID: u8 = 0x9D; + const WINBOND_MF_ID: u8 = 0xEF; + const ADESTO_MF_ID: u8 = 0x1F; + + impl FlashKind { + fn discover(jedec_id: &JedecId) -> Option<Self> { + let flash = match jedec_id.mnf_id { + ISSI_MF_ID => Self::discover_issi(jedec_id)?, + WINBOND_MF_ID => Self::discover_winbond(jedec_id)?, + ADESTO_MF_ID => Self::discover_adesto(jedec_id)?, + _ => return None, + }; + + Some(flash) + } + + fn discover_winbond(_: &JedecId) -> Option<FlashKind> { + Some(FlashKind::W25q) + } + + fn discover_adesto(_: &JedecId) -> Option<FlashKind> { + Some(FlashKind::At25sf) + } + + fn discover_issi(jedec_id: &JedecId) -> Option<FlashKind> { + const ISSI_WP_MEM_TYPE: u8 = 0x70; + const ISSI_LP_MEM_TYPE: u8 = 0x60; + + Some(match jedec_id.mem_type { + ISSI_WP_MEM_TYPE => FlashKind::Is25wp, + ISSI_LP_MEM_TYPE => FlashKind::Is25lp, + _ => return None, + }) + } + } + + /// Figure the fast read quad I/O dummy cycles, possibly + /// querying the part to discover the value. + /// + /// This function should check against rated speeds, when + /// applicable, to make sure you're not going too fast. + fn discover_frqio_dummy_cycles(kind: FlashKind, flexspi: flexspi::Instance) -> u8 { + match kind { + FlashKind::At25sf | FlashKind::W25q => 6, + FlashKind::Is25wp => { + let read_params = read_read_params(flexspi); + let dummy_cycles = (read_params >> 3) & 0b1111; + if dummy_cycles == 0 { 6 } else { dummy_cycles } + } + FlashKind::Is25lp => { + // READ_READ_PARAMS not supported. + // Guess that the user has set the + // default value. + 6 + } + } + } + + use super::sequences::common as sequences; + + pub fn initialize( + flexspi: flexspi::Instance, + flash_size_bytes: usize, + fifo_capacity_bytes: usize, + ) { + crate::reset(flexspi, flash_size_bytes / 1024, fifo_capacity_bytes); + + defmt::assert_eq!( + READ_ID_JEDEC_ID, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + READ_ID_JEDEC_ID.seq_id, + &[sequences::SEQ_READ_ID_JEDEC_ID] + )) + ); + defmt::assert_eq!( + READ_READ_PARAMS, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + READ_READ_PARAMS.seq_id, + &[sequences::SEQ_READ_READ_PARAMS] + )) + ); + + let jedec_id = read_jedec_id(flexspi); + let flash = defmt::unwrap!(FlashKind::discover(&jedec_id), "{:?}", jedec_id); + let dummy_cycles = discover_frqio_dummy_cycles(flash, flexspi); + + defmt::assert_eq!( + READ, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + READ.seq_id, + &[sequences::seq_fast_read_quad_io(dummy_cycles)], + )) + ); + + defmt::assert_eq!( + WRITE_ENABLE, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + WRITE_ENABLE.seq_id, + &[sequences::SEQ_WRITE_ENABLE] + )) + ); + + defmt::assert_eq!( + ERASE_SECTOR, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + ERASE_SECTOR.seq_id, + &[sequences::SEQ_WRITE_ENABLE, sequences::SEQ_ERASE_SECTOR] + )) + ); + + defmt::assert_eq!( + READ_STATUS, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + READ_STATUS.seq_id, + &[sequences::SEQ_READ_STATUS] + )) + ); + + defmt::assert_eq!( + PAGE_PROGRAM, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + PAGE_PROGRAM.seq_id, + &[ + sequences::SEQ_WRITE_ENABLE, + sequences::SEQ_PAGE_PROGRAM_QUAD_INPUT + ] + )) + ); + + defmt::assert_eq!( + CHIP_ERASE, + defmt::unwrap!(crate::install_ip_cmd( + flexspi, + CHIP_ERASE.seq_id, + &[sequences::SEQ_WRITE_ENABLE, sequences::SEQ_ERASE_CHIP] + )) + ); + } } pub mod imxrt10xx; @@ -491,11 +647,3 @@ impl Iterator for FifoReader { Some(word) } } - -pub trait ImxrtFlashAlgorithm: 'static { - const FLASH_CAPACITY_BYTES: usize; - const FLASH_SECTOR_SIZE_BYTES: usize; - const FLASH_PAGE_SIZE_BYTES: usize; - - fn initialize(flexspi: flexspi::Instance); -} diff --git a/src/sequences/common.rs b/src/sequences/common.rs index 4bb9493..1c93067 100644 --- a/src/sequences/common.rs +++ b/src/sequences/common.rs @@ -88,3 +88,11 @@ pub const SEQ_READ_ID_JEDEC_ID: Sequence = { instr[1] = Instr::new(SDR_READ, Pads::One, 0); Sequence(instr) }; + +/// Read the read parameters register. +pub const SEQ_READ_READ_PARAMS: Sequence = { + let mut instr = [Instr::STOP; _]; + instr[0] = Instr::new(SDR_CMD, Pads::One, 0x61); + instr[1] = Instr::new(SDR_READ, Pads::One, 0); + Sequence(instr) +}; |
