Skip to content

Commit 62e9bb3

Browse files
committed
platforms/targets: Add MLK-CU07-KU15P support
Add the platform and reference LiteX target for the Milianke MLK-H5P-CU07-KU15P development board. Define the system and DDR reference clocks, UART, SD card, user LEDs and buttons, I2C, and the board's 4 GB 64-bit DDR4 interface. Add a target using the UltraScale+ DDR PHY, deterministic power-on reset, optional SD card support, and an optional LED chaser. Configure OpenFPGALoader and SPI x4 bitstream generation for the XCKU15P-FFVA1156-2-E device.
1 parent 2f06d08 commit 62e9bb3

3 files changed

Lines changed: 262 additions & 0 deletions

File tree

docs/boards_inventory.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ python3 .github/scripts/generate_board_inventory.py --write
131131
| `microphase_a7_lite` | microphase_a7_lite | vivado | `100000000.0` | Ethernet, SDCard, SPI SDCard, SPI Flash | included |
132132
| `microsoft_catapult_v3` | microsoft_catapult_v3 | quartus | `100000000.0` | - | included |
133133
| `mist` | mist | quartus | `50000000.0` | Video Terminal | included |
134+
| `mlk_cu07_ku15p` | mlk_cu07_ku15p | vivado | `75000000.0` | SDCard | included |
134135
| `mlkpai_fs01_dr1v90m` | mlkpai_fs01_dr1v90m | td | `25000000.0` | - | included |
135136
| `mnt_rkx7` | mnt_rkx7 | vivado | `100000000.0` | Ethernet, Etherbone, SDCard, SPI SDCard, SPI Flash, USB Host | included |
136137
| `muselab_icesugar` | muselab_icesugar | icestorm | `24000000.0` | - | included |
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#
2+
# This file is part of LiteX-Boards.
3+
#
4+
# Copyright (c) 2026 Yu Jin <lambda.jinyu@gmail.com>
5+
# SPDX-License-Identifier: BSD-2-Clause
6+
7+
from litex.build.generic_platform import *
8+
from litex.build.openfpgaloader import OpenFPGALoader
9+
from litex.build.xilinx import XilinxUSPPlatform
10+
11+
# IOs ----------------------------------------------------------------------------------------------
12+
13+
_io = [
14+
# Clk / Rst.
15+
("clk100", 0, Pins("AH18"), IOStandard("LVCMOS18")),
16+
("clk100_ddr", 0,
17+
Subsignal("p", Pins("AK17")),
18+
Subsignal("n", Pins("AK16")),
19+
IOStandard("DIFF_SSTL12")
20+
),
21+
("cpu_resetn", 0, Pins("J23"), IOStandard("LVCMOS18"), Misc("PULLTYPE PULLUP")),
22+
23+
# Buttons.
24+
("user_btn", 0, Pins("G26"), IOStandard("LVCMOS18")),
25+
("user_btn", 1, Pins("G25"), IOStandard("LVCMOS18")),
26+
("user_btn", 2, Pins("H24"), IOStandard("LVCMOS18")),
27+
28+
# Leds.
29+
("user_led", 0, Pins("AP9"), IOStandard("LVCMOS33")),
30+
("user_led", 1, Pins("AN9"), IOStandard("LVCMOS33")),
31+
("user_led", 2, Pins("AP8"), IOStandard("LVCMOS33")),
32+
("user_led", 3, Pins("AN8"), IOStandard("LVCMOS33")),
33+
("user_led", 4, Pins("AL10"), IOStandard("LVCMOS33")),
34+
("user_led", 5, Pins("AM10"), IOStandard("LVCMOS33")),
35+
("user_led", 6, Pins("AE11"), IOStandard("LVCMOS33")),
36+
37+
# Serial.
38+
("serial", 0,
39+
Subsignal("tx", Pins("AN13")),
40+
Subsignal("rx", Pins("AP13")),
41+
IOStandard("LVCMOS33")
42+
),
43+
44+
# SDCard.
45+
("sdcard", 0,
46+
Subsignal("clk", Pins("B9")),
47+
Subsignal("cmd", Pins("A10"), Misc("PULLTYPE PULLUP")),
48+
Subsignal("data", Pins("B11 A9 C8 B10"), Misc("PULLTYPE PULLUP")),
49+
Subsignal("cd", Pins("C11"), Misc("PULLTYPE PULLUP")),
50+
IOStandard("LVCMOS18")
51+
),
52+
53+
# Runtime QSPI is intentionally omitted. The source pin table assigns C8
54+
# to both SD D2 and flash CS, and the dedicated flash clock needs STARTUPE3.
55+
56+
# I2C EEPROM / RTC.
57+
("i2c", 0,
58+
Subsignal("scl", Pins("AP11")),
59+
Subsignal("sda", Pins("AP10")),
60+
IOStandard("LVCMOS33")
61+
),
62+
63+
# 4GB DDR4 SDRAM: 4 x Hynix H5AN8G6NCJR-VKI, modeled as MT40A512M16.
64+
("ddram", 0,
65+
Subsignal("a", Pins(
66+
"AM34 AN26 AP34 AK26 AL32 AK28 AK32 AL30",
67+
"AL34 AP26 AK31 AL33 AH32 AM32"),
68+
IOStandard("SSTL12_DCI")),
69+
Subsignal("ba", Pins("AJ31 AK27"), IOStandard("SSTL12_DCI")),
70+
Subsignal("bg", Pins("AJ30"), IOStandard("SSTL12_DCI")),
71+
Subsignal("ras_n", Pins("AJ33"), IOStandard("SSTL12_DCI")),
72+
Subsignal("cas_n", Pins("AJ34"), IOStandard("SSTL12_DCI")),
73+
Subsignal("we_n", Pins("AJ28"), IOStandard("SSTL12_DCI")),
74+
Subsignal("cs_n", Pins("AH33"), IOStandard("SSTL12_DCI")),
75+
Subsignal("act_n", Pins("AH31"), IOStandard("SSTL12_DCI")),
76+
Subsignal("dm", Pins("Y26 V27 AA22 W23 AE25 AD21 AM21 AJ21"),
77+
IOStandard("POD12_DCI")),
78+
Subsignal("dq", Pins(
79+
"AD25 AA27 AC24 AB25 AB24 AB27 AD26 AB26",
80+
"U25 W28 W26 W29 U24 V29 V26 Y28",
81+
"AB20 Y23 AC22 AA24 AA20 AA25 AC23 AA23",
82+
"U22 T22 T23 W21 U21 Y25 V21 W25",
83+
"AJ23 AF23 AJ24 AG25 AH23 AF24 AH22 AG24",
84+
"AG20 AE22 AF20 AF22 AD20 AE23 AG22 AE20",
85+
"AM22 AM24 AN22 AN24 AN23 AP24 AP23 AP25",
86+
"AL24 AL25 AK22 AL22 AK23 AM20 AL20 AL23"),
87+
IOStandard("POD12_DCI")),
88+
Subsignal("dqs_p", Pins("AC26 U26 AB21 V22 AH24 AG21 AP20 AJ20"),
89+
IOStandard("DIFF_POD12_DCI")),
90+
Subsignal("dqs_n", Pins("AC27 U27 AC21 V23 AJ25 AH21 AP21 AK20"),
91+
IOStandard("DIFF_POD12_DCI")),
92+
Subsignal("clk_p", Pins("AJ29"), IOStandard("DIFF_SSTL12_DCI")),
93+
Subsignal("clk_n", Pins("AK30"), IOStandard("DIFF_SSTL12_DCI")),
94+
Subsignal("cke", Pins("AH27"), IOStandard("SSTL12_DCI")),
95+
Subsignal("odt", Pins("AH28"), IOStandard("SSTL12_DCI")),
96+
Subsignal("reset_n", Pins("AJ26"), IOStandard("LVCMOS12")),
97+
Misc("SLEW=FAST")
98+
),
99+
]
100+
101+
# Platform -----------------------------------------------------------------------------------------
102+
103+
class Platform(XilinxUSPPlatform):
104+
default_clk_name = "clk100"
105+
default_clk_period = 1e9/100e6
106+
107+
def __init__(self, toolchain="vivado"):
108+
XilinxUSPPlatform.__init__(self, "xcku15p-ffva1156-2-e", _io, toolchain=toolchain)
109+
110+
def create_programmer(self):
111+
return OpenFPGALoader(fpga_part="xcku15p-ffva1156", cable="ft2232")
112+
113+
def do_finalize(self, fragment):
114+
self.add_platform_command("set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]")
115+
self.add_platform_command("set_property BITSTREAM.CONFIG.CONFIGRATE 85.0 [current_design]")
116+
self.add_platform_command("set_property BITSTREAM.CONFIG.SPI_FALL_EDGE YES [current_design]")
117+
self.add_platform_command("set_property BITSTREAM.GENERAL.COMPRESS true [current_design]")
118+
self.add_platform_command("set_property CONFIG_VOLTAGE 1.8 [current_design]")
119+
self.add_platform_command("set_property CFGBVS GND [current_design]")
120+
self.add_platform_command("set_property CONFIG_MODE SPIx4 [current_design]")
121+
self.add_platform_command("set_property BITSTREAM.CONFIG.UNUSEDPIN pulldown [current_design]")
122+
XilinxUSPPlatform.do_finalize(self, fragment)
123+
self.add_period_constraint(self.lookup_request("clk100", loose=True), 1e9/100e6)
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env python3
2+
3+
#
4+
# This file is part of LiteX-Boards.
5+
#
6+
# Copyright (c) 2026 Yu Jin <lambda.jinyu@gmail.com>
7+
# SPDX-License-Identifier: BSD-2-Clause
8+
9+
from migen import *
10+
11+
from litex.gen import *
12+
13+
from litex_boards.platforms import mlk_cu07_ku15p
14+
15+
from litex.soc.cores.clock import USMMCM, USIDELAYCTRL
16+
from litex.soc.cores.led import LedChaser
17+
from litex.soc.integration.builder import Builder
18+
from litex.soc.integration.soc_core import SoCCore
19+
20+
from litedram.modules import MT40A512M16
21+
from litedram.phy import usddrphy
22+
23+
# CRG ----------------------------------------------------------------------------------------------
24+
25+
class _CRG(LiteXModule):
26+
def __init__(self, platform, sys_clk_freq):
27+
self.rst = Signal()
28+
self.cd_sys = ClockDomain()
29+
self.cd_sys4x = ClockDomain()
30+
self.cd_idelay = ClockDomain()
31+
32+
clk100 = platform.request("clk100")
33+
platform.request("cpu_resetn")
34+
35+
# Keep reset independent of the active-low button, which can float low
36+
# on some board revisions. The counter provides a deterministic POR.
37+
self.cd_por = ClockDomain()
38+
por_count = Signal(16, reset=2**16 - 1)
39+
por_done = Signal()
40+
self.comb += [
41+
self.cd_por.clk.eq(clk100),
42+
por_done.eq(por_count == 0),
43+
]
44+
self.sync.por += If(~por_done, por_count.eq(por_count - 1))
45+
46+
self.pll = pll = USMMCM(speedgrade=-2)
47+
self.comb += pll.reset.eq(~por_done | self.rst)
48+
pll.register_clkin(clk100, 100e6)
49+
pll.create_clkout(self.cd_sys, sys_clk_freq, with_reset=False)
50+
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq, with_reset=False)
51+
pll.create_clkout(self.cd_idelay, 400e6)
52+
platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin)
53+
54+
self.idelayctrl = USIDELAYCTRL(cd_ref=self.cd_idelay, cd_sys=self.cd_sys)
55+
56+
# BaseSoC ------------------------------------------------------------------------------------------
57+
58+
class BaseSoC(SoCCore):
59+
def __init__(self, sys_clk_freq=int(75e6), with_sdcard=False, with_led_chaser=False, **kwargs):
60+
platform = mlk_cu07_ku15p.Platform()
61+
62+
self.crg = _CRG(platform, sys_clk_freq)
63+
64+
SoCCore.__init__(
65+
self,
66+
platform,
67+
sys_clk_freq,
68+
ident="LiteX SoC on Milianke MLK-CU07-KU15P",
69+
**kwargs,
70+
)
71+
72+
if not self.integrated_main_ram_size:
73+
self.ddrphy = usddrphy.USPDDRPHY(
74+
platform.request("ddram"),
75+
memtype="DDR4",
76+
sys_clk_freq=sys_clk_freq,
77+
iodelay_clk_freq=400e6,
78+
)
79+
self.add_sdram(
80+
"sdram",
81+
phy=self.ddrphy,
82+
module=MT40A512M16(sys_clk_freq, "1:4"),
83+
size=0x40000000,
84+
l2_cache_size=kwargs.get("l2_size", 8192),
85+
)
86+
87+
if with_sdcard:
88+
self.add_sdcard()
89+
90+
if with_led_chaser:
91+
self.leds = LedChaser(
92+
pads=platform.request_all("user_led"),
93+
sys_clk_freq=sys_clk_freq,
94+
)
95+
96+
# Build --------------------------------------------------------------------------------------------
97+
98+
def main():
99+
from litex.build.parser import LiteXArgumentParser
100+
101+
parser = LiteXArgumentParser(
102+
platform=mlk_cu07_ku15p.Platform,
103+
description="LiteX SoC on Milianke MLK-CU07-KU15P.",
104+
)
105+
parser.add_target_argument(
106+
"--sys-clk-freq",
107+
default=75e6,
108+
type=float,
109+
help="System clock frequency.",
110+
)
111+
parser.add_target_argument(
112+
"--with-sdcard",
113+
action="store_true",
114+
help="Enable SD card support.",
115+
)
116+
parser.add_target_argument(
117+
"--with-led-chaser",
118+
action="store_true",
119+
help="Enable LED chaser.",
120+
)
121+
args = parser.parse_args()
122+
123+
soc = BaseSoC(
124+
sys_clk_freq=args.sys_clk_freq,
125+
with_sdcard=args.with_sdcard,
126+
with_led_chaser=args.with_led_chaser,
127+
**parser.soc_argdict,
128+
)
129+
builder = Builder(soc, **parser.builder_argdict)
130+
if args.build:
131+
builder.build(**parser.toolchain_argdict)
132+
133+
if args.load:
134+
prog = soc.platform.create_programmer()
135+
prog.load_bitstream(builder.get_bitstream_filename(mode="sram"))
136+
137+
if __name__ == "__main__":
138+
main()

0 commit comments

Comments
 (0)