Skip to content

Instantly share code, notes, and snippets.

@mntmn
Created October 20, 2021 20:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mntmn/44c3396eb4935e36d91eac41e7bd02bf to your computer and use it in GitHub Desktop.
Save mntmn/44c3396eb4935e36d91eac41e7bd02bf to your computer and use it in GitHub Desktop.
#!/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