From 0c49201be7fe21456fac1e17a74b902a912ead95 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 28 Feb 2018 16:46:16 +0000 Subject: [PATCH] firmware: add slave fpga serial load support based on whitequark's work in f95fb27 m-labs/artiq#813 --- artiq/firmware/Cargo.lock | 1 + artiq/firmware/libboard_artiq/Cargo.toml | 1 + artiq/firmware/libboard_artiq/lib.rs | 3 + artiq/firmware/libboard_artiq/slave_fpga.rs | 79 +++++++++++++++++++++ artiq/firmware/runtime/main.rs | 2 + 5 files changed, 86 insertions(+) create mode 100644 artiq/firmware/libboard_artiq/slave_fpga.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index ed834b273..5a3624209 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -41,6 +41,7 @@ dependencies = [ "board 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index d666b3ef0..149fe4efc 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -14,6 +14,7 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] bitflags = "1.0" +byteorder = { version = "1.0", default-features = false } log = { version = "0.4", default-features = false } board = { path = "../libboard" } diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 127a55db8..f7066a653 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate bitflags; +extern crate byteorder; #[macro_use] extern crate log; extern crate board; @@ -15,6 +16,8 @@ pub mod spi; #[cfg(has_si5324)] pub mod si5324; +#[cfg(has_slave_fpga)] +pub mod slave_fpga; #[cfg(has_serwb_phy_amc)] pub mod serwb; #[cfg(has_hmc830_7043)] diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs new file mode 100644 index 000000000..907f01043 --- /dev/null +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -0,0 +1,79 @@ +mod slave_fpga { + use board::{csr, clock}; + use core::slice; + use byteorder::{ByteOrder, BigEndian}; + + const CCLK_BIT: u8 = 1 << 0; + const DIN_BIT: u8 = 1 << 1; + const DONE_BIT: u8 = 1 << 2; + const INIT_B_BIT: u8 = 1 << 3; + const PROGRAM_B_BIT: u8 = 1 << 4; + + const GATEWARE: *mut u8 = csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8; + + unsafe fn shift_u8(data: u8) { + for i in 0..8 { + let mut bits: u8 = PROGRAM_B_BIT; + if data & (0x80 >> i) != 0 { + bits |= DIN_BIT; + } + // Without delays, this is about 6 MHz CCLK which is fine. + csr::slave_fpga_cfg::out_write(bits); + // clock::spin_us(1); + csr::slave_fpga_cfg::out_write(bits | CCLK_BIT); + // clock::spin_us(1); + } + } + + pub fn load() -> Result<(), &'static str> { + info!("Loading slave FPGA gateware..."); + + let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; + let magic = BigEndian::read_u32(&header[0..]); + let length = BigEndian::read_u32(&header[4..]) as usize; + + if magic != 0x53415231 { // "SAR1" + return Err("Slave FPGA gateware magic not found"); + } else if length > 0x220000 { + return Err("Slave FPGA gateware too large (corrupted?)"); + } + info!("Slave FPGA gateware length: 0x{:06x}", length); + + unsafe { + csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); + + csr::slave_fpga_cfg::out_write(0); + clock::spin_us(1); // TPROGRAM=250ns min + csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); + clock::spin_us(5_000); // TPL=5ms max + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { + return Err("Slave FPGA did not initialize."); + } + + for i in slice::from_raw_parts(GATEWARE.offset(8), length) { + shift_u8(*i); + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { + return Err("Slave FPGA error: INIT_B went low."); + } + } + + let t = clock::get_ms(); + while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { + if clock::get_ms() > t + 100 { + error!("Slave FPGA not DONE after loading"); + error!("Corrupt gateware? Slave FPGA in slave serial mode?"); + return Err("Slave FPGA not DONE"); + } + shift_u8(0xff); + } + shift_u8(0xff); // "Compensate for Special Startup Conditions" + csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); + } + + Ok(()) + } +} + +pub fn load() -> Result<(), &'static str> { + slave_fpga::load() +} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 21d0edf85..9cf3c11f3 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -72,6 +72,8 @@ fn startup() { _ => info!("UART log level set to INFO by default") } + #[cfg(has_slave_fpga)] + board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); #[cfg(has_serwb_phy_amc)] board_artiq::serwb::wait_init();