remove flash support

PITA to get to work and most boards have SD.
pull/69/head
Sebastien Bourdeauducq 2020-09-09 20:13:13 +08:00
parent a6955edf14
commit e601ac9c45
7 changed files with 1 additions and 905 deletions

View File

@ -15,7 +15,7 @@ use libboard_zynq::{
self as zynq,
clocks::source::{ArmPll, ClockSource, IoPll},
clocks::Clocks,
print, println, stdio,
println, stdio,
mpcore,
gic,
smoltcp::{
@ -140,17 +140,6 @@ pub fn main_core0() {
clocks.cpu_1x()
);
let mut flash = zynq::flash::Flash::flash(200_000_000).linear_addressing_mode();
let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) };
for i in 0..=1 {
print!("Flash {}:", i);
for b in &flash_ram[(i * 16 * 1024 * 1024)..][..128] {
print!(" {:02X}", *b);
}
println!("");
}
let _flash = flash.stop();
let timer = libboard_zynq::timer::GlobalTimer::start();
let mut ddr = zynq::ddr::DdrRam::ddrram();
@ -158,45 +147,6 @@ pub fn main_core0() {
ddr.memtest();
ram::init_alloc_ddr(&mut ddr);
#[cfg(dev)]
for i in 0..=1 {
let mut flash_io = flash.manual_mode(i);
// println!("rdcr={:02X}", flash_io.rdcr());
print!("Flash {} ID:", i);
for b in flash_io.rdid() {
print!(" {:02X}", b);
}
println!("");
print!("Flash {} I/O:", i);
for o in 0..8 {
const CHUNK: u32 = 8;
for b in flash_io.read(CHUNK * o, CHUNK as usize) {
print!(" {:02X}", b);
}
}
println!("");
flash_io.dump("Read cr1", 0x35);
flash_io.dump("Read Autoboot", 0x14);
flash_io.dump("Read Bank", 0x16);
flash_io.dump("DLP Bank", 0x16);
flash_io.dump("Read ESig", 0xAB);
flash_io.dump("OTP Read", 0x4B);
flash_io.dump("DYB Read", 0xE0);
flash_io.dump("PPB Read", 0xE2);
flash_io.dump("ASP Read", 0x2B);
flash_io.dump("Password Read", 0xE7);
flash_io.write_enabled(|flash_io| {
flash_io.erase(0);
});
flash_io.write_enabled(|flash_io| {
flash_io.program(0, [0x23054223; 0x100 >> 2].iter().cloned());
});
flash = flash_io.stop();
}
boot::Core1::start(false);
let core1_req = unsafe { &mut CORE1_REQ.0 };

View File

@ -1,41 +0,0 @@
pub trait BytesTransferExt: Sized {
// Turn u32 into u8
fn bytes_transfer(self) -> BytesTransfer<Self>
where
Self: Iterator<Item = u32>;
}
impl<I: Iterator<Item = u32>> BytesTransferExt for I {
// Turn u32 into u8
fn bytes_transfer(self) -> BytesTransfer<Self> {
BytesTransfer {
iter: self,
shift: 0,
word: 0,
}
}
}
pub struct BytesTransfer<I: Iterator<Item = u32> + Sized> {
iter: I,
shift: u8,
word: u32,
}
impl<I: Iterator<Item = u32> + Sized> Iterator for BytesTransfer<I> {
type Item = u8;
fn next(&mut self) -> Option<u8> {
if self.shift > 0 {
self.shift -= 8;
Some((self.word >> self.shift) as u8)
} else {
self.iter.next()
.and_then(|word| {
self.shift = 32;
self.word = word;
self.next()
})
}
}
}

View File

@ -1,503 +0,0 @@
//! Quad-SPI Flash Controller
use core::marker::PhantomData;
use log::{error, info, warn};
use libregister::{RegisterR, RegisterW, RegisterRW};
use crate::{print, println};
use super::slcr;
use super::clocks::source::{IoPll, ClockSource};
mod regs;
mod bytes;
pub use bytes::{BytesTransferExt, BytesTransfer};
mod spi_flash_register;
use spi_flash_register::*;
mod transfer;
use transfer::Transfer;
const FLASH_BAUD_RATE: u32 = 50_000_000;
/// 16 MB
pub const SINGLE_CAPACITY: u32 = 0x1000000;
pub const SECTOR_SIZE: u32 = 0x10000;
pub const PAGE_SIZE: u32 = 0x100;
/// Instruction: Read Identification
const INST_RDID: u8 = 0x9F;
/// Instruction: Read
const INST_READ: u8 = 0x03;
/// Instruction: Quad I/O Fast Read
const INST_4IO_FAST_READ: u8 = 0xEB;
/// Instruction: Write Disable
const INST_WRDI: u8 = 0x04;
/// Instruction: Write Enable
const INST_WREN: u8 = 0x06;
/// Instruction: Program page
const INST_PP: u8 = 0x02;
/// Instruction: Erase 4K Block
const INST_BE_4K: u8 = 0x20;
#[derive(Clone)]
pub enum SpiWord {
W8(u8),
W16(u16),
W24(u32),
W32(u32),
}
impl From<u8> for SpiWord {
fn from(x: u8) -> Self {
SpiWord::W8(x)
}
}
impl From<u16> for SpiWord {
fn from(x: u16) -> Self {
SpiWord::W16(x)
}
}
impl From<u32> for SpiWord {
fn from(x: u32) -> Self {
SpiWord::W32(x)
}
}
/// Memory-mapped mode
pub struct LinearAddressing;
/// Manual I/O mode
pub struct Manual;
/// Flash Interface Driver
///
/// For 2x Spansion S25FL128SAGMFIR01
pub struct Flash<MODE> {
regs: &'static mut regs::RegisterBlock,
_mode: PhantomData<MODE>,
}
impl<MODE> Flash<MODE> {
fn transition<TO>(self) -> Flash<TO> {
Flash {
regs: self.regs,
_mode: PhantomData,
}
}
fn disable_interrupts(&mut self) {
self.regs.intr_dis.write(
regs::IntrDis::zeroed()
.rx_overflow(true)
.tx_fifo_not_full(true)
.tx_fifo_full(true)
.rx_fifo_not_empty(true)
.rx_fifo_full(true)
.tx_fifo_underflow(true)
);
}
fn clear_rx_fifo(&self) {
while self.regs.intr_status.read().rx_fifo_not_empty() {
let _ = self.regs.rx_data.read();
}
}
fn clear_interrupt_status(&mut self) {
self.regs.intr_status.write(
regs::IntrStatus::zeroed()
.rx_overflow(true)
.tx_fifo_underflow(true)
);
}
fn wait_tx_fifo_flush(&mut self) {
self.regs.config.modify(|_, w| w.man_start_com(true));
while !self.regs.intr_status.read().tx_fifo_not_full() {}
}
}
impl Flash<()> {
pub fn flash(clock: u32) -> Self {
Self::enable_clocks(clock);
Self::setup_signals();
Self::reset();
let regs = regs::RegisterBlock::qspi();
let mut flash = Flash { regs, _mode: PhantomData };
flash.configure((FLASH_BAUD_RATE - 1 + clock) / FLASH_BAUD_RATE);
flash
}
/// typical: `200_000_000` Hz
fn enable_clocks(clock: u32) {
let io_pll = IoPll::freq();
let divisor = ((clock - 1 + io_pll) / clock)
.max(1).min(63) as u8;
slcr::RegisterBlock::unlocked(|slcr| {
slcr.lqspi_clk_ctrl.write(
slcr::LqspiClkCtrl::zeroed()
.src_sel(slcr::PllSource::IoPll)
.divisor(divisor)
.clkact(true)
);
});
}
fn setup_signals() {
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)
);
// Option: Add Second Device Chip Select
// 4. Configure MIO pin 0 for chip select 1 output.
slcr.mio_pin_00.write(
slcr::MioPin00::zeroed()
.l0_sel(true)
.io_type(slcr::IoBufferType::Lvcmos18)
);
// Option: Add Second Serial Clock
// 5. Configure MIO pin 9 for serial clock 1 output.
slcr.mio_pin_09.write(
slcr::MioPin09::zeroed()
.l0_sel(true)
.io_type(slcr::IoBufferType::Lvcmos18)
.pullup(true)
);
// Option: Add 4-bit Data
// 6. Configure MIO pins 10 through 13 for I/O.
slcr.mio_pin_10.write(
slcr::MioPin10::zeroed()
.l0_sel(true)
.io_type(slcr::IoBufferType::Lvcmos18)
.pullup(true)
);
slcr.mio_pin_11.write(
slcr::MioPin11::zeroed()
.l0_sel(true)
.io_type(slcr::IoBufferType::Lvcmos18)
.pullup(true)
);
slcr.mio_pin_12.write(
slcr::MioPin12::zeroed()
.l0_sel(true)
.io_type(slcr::IoBufferType::Lvcmos18)
.pullup(true)
);
slcr.mio_pin_13.write(
slcr::MioPin13::zeroed()
.l0_sel(true)
.io_type(slcr::IoBufferType::Lvcmos18)
.pullup(true)
);
// Option: Add Feedback Output Clock
// 7. Configure MIO pin 8 for feedback clock.
slcr.mio_pin_08.write(
slcr::MioPin08::zeroed()
.l0_sel(true)
.io_type(slcr::IoBufferType::Lvcmos18)
.pullup(true)
);
});
}
fn reset() {
slcr::RegisterBlock::unlocked(|slcr| {
slcr.lqspi_rst_ctrl.write(
slcr::LqspiRstCtrl::zeroed()
.ref_rst(true)
.cpu1x_rst(true)
);
slcr.lqspi_rst_ctrl.write(
slcr::LqspiRstCtrl::zeroed()
);
});
}
fn configure(&mut self, divider: u32) {
// Disable
self.regs.enable.write(
regs::Enable::zeroed()
);
self.disable_interrupts();
self.regs.lqspi_cfg.write(
regs::LqspiCfg::zeroed()
);
self.clear_rx_fifo();
self.clear_interrupt_status();
// 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.write(regs::Config::zeroed()
.baud_rate_div(baud_rate_div as u8)
.mode_sel(true)
.leg_flsh(true)
.holdb_dr(true)
// 32 bits TX FIFO width
.fifo_width(0b11)
);
// Initialize RX/TX pipes thresholds
unsafe {
self.regs.rx_thres.write(1);
self.regs.tx_thres.write(1);
}
}
pub fn linear_addressing_mode(self) -> Flash<LinearAddressing> {
// Set manual start enable to auto mode.
// Assert the chip select.
self.regs.config.modify(|_, w| w
.man_start_en(false)
.pcs(false)
.manual_cs(false)
);
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
// Quad I/O Fast Read
.inst_code(INST_4IO_FAST_READ)
.dummy_mask(0x2)
.mode_en(false)
.mode_bits(0xFF)
// 2 devices
.two_mem(true)
.u_page(false)
// Quad SPI mode
.lq_mode(true)
);
self.regs.enable.write(
regs::Enable::zeroed()
.spi_en(true)
);
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)
.endian(true)
);
self.regs.lqspi_cfg.write(regs::LqspiCfg::zeroed()
// Quad I/O Fast Read
.inst_code(INST_READ)
.dummy_mask(0x2)
.mode_en(false)
.mode_bits(0xFF)
// 2 devices
.two_mem(true)
.u_page(chip_index != 0)
// Quad SPI mode
.lq_mode(false)
);
self.transition()
}
}
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 {
0xFC00_0000 as *mut _
}
pub fn size(&self) -> usize {
2 * (SINGLE_CAPACITY as usize)
}
}
impl Flash<Manual> {
pub fn stop(self) -> Flash<()> {
self.transition()
}
pub fn read_reg<R: SpiFlashRegister>(&mut self) -> R {
let args = Some(R::inst_code());
let transfer = self.transfer(args.into_iter(), 2)
.bytes_transfer();
R::new(transfer.skip(1).next().unwrap())
}
pub fn read_reg_until<R, F, A>(&mut self, f: F) -> A
where
R: SpiFlashRegister,
F: Fn(R) -> Option<A>,
{
let mut result = None;
while result.is_none() {
let args = Some(R::inst_code());
for b in self.transfer(args.into_iter(), 32)
.bytes_transfer().skip(1) {
result = f(R::new(b));
if result.is_none() {
break;
}
}
}
result.unwrap()
}
/// Status Register-1 remains `0x00` immediately after invoking a command.
fn wait_while_sr1_zeroed(&mut self) -> SR1 {
self.read_reg_until::<SR1, _, SR1>(|sr1|
if sr1.is_zeroed() {
None
} else {
Some(sr1)
}
)
}
/// Read Identification
pub fn rdid(&mut self) -> core::iter::Skip<BytesTransfer<Transfer<core::option::IntoIter<u32>, u32>>> {
let args = Some((INST_RDID as u32) << 24);
self.transfer(args.into_iter(), 0x44)
.bytes_transfer().skip(1)
}
/// Read flash data
pub fn read(&mut self, offset: u32, len: usize
) -> core::iter::Take<core::iter::Skip<BytesTransfer<Transfer<core::option::IntoIter<u32>, u32>>>>
{
let args = Some(((INST_READ as u32) << 24) | (offset as u32));
self.transfer(args.into_iter(), len + 6)
.bytes_transfer().skip(6).take(len)
}
pub fn erase(&mut self, offset: u32) {
let args = Some(((INST_BE_4K as u32) << 24) | (offset as u32));
self.transfer(args.into_iter(), 4);
let sr1 = self.wait_while_sr1_zeroed();
if sr1.e_err() {
error!("E_ERR");
} else if sr1.p_err() {
error!("P_ERR");
} else if sr1.wip() {
info!("Erase in progress");
while self.read_reg::<SR1>().wip() {
print!(".");
}
println!("");
} else {
warn!("erased? sr1={:02X}", sr1.inner);
}
}
pub fn program<I: Iterator<Item=u32>>(&mut self, offset: u32, data: I) {
{
let len = 4 + 4 * data.size_hint().0;
let args = Some(SpiWord::W32(((INST_PP as u32) << 24) | (offset as u32))).into_iter()
.chain(data.map(SpiWord::W32));
self.transfer(args, len);
}
// let sr1 = self.wait_while_sr1_zeroed();
let sr1 = self.read_reg::<SR1>();
if sr1.e_err() {
error!("E_ERR");
} else if sr1.p_err() {
error!("P_ERR");
} else if sr1.wip() {
info!("Program in progress");
while self.read_reg::<SR1>().wip() {
print!(".");
}
println!("");
} else {
warn!("programmed? sr1={:02X}", sr1.inner);
}
}
pub fn write_enabled<F: Fn(&mut Self) -> R, R>(&mut self, f: F) -> R {
// Write Enable
let args = Some(INST_WREN);
self.transfer(args.into_iter(), 1);
self.regs.gpio.modify(|_, w| w.wp_n(true));
let sr1 = self.wait_while_sr1_zeroed();
if !sr1.wel() {
panic!("Cannot write-enable flash");
}
let result = f(self);
// Write Disable
let args = Some(INST_WRDI);
self.transfer(args.into_iter(), 1);
self.regs.gpio.modify(|_, w| w.wp_n(false));
result
}
pub fn transfer<'s: 't, 't, Args, W>(&'s mut self, args: Args, len: usize) -> Transfer<'t, Args, W>
where
Args: Iterator<Item = W>,
W: Into<SpiWord>,
{
Transfer::new(self, args, len)
}
pub fn dump(&mut self, label: &'_ str, inst_code: u8) {
print!("{}:", label);
let args = Some(u32::from(inst_code) << 24);
for b in self.transfer(args.into_iter(), 32).bytes_transfer() {
print!(" {:02X}", b);
}
println!("");
}
}

View File

@ -1,122 +0,0 @@
use volatile_register::{RO, WO, RW};
use libregister::{register, register_at, register_bit, register_bits};
#[repr(C)]
pub struct RegisterBlock {
pub config: Config,
pub intr_status: IntrStatus,
pub intr_en: IntrEn,
pub intr_dis: IntrDis,
pub intr_mask: RO<u32>,
pub enable: Enable,
pub delay: RW<u32>,
pub txd0: WO<u32>,
pub rx_data: RO<u32>,
pub slave_idle_count: RW<u32>,
pub tx_thres: RW<u32>,
pub rx_thres: RW<u32>,
pub gpio: QspiGpio,
pub _unused1: RO<u32>,
pub lpbk_dly_adj: RW<u32>,
pub _unused2: [RO<u32>; 17],
pub txd1: WO<u32>,
pub txd2: WO<u32>,
pub txd3: WO<u32>,
pub _unused3: [RO<u32>; 5],
pub lqspi_cfg: LqspiCfg,
pub lqspi_sts: RW<u32>,
pub _unused4: [RO<u32>; 21],
pub mod_id: RW<u32>,
}
const BASE_ADDRESS: u32 = 0xE000D000;
register_at!(RegisterBlock, 0xE000D000, qspi);
register!(config, Config, RW, u32);
register_bit!(config,
/// Enables master mode
mode_sel, 0);
register_bit!(config,
/// Clock polarity low/high
clk_pol, 1);
register_bit!(config,
/// Clock phase
clk_ph, 2);
register_bits!(config,
/// divider = 2 ** (1 + baud_rate_div)
baud_rate_div, u8, 3, 5);
register_bits!(config,
/// Must be set to 0b11
fifo_width, u8, 6, 7);
register_bit!(config,
/// Must be 0
ref_clk, 8);
register_bit!(config,
/// Peripheral Chip Select Line
pcs, 10);
register_bit!(config,
/// false: auto mode, true: manual CS mode
manual_cs, 14);
register_bit!(config,
/// false: auto mode, true: enables manual start enable
man_start_en, 15);
register_bit!(config,
/// false: auto mode, true: enables manual start command
man_start_com, 16);
register_bit!(config, holdb_dr, 19);
register_bit!(config,
/// false: little, true: endian
endian, 26);
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_thres
tx_fifo_not_full, 2);
register_bit!(intr_status, tx_fifo_full, 3);
register_bit!(intr_status,
/// >= rx_thres
rx_fifo_not_empty, 4);
register_bit!(intr_status, rx_fifo_full, 5);
register_bit!(intr_status, tx_fifo_underflow, 6);
register!(intr_en, IntrEn, WO, u32);
register_bit!(intr_en, rx_overflow, 0);
register_bit!(intr_en, tx_fifo_not_full, 2);
register_bit!(intr_en, tx_fifo_full, 3);
register_bit!(intr_en, rx_fifo_not_empty, 4);
register_bit!(intr_en, rx_fifo_full, 5);
register_bit!(intr_en, tx_fifo_underflow, 6);
register!(intr_dis, IntrDis, WO, u32);
register_bit!(intr_dis, rx_overflow, 0);
register_bit!(intr_dis, tx_fifo_not_full, 2);
register_bit!(intr_dis, tx_fifo_full, 3);
register_bit!(intr_dis, rx_fifo_not_empty, 4);
register_bit!(intr_dis, rx_fifo_full, 5);
register_bit!(intr_dis, tx_fifo_underflow, 6);
register!(enable, Enable, RW, u32);
register_bit!(enable, spi_en, 0);
// named to avoid confusion with normal gpio
register!(qspi_gpio, QspiGpio, RW, u32);
register_bit!(qspi_gpio,
/// Write protect pin (inverted)
wp_n, 0);
register!(lqspi_cfg, LqspiCfg, RW, u32);
register_bits!(lqspi_cfg, inst_code, u8, 0, 7);
register_bits!(lqspi_cfg, dummy_mask, 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);

