core/spi_flash: re-integrate bitbang write support
This commit is contained in:
parent
5cc4c334d6
commit
cef2369015
|
@ -36,7 +36,7 @@ def _format_cmd(cmd, spi_width):
|
||||||
|
|
||||||
|
|
||||||
class SpiFlashDualQuad(Module, AutoCSR):
|
class SpiFlashDualQuad(Module, AutoCSR):
|
||||||
def __init__(self, pads, dummy=15, div=2, endianness="big"):
|
def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"):
|
||||||
"""
|
"""
|
||||||
Simple SPI flash.
|
Simple SPI flash.
|
||||||
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
|
||||||
|
@ -46,6 +46,11 @@ class SpiFlashDualQuad(Module, AutoCSR):
|
||||||
spi_width = len(pads.dq)
|
spi_width = len(pads.dq)
|
||||||
assert spi_width >= 2
|
assert spi_width >= 2
|
||||||
|
|
||||||
|
if with_bitbang:
|
||||||
|
self.bitbang = CSRStorage(4)
|
||||||
|
self.miso = CSRStatus()
|
||||||
|
self.bitbang_en = CSRStorage()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
cs_n = Signal(reset=1)
|
cs_n = Signal(reset=1)
|
||||||
|
@ -71,13 +76,46 @@ class SpiFlashDualQuad(Module, AutoCSR):
|
||||||
else:
|
else:
|
||||||
self.comb += bus.dat_r.eq(reverse_bytes(sr))
|
self.comb += bus.dat_r.eq(reverse_bytes(sr))
|
||||||
|
|
||||||
self.comb += [
|
hw_read_logic = [
|
||||||
pads.clk.eq(clk),
|
pads.clk.eq(clk),
|
||||||
pads.cs_n.eq(cs_n),
|
pads.cs_n.eq(cs_n),
|
||||||
dq.o.eq(sr[-spi_width:]),
|
dq.o.eq(sr[-spi_width:]),
|
||||||
dq.oe.eq(dq_oe)
|
dq.oe.eq(dq_oe)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if with_bitbang:
|
||||||
|
bitbang_logic = [
|
||||||
|
pads.clk.eq(self.bitbang.storage[1]),
|
||||||
|
pads.cs_n.eq(self.bitbang.storage[2]),
|
||||||
|
|
||||||
|
# In Dual/Quad mode, no single data pin is consistently
|
||||||
|
# an input or output thanks to dual/quad reads, so we need a bit
|
||||||
|
# to swap direction of the pins. Aside from this additional bit,
|
||||||
|
# bitbang mode is identical for Single/Dual/Quad; dq[0] is mosi
|
||||||
|
# and dq[1] is miso, meaning remaining data pin values don't
|
||||||
|
# appear in CSR registers.
|
||||||
|
If(self.bitbang.storage[3],
|
||||||
|
dq.oe.eq(0)
|
||||||
|
).Else(
|
||||||
|
dq.oe.eq(1)
|
||||||
|
),
|
||||||
|
If(self.bitbang.storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
|
||||||
|
self.miso.status.eq(dq.i[1])
|
||||||
|
),
|
||||||
|
dq.o.eq(Cat(self.bitbang.storage[0], Replicate(1, spi_width-1)))
|
||||||
|
]
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
If(self.bitbang_en.storage,
|
||||||
|
bitbang_logic
|
||||||
|
).Else(
|
||||||
|
hw_read_logic
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.comb += hw_read_logic
|
||||||
|
|
||||||
if div < 2:
|
if div < 2:
|
||||||
raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
|
raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
|
||||||
else:
|
else:
|
||||||
|
@ -125,13 +163,18 @@ class SpiFlashDualQuad(Module, AutoCSR):
|
||||||
|
|
||||||
|
|
||||||
class SpiFlashSingle(Module, AutoCSR):
|
class SpiFlashSingle(Module, AutoCSR):
|
||||||
def __init__(self, pads, dummy=15, div=2, endianness="big"):
|
def __init__(self, pads, dummy=15, div=2, with_bitbang=True, endianness="big"):
|
||||||
"""
|
"""
|
||||||
Simple SPI flash.
|
Simple SPI flash.
|
||||||
Supports 1-bit reads. Only supports mode0 (cpol=0, cpha=0).
|
Supports 1-bit reads. Only supports mode0 (cpol=0, cpha=0).
|
||||||
"""
|
"""
|
||||||
self.bus = bus = wishbone.Interface()
|
self.bus = bus = wishbone.Interface()
|
||||||
|
|
||||||
|
if with_bitbang:
|
||||||
|
self.bitbang = CSRStorage(4)
|
||||||
|
self.miso = CSRStatus()
|
||||||
|
self.bitbang_en = CSRStorage()
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
if hasattr(pads, "wp"):
|
if hasattr(pads, "wp"):
|
||||||
|
@ -154,12 +197,33 @@ class SpiFlashSingle(Module, AutoCSR):
|
||||||
else:
|
else:
|
||||||
self.comb += bus.dat_r.eq(reverse_bytes(sr))
|
self.comb += bus.dat_r.eq(reverse_bytes(sr))
|
||||||
|
|
||||||
self.comb += [
|
hw_read_logic = [
|
||||||
pads.clk.eq(clk),
|
pads.clk.eq(clk),
|
||||||
pads.cs_n.eq(cs_n),
|
pads.cs_n.eq(cs_n),
|
||||||
pads.mosi.eq(sr[-1:])
|
pads.mosi.eq(sr[-1:])
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if with_bitbang:
|
||||||
|
bitbang_logic = [
|
||||||
|
pads.clk.eq(self.bitbang.storage[1]),
|
||||||
|
pads.cs_n.eq(self.bitbang.storage[2]),
|
||||||
|
If(self.bitbang.storage[1], # CPOL=0/CPHA=0 or CPOL=1/CPHA=1 only.
|
||||||
|
self.miso.status.eq(pads.miso)
|
||||||
|
),
|
||||||
|
pads.mosi.eq(self.bitbang.storage[0])
|
||||||
|
]
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
If(self.bitbang_en.storage,
|
||||||
|
bitbang_logic
|
||||||
|
).Else(
|
||||||
|
hw_read_logic
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.comb += hw_read_logic
|
||||||
|
|
||||||
if div < 2:
|
if div < 2:
|
||||||
raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
|
raise ValueError("Unsupported value \'{}\' for div parameter for SpiFlash core".format(div))
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in New Issue