Skip to content

Commit 5346e2d

Browse files
committed
boards: add Trenz TEL0025 support
Add a Lattice Nexus platform definition for the Trenz TEL0025 with clock, UART, LED, SPI flash, SDCard, HyperRAM, and CSI resources. Add a board target with NXOSCA/NXPLL clocking, HyperRAM as main RAM, optional native SDCard/SPI-SD/SPI flash support, and programming hooks for SRAM load or SPI flash. Guard against Linux CPU variants that place OpenSBI beyond the board's 8MiB HyperRAM window, while keeping the single-core VexRiscv Linux path usable for HyperRAM boot experiments. Update the generated board inventory entry for the new target.
1 parent e2cb2ab commit 5346e2d

3 files changed

Lines changed: 330 additions & 0 deletions

File tree

docs/boards_inventory.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ python3 .github/scripts/generate_board_inventory.py --write
216216
| `trenz_te0741` | trenz_te0741 | vivado | `100000000.0` | - | included |
217217
| `trenz_te0890` | trenz_te0890 | vivado | `100000000.0` | - | included |
218218
| `trenz_tec0117` | trenz_tec0117 | gowin | `25000000.0` | SDCard, SPI SDCard | included |
219+
| `trenz_tel0025` | trenz_tel0025 | radiant | `50000000.0` | SDCard, SPI SDCard, SPI Flash | included |
219220
| `trenz_tem0006` | trenz_tem0006 | libero_soc | `12000000.0` | - | included |
220221
| `tul_pynq_z2` | tul_pynq_z2 | vivado | `100000000.0` | - | included |
221222
| `xilinx_ac701` | xilinx_ac701 | vivado | `100000000.0` | Ethernet, SPI Flash, PCIe | included |
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#
2+
# This file is part of LiteX-Boards.
3+
#
4+
# Copyright (c) 2026 Florent Kermarrec <florent@enjoy-digital.fr>
5+
# SPDX-License-Identifier: BSD-2-Clause
6+
7+
from litex.build.generic_platform import *
8+
from litex.build.lattice import LatticeNexusPlatform
9+
from litex.build.openfpgaloader import OpenFPGALoader
10+
11+
# IOs ----------------------------------------------------------------------------------------------
12+
13+
_io = [
14+
# Clk / Rst
15+
("clk25", 0, Pins("C1"), IOStandard("LVCMOS33")), # CLK_25M.
16+
("clk25_aux", 0, Pins("G1"), IOStandard("LVCMOS33")), # CLK1_25M.
17+
("clk12", 0, Pins("E6"), IOStandard("LVCMOS33")), # CLK_12M.
18+
("user_btn_n", 0, Pins("C8"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
19+
20+
# Leds (RGB LED, active-low).
21+
("user_led", 0, Pins("A7"), IOStandard("LVCMOS33")),
22+
("user_led", 1, Pins("A8"), IOStandard("LVCMOS33")),
23+
("user_led", 2, Pins("B8"), IOStandard("LVCMOS33")),
24+
("rgb_led", 0,
25+
Subsignal("r", Pins("A7")),
26+
Subsignal("g", Pins("A8")),
27+
Subsignal("b", Pins("B8")),
28+
IOStandard("LVCMOS33"),
29+
),
30+
31+
# Serial (FT2232H channel A).
32+
("serial", 0,
33+
Subsignal("rx", Pins("D2"), IOStandard("LVCMOS33")), # ADBUS0 / FTDI TXD.
34+
Subsignal("tx", Pins("B1"), IOStandard("LVCMOS33")), # ADBUS1 / FTDI RXD.
35+
),
36+
37+
# SPI Flash.
38+
("spiflash", 0,
39+
Subsignal("cs_n", Pins("B4")),
40+
Subsignal("clk", Pins("B3")),
41+
Subsignal("mosi", Pins("A4")),
42+
Subsignal("miso", Pins("A5")),
43+
Subsignal("wp", Pins("A6")),
44+
Subsignal("hold", Pins("B7")),
45+
IOStandard("LVCMOS33"),
46+
Misc("SLEWRATE=FAST"),
47+
),
48+
("spiflash4x", 0,
49+
Subsignal("cs_n", Pins("B4")),
50+
Subsignal("clk", Pins("B3")),
51+
Subsignal("dq", Pins("A4 A5 A6 B7")),
52+
IOStandard("LVCMOS33"),
53+
Misc("SLEWRATE=FAST"),
54+
),
55+
56+
# SDCard.
57+
("spisdcard", 0,
58+
Subsignal("clk", Pins("A10")),
59+
Subsignal("mosi", Pins("A12"), Misc("PULLMODE=UP")),
60+
Subsignal("cs_n", Pins("B12"), Misc("PULLMODE=UP")),
61+
Subsignal("miso", Pins("B9"), Misc("PULLMODE=UP")),
62+
IOStandard("LVCMOS33"),
63+
Misc("SLEWRATE=FAST"),
64+
),
65+
("sdcard", 0,
66+
Subsignal("data", Pins("B9 A9 B13 B12"), Misc("PULLMODE=UP")),
67+
Subsignal("cmd", Pins("A12"), Misc("PULLMODE=UP")),
68+
Subsignal("clk", Pins("A10")),
69+
Subsignal("cd", Pins("B14"), Misc("PULLMODE=UP")),
70+
IOStandard("LVCMOS33"),
71+
Misc("SLEWRATE=FAST"),
72+
),
73+
74+
# HyperRAM.
75+
("hyperram", 0,
76+
Subsignal("dq", Pins("M4 K5 N4 K6 L7 P7 N7 M7"), IOStandard("LVCMOS18H")),
77+
Subsignal("rwds", Pins("N5"), IOStandard("LVCMOS18H")),
78+
Subsignal("cs_n", Pins("K4"), IOStandard("LVCMOS18H")),
79+
Subsignal("rst_n", Pins("L4"), IOStandard("LVCMOS18H")),
80+
Subsignal("clk_p", Pins("N6"), IOStandard("LVDS")),
81+
Subsignal("clk_n", Pins("P6"), IOStandard("LVDS")),
82+
Misc("SLEWRATE=FAST"),
83+
),
84+
85+
# CSI control GPIOs / I2C.
86+
("csi_i2c", 0,
87+
Subsignal("sda", Pins("E2"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
88+
Subsignal("scl", Pins("E1"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
89+
),
90+
("csi_i2c", 1,
91+
Subsignal("scl", Pins("G5"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
92+
Subsignal("sda", Pins("G6"), IOStandard("LVCMOS33"), Misc("PULLMODE=UP")),
93+
),
94+
("csi_gpio", 0,
95+
Subsignal("gpio0", Pins("J6")),
96+
Subsignal("gpio1", Pins("J5")),
97+
IOStandard("LVCMOS33"),
98+
),
99+
("csi_gpio", 1,
100+
Subsignal("gpio0", Pins("H5")),
101+
Subsignal("gpio1", Pins("H6")),
102+
IOStandard("LVCMOS33"),
103+
),
104+
105+
# CSI differential lanes, exposed for future video work.
106+
# Use MIPI_DPHY on P lanes and LVCMOS12H on N lanes, as in Lattice examples.
107+
("csi", 0,
108+
Subsignal("clk_p", Pins("P11"), IOStandard("MIPI_DPHY")),
109+
Subsignal("clk_n", Pins("N11"), IOStandard("LVCMOS12H")),
110+
Subsignal("data_p", Pins("N13 P12 P10 P8"), IOStandard("MIPI_DPHY")),
111+
Subsignal("data_n", Pins("N14 P13 N10 N8"), IOStandard("LVCMOS12H")),
112+
),
113+
("csi", 1,
114+
Subsignal("clk_p", Pins("P9"), IOStandard("MIPI_DPHY")),
115+
Subsignal("clk_n", Pins("N9"), IOStandard("LVCMOS12H")),
116+
Subsignal("data_p", Pins("M9 K9 M14 L13"), IOStandard("MIPI_DPHY")),
117+
Subsignal("data_n", Pins("L9 K10 M13 L14"), IOStandard("LVCMOS12H")),
118+
),
119+
]
120+
121+
# Connectors ---------------------------------------------------------------------------------------
122+
123+
_connectors = [
124+
# 2.54mm placeholder headers.
125+
("x", "C11 E10 E9 G10 F11 D11 D12 E11 B10 G13 G14 F13 F14 E13 E14 E12 D14 C14 G12 F10"),
126+
("y", "D13 C13 C10 C9"),
127+
]
128+
129+
# Platform -----------------------------------------------------------------------------------------
130+
131+
class Platform(LatticeNexusPlatform):
132+
default_clk_name = "clk25"
133+
default_clk_period = 1e9/25e6
134+
135+
def __init__(self, toolchain="radiant", **kwargs):
136+
LatticeNexusPlatform.__init__(
137+
self,
138+
"LFD2NX-40-7BG196I",
139+
_io,
140+
_connectors,
141+
toolchain=toolchain,
142+
**kwargs)
143+
144+
# SPI pins are reused by the LiteSPI core after configuration.
145+
self.add_platform_command("ldc_set_sysconfig {{MASTER_SPI_PORT=DISABLE}}")
146+
147+
# Evaluation mode with the free Radiant license.
148+
if hasattr(self.toolchain, "set_prj_strategy_opts"):
149+
self.toolchain.set_prj_strategy_opts({"bit_ip_eval": "true"})
150+
151+
def create_programmer(self, cable="ft2232"):
152+
return OpenFPGALoader(cable=cable)
153+
154+
def do_finalize(self, fragment):
155+
LatticeNexusPlatform.do_finalize(self, fragment)
156+
self.add_period_constraint(self.lookup_request("clk25", loose=True), 1e9/25e6)
157+
self.add_period_constraint(self.lookup_request("clk25_aux", loose=True), 1e9/25e6)
158+
self.add_period_constraint(self.lookup_request("clk12", loose=True), 1e9/12e6)
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/usr/bin/env python3
2+
3+
#
4+
# This file is part of LiteX-Boards.
5+
#
6+
# Copyright (c) 2026 Florent Kermarrec <florent@enjoy-digital.fr>
7+
# SPDX-License-Identifier: BSD-2-Clause
8+
9+
from migen import *
10+
from migen.genlib.resetsync import AsyncResetSynchronizer
11+
12+
from litex.gen import *
13+
14+
from litex_boards.platforms import trenz_tel0025
15+
16+
from litex.soc.cores.clock import *
17+
from litex.soc.cores.hyperbus import HyperRAM
18+
from litex.soc.cores.led import LedChaser
19+
from litex.soc.integration.soc import *
20+
from litex.soc.integration.builder import *
21+
22+
# Constants ----------------------------------------------------------------------------------------
23+
24+
_HYPERRAM_SIZE = 8*MEGABYTE
25+
_OPENSBI_OFFSET = 0x00f00000
26+
_OPENSBI_SIZE = 0x00080000
27+
28+
# CRG ----------------------------------------------------------------------------------------------
29+
30+
class _CRG(LiteXModule):
31+
def __init__(self, platform, sys_clk_freq):
32+
self.rst = Signal()
33+
self.cd_sys = ClockDomain()
34+
self.cd_por = ClockDomain()
35+
36+
# # #
37+
38+
# Clk / Rst
39+
clk25 = platform.request("clk25")
40+
user_btn_n = platform.request("user_btn_n")
41+
42+
# Built-in oscillator for power-on reset.
43+
self.hf_clk = NXOSCA(platform)
44+
self.hf_clk.create_hf_clk(self.cd_por, 25e6)
45+
46+
# Power-on reset.
47+
por_count = Signal(16, reset=2**16-1)
48+
por_done = Signal()
49+
self.comb += por_done.eq(por_count == 0)
50+
self.sync.por += If(~por_done, por_count.eq(por_count - 1))
51+
self.specials += AsyncResetSynchronizer(self.cd_por, ~user_btn_n)
52+
53+
# PLL.
54+
self.sys_pll = sys_pll = NXPLL(platform=platform, create_output_port_clocks=True)
55+
self.comb += sys_pll.reset.eq(self.rst | ~por_done)
56+
sys_pll.register_clkin(clk25, 25e6)
57+
sys_pll.create_clkout(self.cd_sys, sys_clk_freq)
58+
self.specials += AsyncResetSynchronizer(self.cd_sys, ~sys_pll.locked)
59+
60+
# BaseSoC ------------------------------------------------------------------------------------------
61+
62+
class BaseSoC(SoCCore):
63+
def __init__(self, sys_clk_freq=50e6, toolchain="radiant",
64+
with_hyperram = True,
65+
with_led_chaser = True,
66+
with_sdcard = False,
67+
with_spi_sdcard = False,
68+
with_spi_flash = False,
69+
**kwargs):
70+
platform = trenz_tel0025.Platform(toolchain=toolchain)
71+
72+
# Linux -----------------------------------------------------------------------------------
73+
# The SMP/Vexii Linux variants place OpenSBI at main_ram + 0x00f00000.
74+
main_ram_size = kwargs.get("integrated_main_ram_size", 0) or 0
75+
if with_hyperram and not main_ram_size:
76+
main_ram_size = _HYPERRAM_SIZE
77+
cpu_type = kwargs.get("cpu_type", "vexriscv")
78+
cpu_variant = kwargs.get("cpu_variant", None) or "standard"
79+
with_opensbi = (
80+
(cpu_type == "vexriscv_smp" and cpu_variant == "linux") or
81+
(cpu_type == "vexiiriscv" and cpu_variant in ["linux", "debian"])
82+
)
83+
if with_opensbi and main_ram_size < (_OPENSBI_OFFSET + _OPENSBI_SIZE):
84+
raise ValueError(
85+
"vexriscv_smp/vexiiriscv Linux variants place OpenSBI beyond "
86+
"the TEL0025 8MiB HyperRAM window; use vexriscv linux instead."
87+
)
88+
89+
# CRG --------------------------------------------------------------------------------------
90+
self.crg = _CRG(platform, sys_clk_freq)
91+
92+
# SoCCore ----------------------------------------------------------------------------------
93+
SoCCore.__init__(self, platform, sys_clk_freq, ident="LiteX SoC on Trenz TEL0025", **kwargs)
94+
95+
# HyperRAM ---------------------------------------------------------------------------------
96+
if with_hyperram and not self.integrated_main_ram_size:
97+
self.hyperram = HyperRAM(
98+
pads = platform.request("hyperram"),
99+
latency = 7,
100+
latency_mode = "variable",
101+
sys_clk_freq = sys_clk_freq,
102+
clk_ratio = "4:1",
103+
)
104+
self.bus.add_slave("main_ram", slave=self.hyperram.bus, region=SoCRegion(
105+
origin = self.mem_map["main_ram"],
106+
size = _HYPERRAM_SIZE,
107+
mode = "rwx",
108+
))
109+
110+
# SPI Flash --------------------------------------------------------------------------------
111+
if with_spi_flash:
112+
from litespi.modules import MT25QL256A
113+
from litespi.opcodes import SpiNorFlashOpCodes as Codes
114+
self.add_spi_flash(
115+
mode = "4x",
116+
module = MT25QL256A(Codes.READ_1_1_4),
117+
with_master = False,
118+
)
119+
120+
# SDCard -----------------------------------------------------------------------------------
121+
if with_sdcard:
122+
self.add_sdcard()
123+
if with_spi_sdcard:
124+
self.add_spi_sdcard()
125+
126+
# Leds -------------------------------------------------------------------------------------
127+
if with_led_chaser:
128+
self.leds = LedChaser(
129+
pads = platform.request_all("user_led"),
130+
sys_clk_freq = sys_clk_freq,
131+
polarity = 1,
132+
)
133+
134+
# Build --------------------------------------------------------------------------------------------
135+
136+
def main():
137+
from litex.build.parser import LiteXArgumentParser
138+
parser = LiteXArgumentParser(platform=trenz_tel0025.Platform, description="LiteX SoC on Trenz TEL0025.")
139+
parser.add_target_argument("--sys-clk-freq", default=50e6, type=float, help="System clock frequency.")
140+
parser.add_target_argument("--no-hyperram", action="store_true", help="Disable HyperRAM support.")
141+
parser.add_target_argument("--with-spi-flash", action="store_true", help="Enable SPI Flash support.")
142+
parser.add_target_argument("--flash", action="store_true", help="Flash bitstream to SPI Flash.")
143+
sdopts = parser.target_group.add_mutually_exclusive_group()
144+
sdopts.add_argument("--with-sdcard", action="store_true", help="Enable SDCard support.")
145+
sdopts.add_argument("--with-spi-sdcard", action="store_true", help="Enable SPI-mode SDCard support.")
146+
args = parser.parse_args()
147+
148+
soc = BaseSoC(
149+
sys_clk_freq = args.sys_clk_freq,
150+
toolchain = args.toolchain,
151+
with_hyperram = not args.no_hyperram,
152+
with_sdcard = args.with_sdcard,
153+
with_spi_sdcard = args.with_spi_sdcard,
154+
with_spi_flash = args.with_spi_flash,
155+
**parser.soc_argdict
156+
)
157+
158+
builder = Builder(soc, **parser.builder_argdict)
159+
if args.build:
160+
builder.build(**parser.toolchain_argdict)
161+
162+
if args.load:
163+
prog = soc.platform.create_programmer()
164+
prog.load_bitstream(builder.get_bitstream_filename(mode="sram"))
165+
166+
if args.flash:
167+
prog = soc.platform.create_programmer()
168+
prog.flash(0, builder.get_bitstream_filename(mode="flash"), external=True)
169+
170+
if __name__ == "__main__":
171+
main()

0 commit comments

Comments
 (0)