Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ Some of the supported boards, see yours? Give LiteX-Boards a try!
├── microphase_a7_lite
├── microsoft_catapult_v3
├── mist
├── mlk_cu07_ku15p
├── mlkpai_fs01_dr1v90m
├── mnt_rkx7
├── muselab_icesugar
Expand Down
1 change: 1 addition & 0 deletions docs/boards_inventory.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ python3 .github/scripts/generate_board_inventory.py --write
| `microphase_a7_lite` | microphase_a7_lite | vivado | `100000000.0` | Ethernet, SDCard, SPI SDCard, SPI Flash | included |
| `microsoft_catapult_v3` | microsoft_catapult_v3 | quartus | `100000000.0` | - | included |
| `mist` | mist | quartus | `50000000.0` | Video Terminal | included |
| `mlk_cu07_ku15p` | mlk_cu07_ku15p | vivado | `75000000.0` | SDCard | included |
| `mlkpai_fs01_dr1v90m` | mlkpai_fs01_dr1v90m | td | `25000000.0` | - | included |
| `mnt_rkx7` | mnt_rkx7 | vivado | `100000000.0` | Ethernet, Etherbone, SDCard, SPI SDCard, SPI Flash, USB Host | included |
| `muselab_icesugar` | muselab_icesugar | icestorm | `24000000.0` | - | included |
Expand Down
125 changes: 125 additions & 0 deletions litex_boards/platforms/mlk_cu07_ku15p.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2026 Yu Jin <lambda.jinyu@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause

from litex.build.generic_platform import *
from litex.build.xilinx import XilinxUSPPlatform
from litex.build.openfpgaloader import OpenFPGALoader

# IOs ----------------------------------------------------------------------------------------------

