spiflash: BB write support

This commit is contained in:
Yann Sionneau 2014-11-27 23:10:24 +08:00 committed by Sebastien Bourdeauducq
parent bab6bb7c4a
commit edb1622668
6 changed files with 179 additions and 17 deletions

View File

@ -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,

View File

@ -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 */

View File

@ -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

123
software/libbase/spiflash.c Normal file
View File

@ -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

View File

@ -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)

View File

@ -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,