zynq::flash: start implementing Manual mode
This commit is contained in:
parent
dd3ad3be67
commit
7107244a6e
|
@ -1,15 +1,17 @@
|
|||
//! Quad-SPI Flash Controller
|
||||
|
||||
use core::marker::PhantomData;
|
||||
use crate::regs::{RegisterW, RegisterRW};
|
||||
use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
||||
use super::slcr;
|
||||
use super::clocks::CpuClocks;
|
||||
|
||||
pub mod regs;
|
||||
|
||||
const FLASH_BAUD_RATE: u32 = 50_000_000;
|
||||
const SINGLE_CAPACITY: u32 = 16 * 1024 * 1024;
|
||||
|
||||
pub struct LinearAddressing;
|
||||
pub struct Manual;
|
||||
|
||||
/// Flash Interface Driver
|
||||
///
|
||||
|
@ -196,6 +198,29 @@ impl Flash<()> {
|
|||
|
||||
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> {
|
||||
|
@ -213,6 +238,53 @@ impl Flash<LinearAddressing> {
|
|||
}
|
||||
|
||||
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() {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{register, register_bit, register_bits};
|
|||
#[repr(C)]
|
||||
pub struct RegisterBlock {
|
||||
pub config: Config,
|
||||
pub intr_status: RW<u32>,
|
||||
pub intr_status: IntrStatus,
|
||||
pub intr_en: RW<u32>,
|
||||
pub intr_dis: RW<u32>,
|
||||
pub intr_mask: RO<u32>,
|
||||
|
@ -15,7 +15,7 @@ pub struct RegisterBlock {
|
|||
pub rx_data: RO<u32>,
|
||||
pub slave_idle_count: RW<u32>,
|
||||
pub tx_thres: RW<u32>,
|
||||
pub rx_thes: RW<u32>,
|
||||
pub rx_thres: RW<u32>,
|
||||
pub gpio: RW<u32>,
|
||||
pub _unused1: RO<u32>,
|
||||
pub lpbk_dly_adj: RW<u32>,
|
||||
|
@ -77,6 +77,14 @@ register_bit!(config,
|
|||
/// false: legacy SPI mode, true: Flash memory interface mode
|
||||
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_bit!(enable, spi_en, 0);
|
||||
|
||||
|
|
Loading…
Reference in New Issue