si549 gateware

kasli_soc: add option to select si5324 over si549 using commend line
kasli_soc: add main and helper si549 for satellite
kasli_soc: default to use si549
si549: add i2c and adpll programming for si549
si549: add option to switch between bitbang and gateware i2c
morgan 2023-12-20 15:05:49 +08:00
parent 33cf924805
commit e08d942066
2 changed files with 329 additions and 12 deletions

View File

@ -26,6 +26,7 @@ import analyzer
import acpki
import drtio_aux_controller
import zynq_clocking
import si549
from config import write_csr_file, write_mem_file, write_rustc_cfg_file
eem_iostandard_dict = {
@ -105,7 +106,7 @@ class GTPBootstrapClock(Module):
class GenericStandalone(SoCCore):
def __init__(self, description, acpki=False):
def __init__(self, description, acpki=False, si5324=False):
self.acpki = acpki
clk_freq = description["rtio_frequency"]
@ -205,7 +206,7 @@ class GenericStandalone(SoCCore):
class GenericMaster(SoCCore):
def __init__(self, description, acpki=False):
def __init__(self, description, acpki=False, si5324=False):
clk_freq = description["rtio_frequency"]
has_drtio_over_eem = any(peripheral["type"] == "shuttler" for peripheral in description["peripherals"])
@ -398,7 +399,7 @@ class GenericMaster(SoCCore):
class GenericSatellite(SoCCore):
def __init__(self, description, acpki=False):
def __init__(self, description, acpki=False, si5324=False):
clk_freq = description["rtio_frequency"]
self.acpki = acpki
@ -551,14 +552,19 @@ class GenericSatellite(SoCCore):
self.config["RTIO_FREQUENCY"] = str(clk_freq/1e6)
self.config["CLOCK_FREQUENCY"] = int(clk_freq)
self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"),
rx_synchronizer=self.rx_synchronizer,
ultrascale=False,
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
self.csr_devices.append("siphaser")
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
if si5324:
self.submodules.siphaser = SiPhaser7Series(
si5324_clkin=platform.request("cdr_clk"),
rx_synchronizer=self.rx_synchronizer,
ultrascale=False,
rtio_clk_freq=self.gt_drtio.rtio_clk_freq)
self.csr_devices.append("siphaser")
self.config["HAS_SI5324"] = None
self.config["SI5324_SOFT_RESET"] = None
else:
self.submodules.main_dcxo = si549.Si549(platform.request("ddmtd_main_dcxo_i2c"))
self.submodules.helper_dcxo = si549.Si549(platform.request("ddmtd_helper_dcxo_i2c"))
self.config["HAS_SI549"] = None
gtx0 = self.gt_drtio.gtxs[0]
platform.add_false_path_constraints(
@ -588,6 +594,8 @@ def main():
help="build gateware into the specified directory")
parser.add_argument("--acpki", default=False, action="store_true",
help="enable ACPKI")
parser.add_argument("--si5324", default=False, action="store_true",
help="use si5324 over si549")
parser.add_argument("description", metavar="DESCRIPTION",
help="JSON system description file")
args = parser.parse_args()
@ -605,7 +613,7 @@ def main():
else:
raise ValueError("Invalid DRTIO role")
soc = cls(description, acpki=args.acpki)
soc = cls(description, acpki=args.acpki, si5324=args.si5324)
soc.finalize()
if args.r is not None:

309
src/gateware/si549.py Normal file
View File

@ -0,0 +1,309 @@
from migen import *
from migen.genlib.fsm import *
from migen.genlib.cdc import MultiReg, PulseSynchronizer, BlindTransfer
from misoc.interconnect.csr import *
class I2CClockGen(Module):
def __init__(self, width):
self.load = Signal(width)
self.clk2x = Signal()
cnt = Signal.like(self.load)
self.comb += [
self.clk2x.eq(cnt == 0),
]
self.sync += [
If(self.clk2x,
cnt.eq(self.load),
).Else(
cnt.eq(cnt - 1),
)
]
class I2CMasterMachine(Module):
def __init__(self, clock_width):
self.scl = Signal(reset=1)
self.sda_o = Signal(reset=1)
self.sda_i = Signal()
self.submodules.cg = CEInserter()(I2CClockGen(clock_width))
self.start = Signal()
self.stop = Signal()
self.write = Signal()
self.ack = Signal()
self.data = Signal(8)
self.ready = Signal()
###
bits = Signal(4)
data = Signal(8)
fsm = CEInserter()(FSM("IDLE"))
self.submodules += fsm
fsm.act("IDLE",
self.ready.eq(1),
If(self.start,
NextState("START0"),
).Elif(self.stop,
NextState("STOP0"),
).Elif(self.write,
NextValue(bits, 8),
NextValue(data, self.data),
NextState("WRITE0")
)
)
fsm.act("START0",
NextValue(self.scl, 1),
NextState("START1")
)
fsm.act("START1",
NextValue(self.sda_o, 0),
NextState("IDLE")
)
fsm.act("STOP0",
NextValue(self.scl, 0),
NextState("STOP1")
)
fsm.act("STOP1",
NextValue(self.sda_o, 0),
NextState("STOP2")
)
fsm.act("STOP2",
NextValue(self.scl, 1),
NextState("STOP3")
)
fsm.act("STOP3",
NextValue(self.sda_o, 1),
NextState("IDLE")
)
fsm.act("WRITE0",
NextValue(self.scl, 0),
NextState("WRITE1")
)
fsm.act("WRITE1",
If(bits == 0,
NextValue(self.sda_o, 1),
NextState("READACK0"),
).Else(
NextValue(self.sda_o, data[7]),
NextState("WRITE2"),
)
)
fsm.act("WRITE2",
NextValue(self.scl, 1),
NextValue(data[1:], data[:-1]),
NextValue(bits, bits - 1),
NextState("WRITE0"),
)
fsm.act("READACK0",
NextValue(self.scl, 1),
NextState("READACK1"),
)
fsm.act("READACK1",
NextValue(self.ack, ~self.sda_i),
NextState("IDLE")
)
run = Signal()
idle = Signal()
self.comb += [
run.eq((self.start | self.stop | self.write) & self.ready),
idle.eq(~run & fsm.ongoing("IDLE")),
self.cg.ce.eq(~idle),
fsm.ce.eq(run | self.cg.clk2x),
]
class ADPLLProgrammer(Module):
def __init__(self):
self.i2c_divider = Signal(16)
self.i2c_address = Signal(7)
self.adpll = Signal(24)
self.stb = Signal()
self.busy = Signal()
self.nack = Signal()
self.scl = Signal()
self.sda_i = Signal()
self.sda_o = Signal()
self.scl.attr.add("no_retiming")
self.sda_o.attr.add("no_retiming")
# # #
master = I2CMasterMachine(16)
self.submodules += master
self.comb += [
master.cg.load.eq(self.i2c_divider),
self.scl.eq(master.scl),
master.sda_i.eq(self.sda_i),
self.sda_o.eq(master.sda_o)
]
fsm = FSM()
self.submodules += fsm
adpll = Signal.like(self.adpll)
fsm.act("IDLE",
If(self.stb,
NextValue(adpll, self.adpll),
NextState("START")
)
)
fsm.act("START",
master.start.eq(1),
If(master.ready, NextState("DEVADDRESS"))
)
fsm.act("DEVADDRESS",
master.data.eq(self.i2c_address << 1),
master.write.eq(1),
If(master.ready, NextState("REGADRESS"))
)
fsm.act("REGADRESS",
master.data.eq(231),
master.write.eq(1),
If(master.ready,
If(master.ack,
NextState("DATA0")
).Else(
self.nack.eq(1),
NextState("STOP")
)
)
)
fsm.act("DATA0",
master.data.eq(adpll[0:8]),
master.write.eq(1),
If(master.ready,
If(master.ack,
NextState("DATA1")
).Else(
self.nack.eq(1),
NextState("STOP")
)
)
)
fsm.act("DATA1",
master.data.eq(adpll[8:16]),
master.write.eq(1),
If(master.ready,
If(master.ack,
NextState("DATA2")
).Else(
self.nack.eq(1),
NextState("STOP")
)
)
)
fsm.act("DATA2",
master.data.eq(adpll[16:24]),
master.write.eq(1),
If(master.ready,
If(~master.ack, self.nack.eq(1)),
NextState("STOP")
)
)
fsm.act("STOP",
master.stop.eq(1),
If(master.ready,
If(~master.ack, self.nack.eq(1)),
NextState("IDLE")
)
)
self.comb += self.busy.eq(~fsm.ongoing("IDLE"))
class Si549(Module, AutoCSR):
def __init__(self, pads):
# switching sys clk will reset all csr values
self.bitbang_enable = CSRStorage()
self.gpio_in = CSRStatus(2)
self.gpio_out = CSRStorage(2)
self.gpio_oe = CSRStorage(2)
self.i2c_divider = CSRStorage(16, reset=75)
self.i2c_address = CSRStorage(7)
self.nack = CSRStatus()
self.adpll = CSRStorage(24)
self.adpll_stb = CSRStorage()
self.adpll_busy = CSRStatus()
# # #
self.submodules.programmer = ClockDomainsRenamer("helper")(ADPLLProgrammer())
self.i2c_divider.storage.attr.add("no_retiming")
self.i2c_address.storage.attr.add("no_retiming")
self.adpll.storage.attr.add("no_retiming")
self.adpll_stb.storage.attr.add("no_retiming")
self.specials += [
MultiReg(self.i2c_divider.storage, self.programmer.i2c_divider, "helper"),
MultiReg(self.i2c_address.storage, self.programmer.i2c_address, "helper"),
MultiReg(self.adpll.storage, self.programmer.adpll, "helper"),
MultiReg(self.adpll_stb.storage, self.programmer.stb, "helper"),
MultiReg(self.programmer.busy, self.adpll_busy.status)
]
nack_cdc = PulseSynchronizer("helper", "sys")
self.submodules += nack_cdc
self.comb += nack_cdc.i.eq(self.programmer.nack)
self.sync += [
If(self.bitbang_enable.storage, self.nack.status.eq(0)),
If(nack_cdc.o, self.nack.status.eq(1))
]
self.bitbang_enable.storage.attr.add("no_retiming")
self.gpio_out.storage.attr.add("no_retiming")
self.gpio_oe.storage.attr.add("no_retiming")
# SCL GPIO and mux
ts_scl = TSTriple(1)
self.specials += ts_scl.get_tristate(pads.scl)
status = Signal()
self.comb += self.gpio_in.status[0].eq(status)
self.specials += MultiReg(ts_scl.i, status)
self.comb += [
If(self.bitbang_enable.storage,
ts_scl.o.eq(self.gpio_out.storage[0]),
ts_scl.oe.eq(self.gpio_oe.storage[0])
).Else(
ts_scl.o.eq(0),
ts_scl.oe.eq(~self.programmer.scl)
)
]
# SDA GPIO and mux
ts_sda = TSTriple(1)
self.specials += ts_sda.get_tristate(pads.sda)
status = Signal()
self.comb += self.gpio_in.status[1].eq(status)
self.specials += MultiReg(ts_sda.i, status)
self.comb += [
If(self.bitbang_enable.storage,
ts_sda.o.eq(self.gpio_out.storage[1]),
ts_sda.oe.eq(self.gpio_oe.storage[1])
).Else(
ts_sda.o.eq(0),
ts_sda.oe.eq(~self.programmer.sda_o)
)
]
self.specials += MultiReg(ts_sda.i, self.programmer.sda_i, "helper")