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.bus import wishbone
|
||||||
from migen.genlib.misc import timeline
|
from migen.genlib.misc import timeline
|
||||||
from migen.genlib.record import Record
|
from migen.genlib.record import Record
|
||||||
|
from migen.bank.description import AutoCSR, CSRStorage, CSRStatus
|
||||||
|
|
||||||
_FAST_READ = 0x0b
|
_FAST_READ = 0x0b
|
||||||
_DIOFR = 0xbb
|
_DIOFR = 0xbb
|
||||||
|
@ -22,27 +23,35 @@ def _format_cmd(cmd, spi_width):
|
||||||
c &= ~(1<<(b*spi_width))
|
c &= ~(1<<(b*spi_width))
|
||||||
return c
|
return c
|
||||||
|
|
||||||
class SpiFlash(Module):
|
class SpiFlash(Module, AutoCSR):
|
||||||
def __init__(self, pads, dummy=15, div=2):
|
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
|
Supports multi-bit pseudo-parallel reads (aka Dual or Quad I/O Fast
|
||||||
Read). Only supports mode0 (cpol=0, cpha=0).
|
Read). Only supports mode0 (cpol=0, cpha=0).
|
||||||
|
Supports software bitbanging (for write, erase, or other commands).
|
||||||
"""
|
"""
|
||||||
self.bus = bus = wishbone.Interface()
|
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)
|
wbone_width = flen(bus.dat_r)
|
||||||
spi_width = flen(pads.dq)
|
|
||||||
|
|
||||||
cmd_params = {
|
|
||||||
|
read_cmd_params = {
|
||||||
4: (_format_cmd(_QIOFR, 4), 4*8),
|
4: (_format_cmd(_QIOFR, 4), 4*8),
|
||||||
2: (_format_cmd(_DIOFR, 2), 2*8),
|
2: (_format_cmd(_DIOFR, 2), 2*8),
|
||||||
1: (_format_cmd(_FAST_READ, 1), 1*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
|
addr_width = 24
|
||||||
|
|
||||||
pads.cs_n.reset = 1
|
pads.cs_n.reset = 1
|
||||||
|
@ -51,26 +60,43 @@ class SpiFlash(Module):
|
||||||
self.specials.dq = dq.get_tristate(pads.dq)
|
self.specials.dq = dq.get_tristate(pads.dq)
|
||||||
|
|
||||||
sr = Signal(max(cmd_width, addr_width, wbone_width))
|
sr = Signal(max(cmd_width, addr_width, wbone_width))
|
||||||
|
dqs = Replicate(1, spi_width-1)
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
bus.dat_r.eq(sr),
|
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:
|
if div < 2:
|
||||||
i = 0
|
raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
|
||||||
self.comb += pads.clk.eq(~ClockSignal())
|
|
||||||
self.sync += sr.eq(Cat(dq.i, sr[:-spi_width]))
|
|
||||||
else:
|
else:
|
||||||
i = Signal(max=div)
|
i = Signal(max=div)
|
||||||
dqi = Signal(spi_width)
|
dqi = Signal(spi_width)
|
||||||
self.sync += [
|
self.sync += [
|
||||||
If(i == div//2 - 1,
|
If(i == div//2 - 1,
|
||||||
pads.clk.eq(1),
|
clk.eq(1),
|
||||||
dqi.eq(dq.i),
|
dqi.eq(dq.i),
|
||||||
),
|
),
|
||||||
If(i == div - 1,
|
If(i == div - 1,
|
||||||
i.eq(0),
|
i.eq(0),
|
||||||
pads.clk.eq(0),
|
clk.eq(0),
|
||||||
sr.eq(Cat(dqi, sr[:-spi_width]))
|
sr.eq(Cat(dqi, sr[:-spi_width]))
|
||||||
).Else(
|
).Else(
|
||||||
i.eq(i + 1),
|
i.eq(i + 1),
|
||||||
|
@ -82,13 +108,13 @@ class SpiFlash(Module):
|
||||||
|
|
||||||
seq = [
|
seq = [
|
||||||
(cmd_width//spi_width*div,
|
(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,
|
(addr_width//spi_width*div,
|
||||||
[sr[-addr_width:].eq(Cat(z, bus.adr))]),
|
[sr[-addr_width:].eq(Cat(z, bus.adr))]),
|
||||||
((dummy + wbone_width//spi_width)*div,
|
((dummy + wbone_width//spi_width)*div,
|
||||||
[dq.oe.eq(0)]),
|
[dq_oe.eq(0)]),
|
||||||
(1,
|
(1,
|
||||||
[bus.ack.eq(1), pads.cs_n.eq(1)]),
|
[bus.ack.eq(1), cs_n.eq(1)]),
|
||||||
(div, # tSHSL!
|
(div, # tSHSL!
|
||||||
[bus.ack.eq(0)]),
|
[bus.ack.eq(0)]),
|
||||||
(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=../..
|
MSCDIR=../..
|
||||||
include $(MSCDIR)/software/common.mak
|
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
|
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"
|
default_platform = "kc705"
|
||||||
|
|
||||||
csr_map = {
|
csr_map = {
|
||||||
"ddrphy": 10,
|
"spiflash": 10,
|
||||||
|
"ddrphy": 11,
|
||||||
}
|
}
|
||||||
csr_map.update(SDRAMSoC.csr_map)
|
csr_map.update(SDRAMSoC.csr_map)
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,11 @@ class _CRG(Module):
|
||||||
class BaseSoC(SDRAMSoC):
|
class BaseSoC(SDRAMSoC):
|
||||||
default_platform = "papilio_pro"
|
default_platform = "papilio_pro"
|
||||||
|
|
||||||
|
csr_map = {
|
||||||
|
"spiflash": 10,
|
||||||
|
}
|
||||||
|
csr_map.update(SDRAMSoC.csr_map)
|
||||||
|
|
||||||
def __init__(self, platform, **kwargs):
|
def __init__(self, platform, **kwargs):
|
||||||
clk_freq = 80*1000*1000
|
clk_freq = 80*1000*1000
|
||||||
SDRAMSoC.__init__(self, platform, clk_freq,
|
SDRAMSoC.__init__(self, platform, clk_freq,
|
||||||
|
|
Loading…
Reference in New Issue