View File

@ -1,62 +0,0 @@
use bit_field::BitField;
pub trait SpiFlashRegister {
fn inst_code() -> u8;
fn new(src: u8) -> Self;
}
macro_rules! u8_register {
($name: ident, $doc: tt, $inst_code: expr) => {
#[derive(Clone)]
#[doc=$doc]
pub struct $name {
pub inner: u8,
}
impl SpiFlashRegister for $name {
fn inst_code() -> u8 {
$inst_code
}
fn new(src: u8) -> Self {
$name {
inner: src,
}
}
}
impl $name {
#[allow(unused)]
pub fn is_zeroed(&self) -> bool {
self.inner == 0
}
}
};
}
u8_register!(CR, "Configuration Register", 0x35);
u8_register!(SR1, "Status Register-1", 0x05);
impl SR1 {
/// Write In Progress
pub fn wip(&self) -> bool {
self.inner.get_bit(0)
}
/// Write Enable Latch
pub fn wel(&self) -> bool {
self.inner.get_bit(1)
}
/// Erase Error Occurred
pub fn e_err(&self) -> bool {
self.inner.get_bit(5)
}
/// Programming Error Occurred
pub fn p_err(&self) -> bool {
self.inner.get_bit(6)
}
}
u8_register!(SR2, "Status Register-2", 0x07);
u8_register!(BA, "Bank Address Register", 0xB9);