_io = [
# Clk / Rst.
("clk100", 0, Pins("AH18"), IOStandard("LVCMOS18")),
("clk100_ddr", 0,
Subsignal("p", Pins("AK17")),
Subsignal("n", Pins("AK16")),
IOStandard("DIFF_SSTL12"),
),
("cpu_resetn", 0, Pins("J23"), IOStandard("LVCMOS18"), Misc("PULLTYPE PULLUP")),

# Buttons.
("user_btn", 0, Pins("G26"), IOStandard("LVCMOS18")),
("user_btn", 1, Pins("G25"), IOStandard("LVCMOS18")),
("user_btn", 2, Pins("H24"), IOStandard("LVCMOS18")),

# Leds.
("user_led", 0, Pins("AP9"), IOStandard("LVCMOS33")),
("user_led", 1, Pins("AN9"), IOStandard("LVCMOS33")),
("user_led", 2, Pins("AP8"), IOStandard("LVCMOS33")),
("user_led", 3, Pins("AN8"), IOStandard("LVCMOS33")),
("user_led", 4, Pins("AL10"), IOStandard("LVCMOS33")),
("user_led", 5, Pins("AM10"), IOStandard("LVCMOS33")),
("user_led", 6, Pins("AE11"), IOStandard("LVCMOS33")),

# Serial.
("serial", 0,
Subsignal("tx", Pins("AN13")),
Subsignal("rx", Pins("AP13")),
IOStandard("LVCMOS33"),
),

# SDCard.
("sdcard", 0,
Subsignal("clk", Pins("B9")),
Subsignal("cmd", Pins("A10"), Misc("PULLTYPE PULLUP")),
Subsignal("data", Pins("B11 A9 C8 B10"), Misc("PULLTYPE PULLUP")),
Subsignal("cd", Pins("C11"), Misc("PULLTYPE PULLUP")),
IOStandard("LVCMOS18"),
),

# Runtime QSPI is intentionally omitted. The source pin table assigns C8
# to both SD D2 and flash CS, and the dedicated flash clock needs STARTUPE3.

# I2C EEPROM / RTC.
("i2c", 0,
Subsignal("scl", Pins("AP11")),
Subsignal("sda", Pins("AP10")),
IOStandard("LVCMOS33"),
),

# DDR4 SDRAM (4GB / 4 x Hynix H5AN8G6NCJR-VKI, modeled as MT40A512M16).
("ddram", 0,
Subsignal("a", Pins(
"AM34 AN26 AP34 AK26 AL32 AK28 AK32 AL30",
"AL34 AP26 AK31 AL33 AH32 AM32"),
IOStandard("SSTL12_DCI")),
Subsignal("ba", Pins("AJ31 AK27"), IOStandard("SSTL12_DCI")),
Subsignal("bg", Pins("AJ30"), IOStandard("SSTL12_DCI")),
Subsignal("ras_n", Pins("AJ33"), IOStandard("SSTL12_DCI")),
Subsignal("cas_n", Pins("AJ34"), IOStandard("SSTL12_DCI")),
Subsignal("we_n", Pins("AJ28"), IOStandard("SSTL12_DCI")),
Subsignal("cs_n", Pins("AH33"), IOStandard("SSTL12_DCI")),
Subsignal("act_n", Pins("AH31"), IOStandard("SSTL12_DCI")),
Subsignal("dm", Pins("Y26 V27 AA22 W23 AE25 AD21 AM21 AJ21"),
IOStandard("POD12_DCI")),
Subsignal("dq", Pins(
"AD25 AA27 AC24 AB25 AB24 AB27 AD26 AB26",
"U25 W28 W26 W29 U24 V29 V26 Y28",
"AB20 Y23 AC22 AA24 AA20 AA25 AC23 AA23",
"U22 T22 T23 W21 U21 Y25 V21 W25",
"AJ23 AF23 AJ24 AG25 AH23 AF24 AH22 AG24",
"AG20 AE22 AF20 AF22 AD20 AE23 AG22 AE20",
"AM22 AM24 AN22 AN24 AN23 AP24 AP23 AP25",
"AL24 AL25 AK22 AL22 AK23 AM20 AL20 AL23"),
IOStandard("POD12_DCI")),
Subsignal("dqs_p", Pins("AC26 U26 AB21 V22 AH24 AG21 AP20 AJ20"),
IOStandard("DIFF_POD12_DCI")),
Subsignal("dqs_n", Pins("AC27 U27 AC21 V23 AJ25 AH21 AP21 AK20"),
IOStandard("DIFF_POD12_DCI")),
Subsignal("clk_p", Pins("AJ29"), IOStandard("DIFF_SSTL12_DCI")),
Subsignal("clk_n", Pins("AK30"), IOStandard("DIFF_SSTL12_DCI")),
Subsignal("cke", Pins("AH27"), IOStandard("SSTL12_DCI")),
Subsignal("odt", Pins("AH28"), IOStandard("SSTL12_DCI")),
Subsignal("reset_n", Pins("AJ26"), IOStandard("LVCMOS12")),
Misc("SLEW=FAST"),
),
]

# Platform -----------------------------------------------------------------------------------------

class Platform(XilinxUSPPlatform):
default_clk_name = "clk100"
default_clk_period = 1e9/100e6

def __init__(self, toolchain="vivado"):
XilinxUSPPlatform.__init__(self, "xcku15p-ffva1156-2-e", _io, toolchain=toolchain)

def create_programmer(self):
return OpenFPGALoader(cable="ft2232", fpga_part="xcku15p-ffva1156")

def do_finalize(self, fragment):
XilinxUSPPlatform.do_finalize(self, fragment)
self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6)

# Bitstream generation options.
self.add_platform_command("set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]")
self.add_platform_command("set_property BITSTREAM.CONFIG.CONFIGRATE 85.0 [current_design]")
self.add_platform_command("set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]")
self.add_platform_command("set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]")
self.add_platform_command("set_property CONFIG_VOLTAGE 1.8 [current_design]")
self.add_platform_command("set_property CFGBVS GND [current_design]")
self.add_platform_command("set_property CONFIG_MODE SPIx4 [current_design]")
self.add_platform_command("set_property BITSTREAM.CONFIG.UNUSEDPIN PULLDOWN [current_design]")
120 changes: 120 additions & 0 deletions litex_boards/targets/mlk_cu07_ku15p.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env python3

#
# This file is part of LiteX-Boards.
#
# Copyright (c) 2026 Yu Jin <lambda.jinyu@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause

from migen import *

from litex.gen import *

from litex_boards.platforms import mlk_cu07_ku15p

from litex.soc.cores.clock import USPMMCM, USPIDELAYCTRL
from litex.soc.cores.led import LedChaser
from litex.soc.integration.builder import Builder
from litex.soc.integration.soc_core import SoCCore

from litedram.modules import MT40A512M16
from litedram.phy import usddrphy

# CRG ----------------------------------------------------------------------------------------------

class _CRG(LiteXModule):
def __init__(self, platform, sys_clk_freq):
self.rst = Signal()
self.cd_sys = ClockDomain()
self.cd_sys4x = ClockDomain()
self.cd_idelay = ClockDomain()
self.cd_por = ClockDomain(reset_less=True)

# # #

# Clk.
clk100 = platform.request("clk100")

# Power-on Reset.
# Keep the POR independent of cpu_resetn, which can float low on some board revisions.
por_count = Signal(16, reset=2**16 - 1)
por_done = Signal()
self.comb += [
self.cd_por.clk.eq(clk100),
por_done.eq(por_count == 0),
]
self.sync.por += If(~por_done, por_count.eq(por_count - 1))

# MMCM.
self.pll = pll = USPMMCM(speedgrade=-2)
self.comb += pll.reset.eq(~por_done | self.rst)
pll.register_clkin(clk100, 100e6)
pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False)
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq, with_reset=False)
pll.create_clkout(self.cd_idelay, 400e6)
platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin)

# IDelayCtrl.
self.idelayctrl = USPIDELAYCTRL(cd_ref=self.cd_idelay, cd_sys=self.cd_sys)

# BaseSoC ------------------------------------------------------------------------------------------

class BaseSoC(SoCCore):
def __init__(self, sys_clk_freq=int(75e6), with_sdcard=False, with_led_chaser=False, **kwargs):
platform = mlk_cu07_ku15p.Platform()

# CRG --------------------------------------------------------------------------------------
self.crg = _CRG(platform, sys_clk_freq)

# SoCCore ----------------------------------------------------------------------------------
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Milianke MLK-CU07-KU15P", **kwargs)

# DDR4 SDRAM -------------------------------------------------------------------------------
if not self.integrated_main_ram_size:
self.ddrphy = usddrphy.USPDDRPHY(platform.request("ddram"),
memtype = "DDR4",
sys_clk_freq = sys_clk_freq,
iodelay_clk_freq = 400e6)
self.add_sdram("sdram",
phy = self.ddrphy,
module = MT40A512M16(sys_clk_freq, "1:4"),
size = 0x40000000,
l2_cache_size = kwargs.get("l2_size", 8192)
)

# SDCard -----------------------------------------------------------------------------------
if with_sdcard:
self.add_sdcard()

# Leds -------------------------------------------------------------------------------------
if with_led_chaser:
self.leds = LedChaser(
pads = platform.request_all("user_led"),
sys_clk_freq = sys_clk_freq)

# Build --------------------------------------------------------------------------------------------

def main():
from litex.build.parser import LiteXArgumentParser
parser = LiteXArgumentParser(platform=mlk_cu07_ku15p.Platform, description="LiteX SoC on Milianke MLK-CU07-KU15P.")
parser.add_target_argument("--sys-clk-freq", default=75e6, type=float, help="System clock frequency.")
parser.add_target_argument("--with-sdcard", action="store_true", help="Enable SDCard support.")
parser.add_target_argument("--with-led-chaser", action="store_true", help="Enable LED Chaser.")
args = parser.parse_args()

soc = BaseSoC(
sys_clk_freq = args.sys_clk_freq,
with_sdcard = args.with_sdcard,
with_led_chaser = args.with_led_chaser,
**parser.soc_argdict
)
builder = Builder(soc, **parser.builder_argdict)
if args.build:
builder.build(**parser.toolchain_argdict)

if args.load:
prog = soc.platform.create_programmer()
prog.load_bitstream(builder.get_bitstream_filename(mode="sram"))

if __name__ == "__main__":
main()