-
-
Save mntmn/44c3396eb4935e36d91eac41e7bd02bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# | |
# This file is part of LiteX-Boards. | |
# | |
# Copyright (c) 2021 Florent Kermarrec <florent@enjoy-digital.fr> | |
# SPDX-License-Identifier: BSD-2-Clause | |
import os | |
import argparse | |
from migen import * | |
from litex_boards.platforms import mnt_rkx7 | |
from litex.soc.cores.clock import * | |
from litex.soc.integration.soc_core import * | |
from litex.soc.integration.soc import SoCRegion | |
from litex.soc.integration.builder import * | |
from litex.soc.interconnect.csr import * | |
from litex.soc.interconnect.axi import * | |
from litex.soc.cores.bitbang import I2CMaster | |
from litex.soc.cores.gpio import GPIOOut | |
from litex.soc.cores.video import VideoDVIPHY | |
from migen.fhdl.specials import Tristate | |
from litedram.modules import IS43TR16512B | |
from litedram.phy import s7ddrphy | |
from liteeth.phy.s7rgmii import LiteEthPHYRGMII | |
# CRG ---------------------------------------------------------------------------------------------- | |
class _CRG(Module): | |
def __init__(self, platform, sys_clk_freq): | |
self.rst = Signal() | |
self.clock_domains.cd_sys = ClockDomain() | |
self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) | |
self.clock_domains.cd_idelay = ClockDomain() | |
self.clock_domains.cd_dvi = ClockDomain(reset_less=True) | |
self.clock_domains.cd_dsiref = ClockDomain(reset_less=True) | |
self.submodules.pll = pll = S7MMCM(speedgrade=-2) | |
self.comb += pll.reset.eq(self.rst) | |
pll.register_clkin(platform.request("clk100"), 100e6) | |
pll.create_clkout(self.cd_sys, sys_clk_freq) | |
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) | |
pll.create_clkout(self.cd_idelay, 200e6) | |
platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. | |
pll.create_clkout(self.cd_dvi, 40e6) | |
pll.create_clkout(self.cd_dsiref, 40e6) | |
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay) | |
# BaseSoC ------------------------------------------------------------------------------------------ | |
class BaseSoC(SoCCore): | |
def __init__(self, sys_clk_freq=int(100e6), with_ethernet=True, with_etherbone=False, | |
with_spi_flash=True, **kwargs): | |
platform = mnt_rkx7.Platform() | |
# SoCCore ---------------------------------------------------------------------------------- | |
SoCCore.__init__(self, platform, sys_clk_freq, | |
ident = "LiteX SoC on MNT-RKX7", | |
ident_version = True, | |
**kwargs) | |
# CRG -------------------------------------------------------------------------------------- | |
self.submodules.crg = _CRG(platform, sys_clk_freq) | |
# DDR3 SDRAM ------------------------------------------------------------------------------- | |
if not self.integrated_main_ram_size: | |
self.submodules.ddrphy = s7ddrphy.K7DDRPHY(platform.request("ddram"), | |
memtype = "DDR3", | |
nphases = 4, | |
sys_clk_freq = sys_clk_freq) | |
self.add_sdram("sdram", | |
phy = self.ddrphy, | |
module = IS43TR16512B(sys_clk_freq, "1:4"), | |
#size = 0x40000000, | |
size = 0x3ff00000, | |
l2_cache_size = kwargs.get("l2_size", 8192), | |
) | |
# SPI Flash -------------------------------------------------------------------------------- | |
if with_spi_flash: | |
from litespi.modules import W25Q128JV | |
from litespi.opcodes import SpiNorFlashOpCodes as Codes | |
self.add_spi_flash(mode="4x", module=W25Q128JV(Codes.READ_1_1_4), rate="1:1", with_master=True) | |
# Ethernet / Etherbone --------------------------------------------------------------------- | |
if with_ethernet or with_etherbone: | |
self.submodules.ethphy = LiteEthPHYRGMII( | |
clock_pads = self.platform.request("eth_clocks"), | |
pads = self.platform.request("eth")) | |
platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {{main_ethphy_eth_rx_clk_ibuf}}]") | |
if with_ethernet: | |
self.add_ethernet(phy=self.ethphy) | |
if with_etherbone: | |
self.add_etherbone(phy=self.ethphy) | |
# GPIO | |
self.submodules.leds = GPIOOut(platform.request_all("gpio")) | |
self.add_csr("leds") | |
# Second I2C | |
self.submodules.i2c1 = I2CMaster(platform.request("i2c", 1)) | |
self.submodules.i2c2 = I2CMaster(platform.request("i2c", 2)) | |
# MIPI DSI | |
dsi = platform.request("dsi") | |
self.comb += self.crg.cd_dsiref.clk.eq(dsi.refclk) | |
self.platform.add_false_path_constraints( | |
self.crg.cd_sys.clk, | |
self.crg.cd_dsiref.clk) | |
# Video (HDMI) | |
self.submodules.videophy = VideoDVIPHY(platform.request("hdmi"), clock_domain="dvi") | |
self.add_video_framebuffer(phy=self.videophy, timings="800x600@60Hz", clock_domain="dvi") | |
# USB | |
# via https://github.com/enjoy-digital/litex_vexriscv_smp_usb_host/blob/master/digilent_arty.py | |
usb2_reset_n = Signal(1) | |
usb2_enable = Signal(1) | |
usb2_phy_reset_n = Signal(1) | |
usb_reset_n = platform.request("usb_reset_n") | |
usb_enable = platform.request("usb_enable") | |
usb_ulpi = platform.request("usb_ulpi") | |
usb_pipe_ctrl = platform.request("usb_pipe_ctrl") | |
self.comb += usb_reset_n.eq(usb2_reset_n) | |
self.comb += usb_pipe_ctrl.phy_reset_n.eq(usb2_phy_reset_n) | |
self.comb += usb_enable.eq(usb2_enable) | |
platform.add_verilog_include_path(os.path.join("core_usb_host", "src_v")) | |
platform.add_source_dir(os.path.join("core_usb_host", "src_v")) | |
platform.add_verilog_include_path(os.path.join("core_ulpi_wrapper", "src_v")) | |
platform.add_source_dir(os.path.join("core_ulpi_wrapper", "src_v")) | |
utmi = Record([ | |
("data_in", 8), | |
("txready", 1), | |
("rxvalid", 1), | |
("rxactive", 1), | |
("rxerror", 1), | |
("linestate", 2), | |
("data_out", 8), | |
("txvalid", 1), | |
("op_mode", 2), | |
("xcvrselect", 2), | |
("termselect", 1), | |
("dppulldown", 1), | |
("dmpulldown", 1), | |
]) | |
ulpi_data = Record([("din", 8), ("dout", 8)]) | |
usb_axi = AXILiteInterface(data_width=32, address_width=32) | |
usb_wb = self.bus.add_adapter("usb_axi_wb", usb_axi, "s2m") | |
# FIXME: address? | |
self.bus.add_slave("usb_host", usb_wb, region=SoCRegion(origin=0x81000000, size=0x100000, cached=False)) | |
self.clock_domains.cd_ulpi = ClockDomain() | |
self.comb += self.cd_ulpi.clk.eq(usb_ulpi.clk) | |
self.platform.add_period_constraint(usb_ulpi.clk, 1e9/60e6) # 60MHz in ns(?) | |
self.cd_ulpi.clk.attr.add("keep") # ??? | |
self.platform.add_false_path_constraints( | |
self.crg.cd_sys.clk, | |
self.cd_ulpi.clk) | |
ulpi_wrapper = Instance( | |
"ulpi_wrapper", | |
# ULPI | |
i_ulpi_clk60_i = usb_ulpi.clk, | |
i_ulpi_rst_i = Signal(1), | |
i_ulpi_data_out_i = ulpi_data.din, | |
i_ulpi_dir_i = usb_ulpi.dir, | |
o_ulpi_stp_o = usb_ulpi.stp, | |
i_ulpi_nxt_i = usb_ulpi.nxt, | |
o_ulpi_data_in_o = ulpi_data.dout, | |
# UTMI | |
o_utmi_data_in_o = utmi.data_in, | |
o_utmi_txready_o = utmi.txready, | |
o_utmi_rxvalid_o = utmi.rxvalid, | |
o_utmi_rxactive_o = utmi.rxactive, | |
o_utmi_rxerror_o = utmi.rxerror, | |
o_utmi_linestate_o = utmi.linestate, | |
i_utmi_data_out_i = utmi.data_out, | |
i_utmi_txvalid_i = utmi.txvalid, | |
i_utmi_op_mode_i = utmi.op_mode, | |
i_utmi_xcvrselect_i = utmi.xcvrselect, | |
i_utmi_termselect_i = utmi.termselect, | |
i_utmi_dppulldown_i = utmi.dppulldown, | |
i_utmi_dmpulldown_i = utmi.dmpulldown, | |
) | |
self.specials += ulpi_wrapper | |
ulpi_data_tristate = Tristate( | |
usb_ulpi.data, | |
ulpi_data.din, | |
usb_ulpi.dir, | |
ulpi_data.dout, | |
) | |
self.specials += ulpi_data_tristate | |
usb_host_intr = Signal() | |
usb_host = Instance( | |
"usbh_host", | |
i_clk_i = usb_ulpi.clk, | |
i_rst_i = Signal(1), | |
o_intr_o = usb_host_intr, | |
# UTMI | |
i_utmi_data_in_i = utmi.data_in, | |
i_utmi_txready_i = utmi.txready, | |
i_utmi_rxvalid_i = utmi.rxvalid, | |
i_utmi_rxactive_i = utmi.rxactive, | |
i_utmi_rxerror_i = utmi.rxerror, | |
i_utmi_linestate_i = utmi.linestate, | |
o_utmi_data_out_o = utmi.data_out, | |
o_utmi_txvalid_o = utmi.txvalid, | |
o_utmi_op_mode_o = utmi.op_mode, | |
o_utmi_xcvrselect_o = utmi.xcvrselect, | |
o_utmi_termselect_o = utmi.termselect, | |
o_utmi_dppulldown_o = utmi.dppulldown, | |
o_utmi_dmpulldown_o = utmi.dmpulldown, | |
# AXI4 Lite | |
i_cfg_awvalid_i = usb_axi.aw.valid, | |
i_cfg_awaddr_i = usb_axi.aw.addr, | |
i_cfg_wvalid_i = usb_axi.w.valid, | |
i_cfg_wdata_i = usb_axi.w.data, | |
i_cfg_wstrb_i = usb_axi.w.strb, | |
i_cfg_bready_i = usb_axi.b.ready, | |
i_cfg_arvalid_i = usb_axi.ar.valid, | |
i_cfg_araddr_i = usb_axi.ar.addr, | |
i_cfg_rready_i = usb_axi.r.ready, | |
o_cfg_awready_o = usb_axi.aw.ready, | |
o_cfg_wready_o = usb_axi.w.ready, | |
o_cfg_bvalid_o = usb_axi.b.valid, | |
o_cfg_bresp_o = usb_axi.b.resp, | |
o_cfg_arready_o = usb_axi.ar.ready, | |
o_cfg_rvalid_o = usb_axi.r.valid, | |
o_cfg_rdata_o = usb_axi.r.data, | |
o_cfg_rresp_o = usb_axi.r.resp | |
) | |
self.specials += usb_host | |
platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets usb_ulpi_clk_IBUF]") | |
self.comb += self.cpu.interrupt[16].eq(usb_host_intr) | |
# Build -------------------------------------------------------------------------------------------- | |
def main(): | |
parser = argparse.ArgumentParser(description="LiteX SoC on MNT-RKX7") | |
parser.add_argument("--build", action="store_true", help="Build bitstream") | |
parser.add_argument("--load", action="store_true", help="Load bitstream") | |
parser.add_argument("--sys-clk-freq", default=100e6, help="System clock frequency (default: 100MHz)") | |
parser.add_argument("--with-spi-flash", default=True, action="store_true", help="Enable SPI Flash (MMAPed)") | |
sdopts = parser.add_mutually_exclusive_group() | |
sdopts.add_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support") | |
sdopts.add_argument("--with-sdcard", default=True, action="store_true", help="Enable SDCard support") | |
ethopts = parser.add_mutually_exclusive_group() | |
ethopts.add_argument("--with-ethernet", default=True, action="store_true", help="Enable Ethernet support") | |
ethopts.add_argument("--with-etherbone", action="store_true", help="Enable Etherbone support") | |
builder_args(parser) | |
soc_core_args(parser) | |
args = parser.parse_args() | |
soc = BaseSoC( | |
sys_clk_freq = int(float(args.sys_clk_freq)), | |
with_ethernet = args.with_ethernet, | |
with_etherbone = args.with_etherbone, | |
with_spi_flash = args.with_spi_flash, | |
**soc_core_argdict(args) | |
) | |
if args.with_spi_sdcard: | |
soc.add_spi_sdcard() | |
if args.with_sdcard: | |
soc.add_sdcard() | |
builder = Builder(soc, **builder_argdict(args)) | |
builder.build(run=args.build) | |
if args.load: | |
prog = soc.platform.create_programmer() | |
prog.load_bitstream(os.path.join(builder.gateware_dir, soc.build_name + ".bit")) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment