From 3180f1c3f766d8113763ba3223e2cddaf71b219e Mon Sep 17 00:00:00 2001 From: Astro Date: Thu, 21 Nov 2019 00:14:09 +0100 Subject: [PATCH] zynq::flash: begin driver implementation --- src/zynq/flash/mod.rs | 67 ++++++++++++++++++++++++++++++++++++ src/zynq/flash/regs.rs | 78 ++++++++++++++++++++++++++++++++++++++++++ src/zynq/mod.rs | 1 + src/zynq/slcr.rs | 13 +++++-- 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 src/zynq/flash/mod.rs create mode 100644 src/zynq/flash/regs.rs diff --git a/src/zynq/flash/mod.rs b/src/zynq/flash/mod.rs new file mode 100644 index 0000000..284fcd2 --- /dev/null +++ b/src/zynq/flash/mod.rs @@ -0,0 +1,67 @@ +//! Quad-SPI Flash Controller + +use crate::regs::{RegisterW, RegisterRW}; +use super::slcr; +use super::clocks::CpuClocks; + +pub mod regs; + +/// Flash Interface Driver +pub struct Flash { + regs: &'static mut regs::RegisterBlock, +} + +impl Flash { + pub fn new(clock: u32) -> Self { + Self::enable_clocks(clock); + Self::setup_signals(); + Self::reset(); + + let regs = regs::RegisterBlock::qspi(); + let mut flash = Flash { regs }; + flash.configure(); + flash + } + + fn enable_clocks(clock: u32) { + let io_pll = CpuClocks::get().io; + 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() { + // TODO + } + + 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) { + self.regs.config.modify(|_, w| w + .baud_rate_div(4 /* TODO */) + .mode_sel(true) + .leg_flsh(true) + .endian(false) + .fifo_width(0b11) + ); + } +} diff --git a/src/zynq/flash/regs.rs b/src/zynq/flash/regs.rs new file mode 100644 index 0000000..65ee0cc --- /dev/null +++ b/src/zynq/flash/regs.rs @@ -0,0 +1,78 @@ +use volatile_register::{RO, WO, RW}; + +use crate::{register, register_bit, register_bits, register_bits_typed}; + +#[repr(C)] +pub struct RegisterBlock { + pub config: Config, + pub intr_status: RW, + pub intr_en: RW, + pub intr_dis: RW, + pub intr_mask: RO, + pub enable: RW, + pub delay: RW, + pub txd0: WO, + pub rx_data: RO, + pub slave_idle_count: RW, + pub tx_thres: RW, + pub rx_thes: RW, + pub gpio: RW, + pub _unused1: RO, + pub lpbk_dly_adj: RW, + pub _unused2: [RO; 17], + pub txd1: WO, + pub txd2: WO, + pub txd3: WO, + pub _unused3: [RO; 5], + pub lqspi_cfg: RW, + pub lqspi_sts: RW, + pub _unused4: [RO; 21], + pub mod_id: RW, +} + +impl RegisterBlock { + const BASE_ADDRESS: *mut Self = 0xE000D000 as *mut _; + + pub fn qspi() -> &'static mut Self { + unsafe { &mut *Self::BASE_ADDRESS } + } +} + +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, + /// divisor = 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); diff --git a/src/zynq/mod.rs b/src/zynq/mod.rs index d4625d0..0d72644 100644 --- a/src/zynq/mod.rs +++ b/src/zynq/mod.rs @@ -6,3 +6,4 @@ pub mod axi_hp; pub mod axi_gp; pub mod ddr; pub mod mpcore; +pub mod flash; diff --git a/src/zynq/slcr.rs b/src/zynq/slcr.rs index a0c84e6..f372b6e 100644 --- a/src/zynq/slcr.rs +++ b/src/zynq/slcr.rs @@ -84,7 +84,7 @@ pub struct RegisterBlock { pub gem0_clk_ctrl: GemClkCtrl, pub gem1_clk_ctrl: GemClkCtrl, pub smc_clk_ctrl: RW, - pub lqspi_clk_ctrl: RW, + pub lqspi_clk_ctrl: LqspiClkCtrl, pub sdio_clk_ctrl: RW, pub uart_clk_ctrl: UartClkCtrl, pub spi_clk_ctrl: RW, @@ -124,7 +124,7 @@ pub struct RegisterBlock { pub i2c_rst_ctrl: RW, pub uart_rst_ctrl: UartRstCtrl, pub gpio_rst_ctrl: RW, - pub lqspi_rst_ctrl: RW, + pub lqspi_rst_ctrl: LqspiRstCtrl, pub smc_rst_ctrl: RW, pub ocm_rst_ctrl: RW, reserved4: [u32; 1], @@ -440,6 +440,15 @@ impl UartRstCtrl { } } +register!(lqspi_clk_ctrl, LqspiClkCtrl, RW, u32); +register_bit!(lqspi_clk_ctrl, clkact, 0); +register_bits_typed!(lqspi_clk_ctrl, src_sel, u8, PllSource, 4, 5); +register_bits!(lqspi_clk_ctrl, divisor, u8, 8, 13); + +register!(lqspi_rst_ctrl, LqspiRstCtrl, RW, u32); +register_bit!(lqspi_rst_ctrl, ref_rst, 1); +register_bit!(lqspi_rst_ctrl, cpu1x_rst, 0); + register!(a9_cpu_rst_ctrl, A9CpuRstCtrl, RW, u32); register_bit!(a9_cpu_rst_ctrl, peri_rst, 8); register_bit!(a9_cpu_rst_ctrl, a9_clkstop1, 5);