Skip to content
Permalink
Browse files

spiflash: BB write support

  • Loading branch information...
fallen authored and sbourdeauducq committed Nov 27, 2014
1 parent bab6bb7 commit edb16226682a36f21c31eeb81680ae66818c5d3a
Showing with 179 additions and 17 deletions.
  1. +41 −15 misoclib/spiflash/__init__.py
  2. +7 −0 software/include/base/spiflash.h
  3. +1 −1 software/libbase/Makefile
  4. +123 −0 software/libbase/spiflash.c
  5. +2 −1 targets/kc705.py
  6. +5 −0 targets/ppro.py
@@ -3,6 +3,7 @@
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 @@ def __init__(self, pads, dummy=15, div=2):
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 @@ def __init__(self, pads, dummy=15, div=2):

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 @@ def __init__(self, platform, clk_freq):
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,

0 comments on commit edb1622

Please sign in to comment.
You can’t perform that action at this time.