diff --git a/src/zynq/flash/mod.rs b/src/zynq/flash/mod.rs index 284fcd2f..30435631 100644 --- a/src/zynq/flash/mod.rs +++ b/src/zynq/flash/mod.rs @@ -6,7 +6,11 @@ use super::clocks::CpuClocks; pub mod regs; +const FLASH_BAUD_RATE: u32 = 50_000_000; + /// Flash Interface Driver +/// +/// For 2x Spansion S25FL128SAGMFIR01 pub struct Flash { regs: &'static mut regs::RegisterBlock, } @@ -19,7 +23,8 @@ impl Flash { let regs = regs::RegisterBlock::qspi(); let mut flash = Flash { regs }; - flash.configure(); + flash.configure((FLASH_BAUD_RATE - 1 + clock) / FLASH_BAUD_RATE); + flash.setup_linear_addressing_mode(); flash } @@ -39,7 +44,46 @@ impl Flash { } fn setup_signals() { - // TODO + slcr::RegisterBlock::unlocked(|slcr| { + // 1. Configure MIO pin 1 for chip select 0 output. + slcr.mio_pin_01.write( + slcr::MioPin01::zeroed() + .l0_sel(true) + .io_type(slcr::IoBufferType::Lvcmos18) + .pullup(true) + ); + + // Configure MIO pins 2 through 5 for I/O. + slcr.mio_pin_02.write( + slcr::MioPin02::zeroed() + .l0_sel(true) + .io_type(slcr::IoBufferType::Lvcmos18) + ); + slcr.mio_pin_03.write( + slcr::MioPin03::zeroed() + .l0_sel(true) + .io_type(slcr::IoBufferType::Lvcmos18) + ); + slcr.mio_pin_04.write( + slcr::MioPin04::zeroed() + .l0_sel(true) + .io_type(slcr::IoBufferType::Lvcmos18) + ); + slcr.mio_pin_05.write( + slcr::MioPin05::zeroed() + .l0_sel(true) + .io_type(slcr::IoBufferType::Lvcmos18) + ); + + // 3. Configure MIO pin 6 for serial clock 0 output. + slcr.mio_pin_06.write( + slcr::MioPin06::zeroed() + .l0_sel(true) + .io_type(slcr::IoBufferType::Lvcmos18) + ); + + // TODO: optional 2nd chip setup + }); } fn reset() { @@ -55,13 +99,33 @@ impl Flash { }); } - fn configure(&mut self) { + fn configure(&mut self, divider: u32) { + // for a baud_rate_div=1 LPBK_DLY_ADJ would be required + let mut baud_rate_div = 2u32; + while baud_rate_div < 7 && 2u32.pow(1 + baud_rate_div) < divider { + baud_rate_div += 1; + } + self.regs.config.modify(|_, w| w - .baud_rate_div(4 /* TODO */) + .baud_rate_div(baud_rate_div as u8) .mode_sel(true) .leg_flsh(true) .endian(false) .fifo_width(0b11) ); } + + fn setup_linear_addressing_mode(&mut self) { + self.regs.lqspi_cfg.modify(|_, w| w + .inst_code(0x3) + .u_page(false) + .sep_bus(false) + .two_mem(false) + .lq_mode(true) + ); + } + + pub fn ptr(&mut self) -> *mut T { + 0xFC00_0000 as *mut _ + } } diff --git a/src/zynq/flash/regs.rs b/src/zynq/flash/regs.rs index 65ee0cc4..955d1c4f 100644 --- a/src/zynq/flash/regs.rs +++ b/src/zynq/flash/regs.rs @@ -1,6 +1,6 @@ use volatile_register::{RO, WO, RW}; -use crate::{register, register_bit, register_bits, register_bits_typed}; +use crate::{register, register_bit, register_bits}; #[repr(C)] pub struct RegisterBlock { @@ -24,7 +24,7 @@ pub struct RegisterBlock { pub txd2: WO, pub txd3: WO, pub _unused3: [RO; 5], - pub lqspi_cfg: RW, + pub lqspi_cfg: LqspiCfg, pub lqspi_sts: RW, pub _unused4: [RO; 21], pub mod_id: RW, @@ -49,7 +49,7 @@ register_bit!(config, /// Clock phase clk_ph, 2); register_bits!(config, - /// divisor = 2 ** (1 + baud_rate_div) + /// divider = 2 ** (1 + baud_rate_div) baud_rate_div, u8, 3, 5); register_bits!(config, /// Must be set to 0b11 @@ -76,3 +76,14 @@ register_bit!(config, register_bit!(config, /// false: legacy SPI mode, true: Flash memory interface mode leg_flsh, 31); + +register!(lqspi_cfg, LqspiCfg, RW, u32); +register_bits!(lqspi_cfg, inst_code, u8, 0, 7); +register_bits!(lqspi_cfg, dummy_byte, u8, 8, 10); +register_bits!(lqspi_cfg, mode_bits, u8, 16, 23); +register_bit!(lqspi_cfg, mode_on, 24); +register_bit!(lqspi_cfg, mode_en, 25); +register_bit!(lqspi_cfg, u_page, 28); +register_bit!(lqspi_cfg, sep_bus, 29); +register_bit!(lqspi_cfg, two_mem, 30); +register_bit!(lqspi_cfg, lq_mode, 31);