+# GPIO Tristate -------------------------------------------------------
+# doesn't work properly.
+#from litex.soc.cores.gpio import GPIOTristate
+from litex.soc.interconnect.csr import CSRStorage, CSRStatus
+from migen.genlib.cdc import MultiReg
+
+# Imports
+from litex.soc.interconnect import wishbone
+from litesdcard.phy import (SDPHY, SDPHYClocker,
+ SDPHYInit, SDPHYCMDW, SDPHYCMDR,
+ SDPHYDATAW, SDPHYDATAR,
+ _sdpads_layout)
+from litesdcard.core import SDCore
+from litesdcard.frontend.dma import SDBlock2MemDMA, SDMem2BlockDMA
+from litex.build.io import SDROutput, SDRInput
+
+
+class GPIOTristateASIC(Module, AutoCSR):
+ def __init__(self, pads):
+ nbits = len(pads.oe) # hack
+ self._oe = CSRStorage(nbits, description="GPIO Tristate(s) Control.")
+ self._in = CSRStatus(nbits, description="GPIO Input(s) Status.")
+ self._out = CSRStorage(nbits, description="GPIO Ouptut(s) Control.")
+
+ # # #
+
+ _pads = Record( (("i", nbits),
+ ("o", nbits),
+ ("oe", nbits)))
+ self.comb += _pads.i.eq(pads.i)
+ self.comb += pads.o.eq(_pads.o)
+ self.comb += pads.oe.eq(_pads.oe)
+
+ self.comb += _pads.oe.eq(self._oe.storage)
+ self.comb += _pads.o.eq(self._out.storage)
+ for i in range(nbits):
+ self.specials += MultiReg(_pads.i[i], self._in.status[i])
+
+# SDCard PHY IO -------------------------------------------------------
+
+class SDRPad(Module):
+ def __init__(self, pad, name, o, oe, i):
+ clk = ClockSignal()
+ _o = getattr(pad, "%s_o" % name)
+ _oe = getattr(pad, "%s_oe" % name)
+ _i = getattr(pad, "%s_i" % name)
+ self.specials += SDROutput(clk=clk, i=oe, o=_oe)
+ for j in range(len(_o)):
+ self.specials += SDROutput(clk=clk, i=o[j], o=_o[j])
+ self.specials += SDRInput(clk=clk, i=_i[j], o=i[j])
+
+
+class SDPHYIOGen(Module):
+ def __init__(self, clocker, sdpads, pads):
+ # Rst
+ if hasattr(pads, "rst"):
+ self.comb += pads.rst.eq(0)
+
+ # Clk
+ self.specials += SDROutput(
+ clk = ClockSignal(),
+ i = ~clocker.clk & sdpads.clk,
+ o = pads.clk
+ )
+
+ # Cmd
+ c = sdpads.cmd
+ self.submodules.sd_cmd = SDRPad(pads, "cmd", c.o, c.oe, c.i)
+
+ # Data
+ d = sdpads.data
+ self.submodules.sd_data = SDRPad(pads, "data", d.o, d.oe, d.i)
+
+
+class SDPHY(Module, AutoCSR):
+ def __init__(self, pads, device, sys_clk_freq,
+ cmd_timeout=10e-3, data_timeout=10e-3):
+ self.card_detect = CSRStatus() # Assume SDCard is present if no cd pin.
+ self.comb += self.card_detect.status.eq(getattr(pads, "cd", 0))
+
+ self.submodules.clocker = clocker = SDPHYClocker()
+ self.submodules.init = init = SDPHYInit()
+ self.submodules.cmdw = cmdw = SDPHYCMDW()
+ self.submodules.cmdr = cmdr = SDPHYCMDR(sys_clk_freq,
+ cmd_timeout, cmdw)
+ self.submodules.dataw = dataw = SDPHYDATAW()
+ self.submodules.datar = datar = SDPHYDATAR(sys_clk_freq,
+ data_timeout)
+
+ # # #
+
+ self.sdpads = sdpads = Record(_sdpads_layout)
+
+ # IOs
+ sdphy_cls = SDPHYIOGen
+ self.submodules.io = sdphy_cls(clocker, sdpads, pads)
+
+ # Connect pads_out of submodules to physical pads --------------
+ pl = [init, cmdw, cmdr, dataw, datar]
+ self.comb += [
+ sdpads.clk.eq( reduce(or_, [m.pads_out.clk for m in pl])),
+ sdpads.cmd.oe.eq( reduce(or_, [m.pads_out.cmd.oe for m in pl])),
+ sdpads.cmd.o.eq( reduce(or_, [m.pads_out.cmd.o for m in pl])),
+ sdpads.data.oe.eq(reduce(or_, [m.pads_out.data.oe for m in pl])),
+ sdpads.data.o.eq( reduce(or_, [m.pads_out.data.o for m in pl])),
+ ]
+ for m in pl:
+ self.comb += m.pads_out.ready.eq(self.clocker.ce)
+
+ # Connect physical pads to pads_in of submodules ---------------
+ for m in pl:
+ self.comb += m.pads_in.valid.eq(self.clocker.ce)
+ self.comb += m.pads_in.cmd.i.eq(sdpads.cmd.i)
+ self.comb += m.pads_in.data.i.eq(sdpads.data.i)
+
+ # Speed Throttling -------------------------------------------
+ self.comb += clocker.stop.eq(dataw.stop | datar.stop)
+
+
+# Generic SDR PHY ---------------------------------------------------------
+
+class GENSDRPHY(Module):
+ def __init__(self, pads, cl=2, cmd_latency=1):
+ pads = PHYPadsCombiner(pads)
+ addressbits = len(pads.a)
+ bankbits = len(pads.ba)
+ nranks = 1 if not hasattr(pads, "cs_n") else len(pads.cs_n)
+ databits = len(pads.dq_i)
+ assert cl in [2, 3]
+ assert databits%8 == 0
+
+ # PHY settings ----------------------------------------------------
+ self.settings = PhySettings(
+ phytype = "GENSDRPHY",
+ memtype = "SDR",
+ databits = databits,
+ dfi_databits = databits,
+ nranks = nranks,
+ nphases = 1,
+ rdphase = 0,
+ wrphase = 0,
+ rdcmdphase = 0,
+ wrcmdphase = 0,
+ cl = cl,
+ read_latency = cl + cmd_latency,
+ write_latency = 0
+ )
+
+ # DFI Interface ---------------------------------------------------
+ self.dfi = dfi = DFIInterface(addressbits, bankbits, nranks, databits)
+
+ # # #
+
+ # Iterate on pads groups ------------------------------------------
+ for pads_group in range(len(pads.groups)):
+ pads.sel_group(pads_group)
+
+ # Addresses and Commands --------------------------------------
+ p0 = dfi.p0
+ self.specials += [SDROutput(i=p0.address[i], o=pads.a[i])
+ for i in range(len(pads.a))]
+ self.specials += [SDROutput(i=p0.bank[i], o=pads.ba[i])
+ for i in range(len(pads.ba))]
+ self.specials += SDROutput(i=p0.cas_n, o=pads.cas_n)
+ self.specials += SDROutput(i=p0.ras_n, o=pads.ras_n)
+ self.specials += SDROutput(i=p0.we_n, o=pads.we_n)
+ if hasattr(pads, "cke"):
+ for i in range(len(pads.cke)):
+ self.specials += SDROutput(i=p0.cke[i], o=pads.cke[i])
+ if hasattr(pads, "cs_n"):
+ for i in range(len(pads.cs_n)):
+ self.specials += SDROutput(i=p0.cs_n[i], o=pads.cs_n[i])
+
+ # DQ/DM Data Path -------------------------------------------------
+
+ d = dfi.p0
+ wren = []
+ self.submodules.dq = SDRPad(pads, "dq", d.wrdata, d.wrdata_en, d.rddata)