spiflash: BB write support
This commit is contained in:
parent
bab6bb7c4a
commit
edb1622668
|
@ -3,6 +3,7 @@ from migen.bus.transactions import *
|
|||
from migen.bus import wishbone
|
||||
from migen.genlib.misc import timeline
|
||||
from migen.genlib.record import Record
|
||||
from migen.bank.description import AutoCSR, CSRStorage, CSRStatus
|
||||
|
||||
_FAST_READ = 0x0b
|
||||
_DIOFR = 0xbb
|
||||
|
@ -22,27 +23,35 @@ def _format_cmd(cmd, spi_width):
|
|||
c &= ~(1<<(b*spi_width))
|
||||
return c
|
||||
|
||||
class SpiFlash(Module):
|
||||
class SpiFlash(Module, AutoCSR):
|
||||
def __init__(self, pads, dummy=15, div=2):
|
||||
"""
|
||||
Simple read-only SPI flash, e.g. N25Q128 on the LX9 Microboard.
|
||||
Simple SPI flash, e.g. N25Q128 on the LX9 Microboard.
|
||||
|
||||
Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
|
||||
Read). Only supports mode0 (cpol=0, cpha=0).
|
||||
Supports software bitbanging (for write, erase, or other commands).
|
||||
"""
|
||||
self.bus = bus = wishbone.Interface()
|
||||
spi_width = flen(pads.dq)
|
||||
self.bitbang = CSRStorage(4)
|
||||
self.miso = CSRStatus()
|
||||
self.bitbang_en = CSRStorage()
|
||||
|
||||
##
|
||||
|
||||
cs_n = Signal(reset=1)
|
||||
clk = Signal()
|
||||
dq_oe = Signal()
|
||||
wbone_width = flen(bus.dat_r)
|
||||
spi_width = flen(pads.dq)
|
||||
|
||||
cmd_params = {
|
||||
|
||||
read_cmd_params = {
|
||||
4: (_format_cmd(_QIOFR, 4), 4*8),
|
||||
2: (_format_cmd(_DIOFR, 2), 2*8),
|
||||
1: (_format_cmd(_FAST_READ, 1), 1*8)
|
||||
}
|
||||
cmd, cmd_width = cmd_params[spi_width]
|
||||
read_cmd, cmd_width = read_cmd_params[spi_width]
|
||||
addr_width = 24
|
||||
|
||||
pads.cs_n.reset = 1
|
||||
|
@ -51,26 +60,43 @@ class SpiFlash(Module):
|
|||
self.specials.dq = dq.get_tristate(pads.dq)
|
||||
|
||||
sr = Signal(max(cmd_width, addr_width, wbone_width))
|
||||
dqs = Replicate(1, spi_width-1)
|
||||
|
||||
self.comb += [
|
||||
bus.dat_r.eq(sr),
|
||||
dq.o.eq(sr[-spi_width:]),
|
||||
If(self.bitbang_en.storage,
|
||||
pads.clk.eq(self.bitbang.storage[1]),
|
||||
pads.cs_n.eq(self.bitbang.storage[2]),
|
||||
dq.o.eq(Cat(self.bitbang.storage[0], dqs)),
|
||||
If(self.bitbang.storage[3],
|
||||
dq.oe.eq(0)
|
||||
).Else(
|
||||
dq.oe.eq(1)
|
||||
),
|
||||
If(self.bitbang.storage[1],
|
||||
self.miso.status.eq(dq.i[-1])
|
||||
)
|
||||
).Else(
|
||||
pads.clk.eq(clk),
|
||||
pads.cs_n.eq(cs_n),
|
||||
dq.o.eq(sr[-spi_width:]),
|
||||
dq.oe.eq(dq_oe)
|
||||
)
|
||||
]
|
||||
|
||||
if div == 1:
|
||||
i = 0
|
||||
self.comb += pads.clk.eq(~ClockSignal())
|
||||
self.sync += sr.eq(Cat(dq.i, sr[:-spi_width]))
|
||||
if div < 2:
|
||||
raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
|
||||
else:
|
||||
i = Signal(max=div)
|
||||
dqi = Signal(spi_width)
|
||||
self.sync += [
|
||||
If(i == div//2 - 1,
|
||||
pads.clk.eq(1),
|
||||
clk.eq(1),
|
||||
dqi.eq(dq.i),
|
||||
),
|
||||
If(i == div - 1,
|
||||
i.eq(0),
|
||||
pads.clk.eq(0),
|
||||
clk.eq(0),
|
||||
sr.eq(Cat(dqi, sr[:-spi_width]))
|
||||
).Else(
|
||||
i.eq(i + 1),
|
||||
|
@ -82,13 +108,13 @@ class SpiFlash(Module):
|
|||
|
||||
seq = [
|
||||
(cmd_width//spi_width*div,
|
||||
[dq.oe.eq(1), pads.cs_n.eq(0), sr[-cmd_width:].eq(cmd)]),
|
||||
[dq_oe.eq(1), cs_n.eq(0), sr[-cmd_width:].eq(read_cmd)]),
|
||||
(addr_width//spi_width*div,
|
||||
[sr[-addr_width:].eq(Cat(z, bus.adr))]),
|
||||
((dummy + wbone_width//spi_width)*div,
|
||||
[dq.oe.eq(0)]),
|
||||
[dq_oe.eq(0)]),
|
||||
(1,
|
||||
[bus.ack.eq(1), pads.cs_n.eq(1)]),
|
||||
[bus.ack.eq(1), cs_n.eq(1)]),
|
||||
(div, # tSHSL!
|
||||
[bus.ack.eq(0)]),
|
||||
(0,
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef __SPIFLASH_H
|
||||
#define __SPIFLASH_H
|
||||
|
||||
void write_to_flash_page(unsigned int addr, unsigned char *c, unsigned int len);
|
||||
void erase_flash_sector(unsigned int addr);
|
||||
|
||||
#endif /* __SPIFLASH_H */
|
|
@ -1,7 +1,7 @@
|
|||
MSCDIR=../..
|
||||
include $(MSCDIR)/software/common.mak
|
||||
|
||||
OBJECTS=exception.o libc.o errno.o crc16.o crc32.o console.o system.o id.o uart.o time.o qsort.o strtod.o
|
||||
OBJECTS=exception.o libc.o errno.o crc16.o crc32.o console.o system.o id.o uart.o time.o qsort.o strtod.o spiflash.o
|
||||
|
||||
all: crt0-$(CPU).o libbase.a libbase-nofloat.a
|
||||
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
#include <generated/csr.h>
|
||||
|
||||
#include <spiflash.h>
|
||||
|
||||
#ifdef SPIFLASH_BASE
|
||||
|
||||
#define PAGE_PROGRAM_CMD (0x02)
|
||||
#define WRDI_CMD (0x04)
|
||||
#define RDSR_CMD (0x05)
|
||||
#define WREN_CMD (0x06)
|
||||
#define SE_CMD (0x20)
|
||||
|
||||
#define BITBANG_CLK (1 << 1)
|
||||
#define BITBANG_CS_N (1 << 2)
|
||||
#define BITBANG_DQ_INPUT (1 << 3)
|
||||
|
||||
#define SR_WIP (1)
|
||||
|
||||
#define PAGE_SIZE (256)
|
||||
#define PAGE_MASK (PAGE_SIZE - 1)
|
||||
#define SECTOR_SIZE (4096)
|
||||
#define SECTOR_MASK (SECTOR_SIZE - 1)
|
||||
|
||||
static void flash_write_byte(unsigned char b);
|
||||
static void flash_write_addr(unsigned int addr);
|
||||
static void wait_for_device_ready(void);
|
||||
|
||||
#define min(a,b) (a>b?b:a)
|
||||
|
||||
static void flash_write_byte(unsigned char b)
|
||||
{
|
||||
int i;
|
||||
spiflash_bitbang_write(0); // ~CS_N ~CLK
|
||||
|
||||
for(i = 0; i < 8; i++, b <<= 1) {
|
||||
|
||||
spiflash_bitbang_write((b & 0x80) >> 7);
|
||||
spiflash_bitbang_write(((b & 0x80) >> 7) | BITBANG_CLK);
|
||||
}
|
||||
|
||||
spiflash_bitbang_write(0); // ~CS_N ~CLK
|
||||
|
||||
}
|
||||
|
||||
static void flash_write_addr(unsigned int addr)
|
||||
{
|
||||
int i;
|
||||
spiflash_bitbang_write(0);
|
||||
|
||||
for(i = 0; i < 24; i++, addr <<= 1) {
|
||||
spiflash_bitbang_write((addr & 0x800000) >> 23);
|
||||
spiflash_bitbang_write(((addr & 0x800000) >> 23) | BITBANG_CLK);
|
||||
}
|
||||
|
||||
spiflash_bitbang_write(0);
|
||||
}
|
||||
|
||||
static void wait_for_device_ready(void)
|
||||
{
|
||||
unsigned char sr;
|
||||
unsigned char i;
|
||||
do {
|
||||
sr = 0;
|
||||
flash_write_byte(RDSR_CMD);
|
||||
spiflash_bitbang_write(BITBANG_DQ_INPUT);
|
||||
for(i = 0; i < 8; i++) {
|
||||
sr <<= 1;
|
||||
spiflash_bitbang_write(BITBANG_CLK | BITBANG_DQ_INPUT);
|
||||
sr |= spiflash_miso_read();
|
||||
spiflash_bitbang_write(0 | BITBANG_DQ_INPUT);
|
||||
}
|
||||
spiflash_bitbang_write(0);
|
||||
spiflash_bitbang_write(BITBANG_CS_N);
|
||||
} while(sr & SR_WIP);
|
||||
}
|
||||
|
||||
void erase_flash_sector(unsigned int addr)
|
||||
{
|
||||
unsigned int sector_addr = addr & ~(SECTOR_MASK);
|
||||
|
||||
spiflash_bitbang_en_write(1);
|
||||
|
||||
wait_for_device_ready();
|
||||
|
||||
flash_write_byte(WREN_CMD);
|
||||
spiflash_bitbang_write(BITBANG_CS_N);
|
||||
|
||||
flash_write_byte(SE_CMD);
|
||||
flash_write_addr(sector_addr);
|
||||
spiflash_bitbang_write(BITBANG_CS_N);
|
||||
|
||||
wait_for_device_ready();
|
||||
|
||||
spiflash_bitbang_en_write(0);
|
||||
}
|
||||
|
||||
void write_to_flash_page(unsigned int addr, unsigned char *c, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if(len > PAGE_SIZE)
|
||||
len = PAGE_SIZE;
|
||||
|
||||
spiflash_bitbang_en_write(1);
|
||||
|
||||
wait_for_device_ready();
|
||||
|
||||
flash_write_byte(WREN_CMD);
|
||||
spiflash_bitbang_write(BITBANG_CS_N);
|
||||
flash_write_byte(PAGE_PROGRAM_CMD);
|
||||
flash_write_addr((unsigned int)addr);
|
||||
for(i = 0; i < len; i++)
|
||||
flash_write_byte(*c++);
|
||||
|
||||
spiflash_bitbang_write(BITBANG_CS_N);
|
||||
spiflash_bitbang_write(0);
|
||||
|
||||
wait_for_device_ready();
|
||||
|
||||
spiflash_bitbang_en_write(0);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -64,7 +64,8 @@ class BaseSoC(SDRAMSoC):
|
|||
default_platform = "kc705"
|
||||
|
||||
csr_map = {
|
||||
"ddrphy": 10,
|
||||
"spiflash": 10,
|
||||
"ddrphy": 11,
|
||||
}
|
||||
csr_map.update(SDRAMSoC.csr_map)
|
||||
|
||||
|
|
|
@ -60,6 +60,11 @@ class _CRG(Module):
|
|||
class BaseSoC(SDRAMSoC):
|
||||
default_platform = "papilio_pro"
|
||||
|
||||
csr_map = {
|
||||
"spiflash": 10,
|
||||
}
|
||||
csr_map.update(SDRAMSoC.csr_map)
|
||||
|
||||
def __init__(self, platform, **kwargs):
|
||||
clk_freq = 80*1000*1000
|
||||
SDRAMSoC.__init__(self, platform, clk_freq,
|
||||
|
|
Loading…
Reference in New Issue