artiq/artiq/firmware/libboard_misoc/spiflash.rs

122 lines
3.0 KiB
Rust

use core::cmp;
use csr;
pub const SECTOR_SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize;
pub const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize;
const PAGE_MASK: usize = PAGE_SIZE - 1;
const CMD_PP: u8 = 0x02;
// const CMD_WRDI: u8 = 0x04;
const CMD_RDSR: u8 = 0x05;
const CMD_WREN: u8 = 0x06;
const CMD_SE: u8 = 0xd8;
const PIN_CLK: u8 = 1 << 1;
const PIN_CS_N: u8 = 1 << 2;
const PIN_DQ_I: u8 = 1 << 3;
const SR_WIP: u8 = 1;
unsafe fn write_byte(mut byte: u8) {
csr::spiflash::bitbang_write(0);
for _ in 0..8 {
csr::spiflash::bitbang_write((byte & 0x80) >> 7);
csr::spiflash::bitbang_write((byte & 0x80) >> 7 | PIN_CLK);
byte <<= 1;
}
csr::spiflash::bitbang_write(0);
}
unsafe fn write_addr(mut addr: usize) {
csr::spiflash::bitbang_write(0);
for _ in 0..24 {
csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8);
csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8 | PIN_CLK);
addr <<= 1;
}
csr::spiflash::bitbang_write(0);
}
fn wait_until_ready() {
unsafe {
loop {
let mut sr = 0;
write_byte(CMD_RDSR);
for _ in 0..8 {
sr <<= 1;
csr::spiflash::bitbang_write(PIN_DQ_I | PIN_CLK);
sr |= csr::spiflash::miso_read();
csr::spiflash::bitbang_write(PIN_DQ_I);
}
csr::spiflash::bitbang_write(0);
csr::spiflash::bitbang_write(PIN_CS_N);
if sr & SR_WIP == 0 {
return
}
}
}
}
pub unsafe fn erase_sector(addr: usize) {
let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1);
csr::spiflash::bitbang_en_write(1);
wait_until_ready();
write_byte(CMD_WREN);
csr::spiflash::bitbang_write(PIN_CS_N);
write_byte(CMD_SE);
write_addr(sector_addr);
csr::spiflash::bitbang_write(PIN_CS_N);
wait_until_ready();
csr::spiflash::bitbang_en_write(0);
}
unsafe fn write_page(addr: usize, data: &[u8]) {
csr::spiflash::bitbang_en_write(1);
wait_until_ready();
write_byte(CMD_WREN);
csr::spiflash::bitbang_write(PIN_CS_N);
write_byte(CMD_PP);
write_addr(addr);
for &byte in data {
write_byte(byte)
}
csr::spiflash::bitbang_write(PIN_CS_N);
csr::spiflash::bitbang_write(0);
wait_until_ready();
csr::spiflash::bitbang_en_write(0);
}
pub unsafe fn write(mut addr: usize, mut data: &[u8]) {
if addr & PAGE_MASK != 0 {
let size = cmp::min((PAGE_SIZE - (addr & PAGE_MASK)) as usize, data.len());
write_page(addr, &data[..size]);
addr += size;
data = &data[size..];
}
while data.len() > 0 {
let size = cmp::min(PAGE_SIZE as usize, data.len());
write_page(addr, &data[..size]);
addr += size;
data = &data[size..];
}
}
#[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))]
pub unsafe fn reload () -> ! {
csr::icap::iprog_write(1);
loop {}
}