View File

@ -1,125 +0,0 @@
use libregister::{RegisterR, RegisterW, RegisterRW};
use super::regs;
use super::{SpiWord, Flash, Manual};
pub struct Transfer<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> {
flash: &'a mut Flash<Manual>,
args: Args,
sent: usize,
received: usize,
len: usize,
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Transfer<'a, Args, W> {
pub fn new(flash: &'a mut Flash<Manual>, args: Args, len: usize) -> Self {
flash.regs.config.modify(|_, w| w.pcs(false));
flash.regs.enable.write(
regs::Enable::zeroed()
.spi_en(true)
);
let mut xfer = Transfer {
flash,
args,
sent: 0,
received: 0,
len,
};
xfer.fill_tx_fifo();
xfer.flash.regs.config.modify(|_, w| w.man_start_com(true));
xfer
}
fn fill_tx_fifo(&mut self) {
while self.sent < self.len && !self.flash.regs.intr_status.read().tx_fifo_full() {
let arg = self.args.next()
.map(|n| n.into())
.unwrap_or(SpiWord::W32(0));
match arg {
SpiWord::W32(w) => {
// println!("txd0 {:08X}", w);
unsafe {
self.flash.regs.txd0.write(w);
}
self.sent += 4;
}
// Only txd0 can be used without flushing
_ => {
if !self.flash.regs.intr_status.read().tx_fifo_not_full() {
// Flush if necessary
self.flash.wait_tx_fifo_flush();
}
match arg {
SpiWord::W8(w) => {
// println!("txd1 {:02X}", w);
unsafe {
self.flash.regs.txd1.write(u32::from(w) << 24);
}
self.sent += 1;
}
SpiWord::W16(w) => {
unsafe {
self.flash.regs.txd2.write(u32::from(w) << 16);
}
self.sent += 2;
}
SpiWord::W24(w) => {
unsafe {
self.flash.regs.txd3.write(w << 8);
}
self.sent += 3;
}
SpiWord::W32(_) => unreachable!(),
}
self.flash.wait_tx_fifo_flush();
}
}
}
}
fn can_read(&mut self) -> bool {
self.flash.regs.intr_status.read().rx_fifo_not_empty()
}
fn read(&mut self) -> u32 {
let rx = self.flash.regs.rx_data.read();
self.received += 4;
rx
}
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Drop for Transfer<'a, Args, W> {
fn drop(&mut self) {
// Discard remaining rx_data
while self.can_read() {
self.read();
}
// Stop
self.flash.regs.enable.write(
regs::Enable::zeroed()
.spi_en(false)
);
self.flash.regs.config.modify(|_, w| w
.pcs(true)
.man_start_com(false)
);
}
}
impl<'a, Args: Iterator<Item = W>, W: Into<SpiWord>> Iterator for Transfer<'a, Args, W> {
type Item = u32;
fn next<'s>(&'s mut self) -> Option<u32> {
if self.received >= self.len {
return None;
}
self.fill_tx_fifo();
while !self.can_read() {}
Some(self.read())
}
}

View File

@ -16,7 +16,6 @@ pub mod axi_gp;
pub mod ddr;
pub mod mpcore;
pub mod gic;
pub mod flash;
pub mod time;
pub mod timer;
pub mod sdio;