Compare commits
No commits in common. "7107244a6ec56a81205e2cc0101d5330931144e2" and "78caca1f04291a05930d76c7b2f49bb262789e3c" have entirely different histories.
7107244a6e
...
78caca1f04
|
@ -1,17 +1,15 @@
|
||||||
//! Quad-SPI Flash Controller
|
//! Quad-SPI Flash Controller
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use crate::regs::{RegisterR, RegisterW, RegisterRW};
|
use crate::regs::{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
|
||||||
///
|
///
|
||||||
|
@ -21,15 +19,6 @@ pub struct Flash<MODE> {
|
||||||
_mode: PhantomData<MODE>,
|
_mode: PhantomData<MODE>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<MODE> Flash<MODE> {
|
|
||||||
fn transition<TO>(self) -> Flash<TO> {
|
|
||||||
Flash {
|
|
||||||
regs: self.regs,
|
|
||||||
_mode: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Flash<()> {
|
impl Flash<()> {
|
||||||
pub fn new(clock: u32) -> Self {
|
pub fn new(clock: u32) -> Self {
|
||||||
Self::enable_clocks(clock);
|
Self::enable_clocks(clock);
|
||||||
|
@ -183,108 +172,24 @@ impl Flash<()> {
|
||||||
);
|
);
|
||||||
|
|
||||||
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
|
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
|
||||||
// Quad I/O Fast Read
|
.inst_code(0x3)
|
||||||
.inst_code(0xEB)
|
.u_page(false)
|
||||||
.mode_bits(0xFF)
|
.sep_bus(false)
|
||||||
.dummy_byte(0x2)
|
.two_mem(false)
|
||||||
.mode_en(true)
|
|
||||||
// 2 devices
|
|
||||||
.two_mem(true)
|
|
||||||
// Linear Addressing Mode
|
|
||||||
.lq_mode(true)
|
.lq_mode(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
self.regs.enable.modify(|_, w| w.spi_en(true));
|
self.regs.enable.modify(|_, w| w.spi_en(true));
|
||||||
|
|
||||||
self.transition()
|
Flash {
|
||||||
}
|
regs: self.regs,
|
||||||
|
_mode: PhantomData,
|
||||||
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> {
|
||||||
/// Stop linear addressing mode
|
|
||||||
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 ptr<T>(&mut self) -> *mut T {
|
pub fn ptr<T>(&mut self) -> *mut T {
|
||||||
0xFC00_0000 as *mut _
|
0xFC00_0000 as *mut _
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> usize {
|
|
||||||
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)]
|
#[repr(C)]
|
||||||
pub struct RegisterBlock {
|
pub struct RegisterBlock {
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
pub intr_status: IntrStatus,
|
pub intr_status: RW<u32>,
|
||||||
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_thres: RW<u32>,
|
pub rx_thes: 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,14 +77,6 @@ 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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue