zynq::flash: start implementing Manual mode

This commit is contained in:
Astro 2019-11-30 02:48:39 +01:00
parent dd3ad3be67
commit 7107244a6e
2 changed files with 84 additions and 4 deletions

View File

@ -1,15 +1,17 @@
//! Quad-SPI Flash Controller //! Quad-SPI Flash Controller
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::regs::{RegisterW, RegisterRW}; use crate::regs::{RegisterR, RegisterW, RegisterRW};
use super::slcr; use super::slcr;
use super::clocks::CpuClocks; use super::clocks::CpuClocks;
pub mod regs; pub mod regs;
const FLASH_BAUD_RATE: u32 = 50_000_000; const FLASH_BAUD_RATE: u32 = 50_000_000;
const SINGLE_CAPACITY: u32 = 16 * 1024 * 1024;
pub struct LinearAddressing; pub struct LinearAddressing;
pub struct Manual;
/// Flash Interface Driver /// Flash Interface Driver
/// ///
@ -196,6 +198,29 @@ impl Flash<()> {
self.transition() self.transition()
} }
pub fn manual_mode(self, chip_index: usize) -> Flash<Manual> {
self.regs.config.modify(|_, w| w
.man_start_en(true)
.manual_cs(true)
);
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
.mode_bits(0xFF)
.dummy_byte(0x2)
.mode_en(true)
// 2 devices
.two_mem(true)
.u_page(chip_index != 0)
);
self.regs.config.modify(|_, w| w
.pcs(false)
);
self.regs.enable.modify(|_, w| w.spi_en(true));
self.transition()
}
} }
impl Flash<LinearAddressing> { impl Flash<LinearAddressing> {
@ -213,6 +238,53 @@ impl Flash<LinearAddressing> {
} }
pub fn size(&self) -> usize { pub fn size(&self) -> usize {
32 * 1024 * 1024 2 * (SINGLE_CAPACITY as usize)
}
}
impl Flash<Manual> {
pub fn stop(self) -> Flash<()> {
self.regs.enable.modify(|_, w| w.spi_en(false));
// De-assert chip select.
self.regs.config.modify(|_, w| w.pcs(true));
self.transition()
}
pub fn read(&mut self, offset: u32, dest: &mut [u8]) {
self.regs.config.modify(|_, w| w.man_start_com(true));
// Quad I/O Read
let instr = 0xEB;
unsafe {
self.regs.txd0.write(
instr |
(offset << 8)
);
}
while self.regs.intr_status.read().tx_fifo_not_full() {
unsafe {
self.regs.txd0.write(0);
}
let rx = self.regs.rx_data.read();
}
for d in dest {
while !self.regs.intr_status.read().rx_fifo_not_empty() {}
// TODO: drops data?
let rx = self.regs.rx_data.read();
*d = rx as u8;
// Output dummy byte to generate clock for further RX
unsafe {
self.regs.txd1.write(0);
}
}
}
fn wait_tx_not_full(&self) {
while self.regs.intr_status.read().tx_fifo_full() {}
} }
} }

View File

@ -5,7 +5,7 @@ use crate::{register, register_bit, register_bits};
#[repr(C)] #[repr(C)]
pub struct RegisterBlock { pub struct RegisterBlock {
pub config: Config, pub config: Config,
pub intr_status: RW<u32>, pub intr_status: IntrStatus,
pub intr_en: RW<u32>, pub intr_en: RW<u32>,
pub intr_dis: RW<u32>, pub intr_dis: RW<u32>,
pub intr_mask: RO<u32>, pub intr_mask: RO<u32>,
@ -15,7 +15,7 @@ pub struct RegisterBlock {
pub rx_data: RO<u32>, pub rx_data: RO<u32>,
pub slave_idle_count: RW<u32>, pub slave_idle_count: RW<u32>,
pub tx_thres: RW<u32>, pub tx_thres: RW<u32>,
pub rx_thes: RW<u32>, pub rx_thres: RW<u32>,
pub gpio: RW<u32>, pub gpio: RW<u32>,
pub _unused1: RO<u32>, pub _unused1: RO<u32>,
pub lpbk_dly_adj: RW<u32>, pub lpbk_dly_adj: RW<u32>,
@ -77,6 +77,14 @@ register_bit!(config,
/// false: legacy SPI mode, true: Flash memory interface mode /// false: legacy SPI mode, true: Flash memory interface mode
leg_flsh, 31); leg_flsh, 31);
register!(intr_status, IntrStatus, RW, u32);
register_bit!(intr_status, rx_overflow, 0);
register_bit!(intr_status, tx_fifo_not_full, 2);
register_bit!(intr_status, tx_fifo_full, 3);
register_bit!(intr_status, rx_fifo_not_empty, 4);
register_bit!(intr_status, rx_fifo_full, 5);
register_bit!(intr_status, tx_fifo_underflow, 6);
register!(enable, Enable, RW, u32); register!(enable, Enable, RW, u32);
register_bit!(enable, spi_en, 0); register_bit!(enable, spi_en, 0);