Skip to content

boards/risc-v/eic7700x: Add the ESWIN EIC7700 EVB and share the SoC glue. - #19863

Merged
xiaoxiang781216 merged 7 commits into
apache:masterfrom
Fishwaldo:upstream-eic7700x-bringup
Aug 18, 2026
Merged

boards/risc-v/eic7700x: Add the ESWIN EIC7700 EVB and share the SoC glue.#19863
xiaoxiang781216 merged 7 commits into
apache:masterfrom
Fishwaldo:upstream-eic7700x-bringup

Conversation

@Fishwaldo

Copy link
Copy Markdown
Contributor

Summary

The EIC7700X port has one board directory holding one board, with everything
in it whether it describes the SoC or the PCB. This restructures that into the
common-plus-board layout NuttX provides, adds a second board, and makes the
arch side work on all four harts.

Refactoring StarPro64. boards/risc-v/eic7700x/common now holds what is
true of the SoC: the boot path that mounts the RAM disk and /proc before
calling the board's own bring-up, the linker script, the start-up scripts and
the image builder. ARCH_CHIP_EIC7700X selects ARCH_BOARD_COMMON, so the
symlinks the build makes always point at code that compiles. The StarPro64
directory keeps what is a fact about the PCB: its own board.h and
board_memorymap.h, since the include fallback is all or nothing, a bring-up
that owns the order its devices register in, and a board_config.h declaring
what that bring-up may call. This is the layout mpfs uses.

The image builder moves to common/tools and derives its output name from the
configuration. It computes the padding between the kernel and the RAM disk from
_ebss rather than assuming 64 KiB, which fails once BSS grows past it: the
disk lands below _ebss and the BSS clear zeroes it before anything looks for
it.

Adding the ESWIN EIC7700 EVB. ESWIN's own evaluation board for this SoC,
and the board this port has been developed against. It brings out most of the
SoC's interfaces where the StarPro64 is a single board computer built around
the chip. Everything shared already lives in common, so the board contributes
its own facts: which UART reaches which connector, which pads carry the boot
straps, and where its memory sits.

One warning for anyone reading the schematics: the summary tables on sheet 3 of
both boards are inherited from ESWIN's reference design and describe that
design, not the board in hand. On the EVB the console is UART0 through the
FT4232 bridge, UART1 goes to the M.2 socket and a header, and UART2 reaches the
RS232 port. The summary agrees with none of them.

Four harts. The firmware does not hand over on a fixed hart, so nothing may
assume one: the hart that arrives first records which it was, indexes its idle
stack by its own ID, and restarts on hart 0. CONFIG_SMP_NCPUS below four is
refused at build time, because the hart the firmware picked might have no slot
and would stop before it could restart. Secondary harts are released through
the common SBI helper. External interrupts are pinned to CPU0's PLIC context
rather than left wherever the boot loader routed them. The memory map gains
three corrections: the page pool no longer covers the RAM disk, the kernel data
region is mapped with 2 MiB pages, and the linker script and page pool agree on
where the pool starts.

Impact

EIC7700X boards only. StarPro64 keeps its configuration name and gains SMP, a
larger RAM window and RAMLOG; its files move but its behaviour is intended to
be unchanged. No effect on any other architecture.

Testing

EIC7700 EVB. OpenSBI's banner reported Boot HART ID: 1 for this boot, so it
is also the demonstration of the hart-agnostic entry: the firmware handed over
on hart 1 and NuttX still ran CPU0 on hart 0 with all four harts up.

A[CPU0] eic7700x_start_s: Firmware handed off on Hart 1, NuttX running on Hart 0
BC
NuttShell (NSH) NuttX-13.0.0
nsh> 
nsh> uname -a
NuttX 13.0.0 1fdf2da536 Aug 16 2026 18:11:21 risc-v eic7700-evb
nsh> cat /proc/cpuinfo
processor	: 0
hart		: 0
BogoMIPS	: 1.12
cpu MHz		: 0.000
isa		: rv64imafdc
mmu		: none
processor	: 1
hart		: 1
BogoMIPS	: 1.12
cpu MHz		: 0.000
isa		: rv64imafdc
mmu		: none
processor	: 2
hart		: 2
BogoMIPS	: 1.12
cpu MHz		: 0.000
isa		: rv64imafdc
mmu		: none
processor	: 3
hart		: 3
BogoMIPS	: 1.12
cpu MHz		: 0.000
isa		: rv64imafdc
mmu		: none
nsh> ls /dev
/dev:
 console
 kmsg
 null
 ram0
 ttyS0
 ttyS1
 ttyS2
 zero
nsh> free
      total       used       free    maxused    maxfree  nused  nfree name
  670994432      26152  670968280      51360  670946296     61      7 Kmem
  266338304     638976  265699328             265699328               Page
nsh>

/dev/ram0 is present, so the RAM disk survived the BSS clear with the padding
mkimage computed from _ebss, 145128 bytes for this build where the old
fixed pad was 64 KiB. Repeated resets have handed over on different harts and
boot the same way.

Depends-On: #19856
Depends-On: #19857

The port ran on whichever hart the firmware handed over on, with a single
idle stack.  The firmware does not pick the same hart every boot, so
nothing may assume one.

The hart that arrives first records which it was, indexes its idle stack
by its own ID, and restarts on hart 0; NuttX runs CPU0 there because that
is the only hart riscv_set_inital_sp() gives a whole idle stack to.  The
first hart in owns the one time setup, and that guard lives in .data
because it is read before the BSS is cleared.

CONFIG_SMP_NCPUS below four is refused in chip.h: the hart the firmware
picked would have no slot and would stop in __start before it could
restart, which fails on some resets and not others.

Secondary harts are released through the common SBI helper rather than a
private copy of the same call.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
External interrupts were enabled and claimed in the context of whichever
hart the firmware handed over on, which is not fixed.  They reset routed
to wherever the boot loader left them, and an interrupt delivered to a
context nobody services cannot be told from a device that never raised
one.

Enable and claim in CPU0's S mode context, which is hart 0's.  Steering a
source at another hart would mean choosing which, and NuttX has no way for
a driver to say.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Three faults in how the kernel maps itself.

The page pool covered the RAM disk, which the boot loader appends above
the kernel, so the BSS clear destroyed it before anything searched for it.
The pool now covers only pgram, and the RAM disk is mapped on its own
account.

The kernel data region is mapped with 2 MiB pages rather than 4 KiB ones.
Everything in it carries the same permissions, so the finer granularity
bought nothing while costing one L3 slab per 2 MiB from a pool of two.

The linker script and Kconfig describe the page pool separately and both
descriptions are used, so they now agree.  When they disagree, pages
outside the smaller of the two get a virtual address of zero and are
written through, which on this SoC lands on identity mapped low memory
rather than faulting.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
@github-actions github-actions Bot added Area: Build system Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. Board: risc-v labels Aug 16, 2026
@github-actions

github-actions Bot commented Aug 16, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

Comment thread boards/risc-v/eic7700x/eic7700-evb/include/board.h Outdated
The port had one board directory holding one board, with everything in it
whether it described the SoC or the PCB.  A second EIC7700X board follows,
so this adopts the common-plus-board layout NuttX provides, as mpfs uses.

boards/risc-v/eic7700x/common holds what is true of the SoC: the boot path
that mounts the RAM disk and /proc before calling the board's own bring
up, the linker script, the start up scripts and the image builder.
ARCH_CHIP_EIC7700X selects ARCH_BOARD_COMMON, so the symlinks the build
makes always point at code that compiles.

The board directory keeps what is a fact about the PCB: its own board.h
and board_memorymap.h, since the include fallback is all or nothing, a
bring up that owns the order its devices register in, and a board_config.h
declaring what that bring up may call.

The image builder moves to common/tools and derives its output name from
the configuration.  It computes the padding between the kernel and the RAM
disk from _ebss rather than assuming 64 KiB, which fails once BSS grows
past it: the disk lands below _ebss and the BSS clear zeroes it before
anything searches for it.

The StarPro64 configuration gains what the port now needs: four harts,
960 MiB of RAM, a larger task stack, a backtrace on assert, the system log
in RAM for dmesg, and ELF applications, for which ARCH_CHIP_EIC7700X now
selects ARCH_HAVE_ELF_EXECUTABLE.

board.h loses its LED definitions.  CONFIG_ARCH_LEDS is not set, nothing
implements board_autoled_on(), and the indices they gave named no LED.

The documentation pages gain the tags the template asks for.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
ESWIN's own evaluation board for this SoC.  Where the StarPro64 is a
single board computer built around the chip, the EVB brings out most of
the SoC's interfaces.

Everything shared with the StarPro64 is already in the common directory,
so this carries the board's own facts: which UART reaches which connector,
which pads carry the boot straps, where its memory sits, and a
configuration starting from the same place the StarPro64's does.

The summary tables on sheet 3 of both boards' schematics are inherited
from ESWIN's reference design and describe that design rather than either
board.  On this board the console is UART0 through the FT4232 bridge,
UART1 goes to the M.2 socket and a header, and UART2 reaches the RS232
port.

The documentation page follows the board template: a photograph, the
board's features, the console and its port on the FT4232 bridge, power,
the build and TFTP boot procedure, and what NuttX drives so far.

Boots to an NSH prompt over UART0 with all four harts running.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Both boards used the C string and memory routines while the
architecture's hand written ones sat unused beside them.  A 64 bit core
with a filesystem, a network stack and a display above it spends a great
deal of its time in these functions, and the assembly moves a register at
a time rather than a byte.

RISCV_STRING_FUNCTION selects the whole set, so one symbol covers memcpy,
memset, memmove and the string routines together.  The generic memset
tuning options go with it, since the C memset they tune is no longer
built.

These routines need the alignment fixes in apache#19856 and
apache#19857 to be correct on misaligned pointers.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
…ead.

USB class drivers do their transfers on the low priority queue and block
there, so one thread means a device waiting on a transfer stalls every
other user of the queue.  usbhost_cdcacm.c says so at compile time when
CONFIG_SCHED_LPNTHREADS is 1.

The high priority queue keeps one thread.  Nothing asks for more, and the
work it carries is meant to be short.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
@Fishwaldo
Fishwaldo force-pushed the upstream-eic7700x-bringup branch from 62c54f1 to ddddf0d Compare August 16, 2026 13:09
@github-actions

Copy link
Copy Markdown

🔗 Cross-repo PR dependencies

The read-only Build run reported the following dependent PR(s) and fetched head SHA(s):

CI run: https://github.com/apache/nuttx/actions/runs/31949016282

@acassis

acassis commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

@xiaoxiang781216 @jerpelea seems like the CI is broken again:

====================================================================================
Cmake in present: qemu-armv8a/citest_smp
Configuration/Tool: qemu-armv8a/citest_smp
2026-08-16 14:54:57
------------------------------------------------------------------------------------
  Cleaning...
  Configuring...
  Select HOST_LINUX=y
   TOOLS_DIR path is "/github/workspace/sources/nuttx"
   HOST = Linux
  Building NuttX...
  Running NuttX...
++ pwd
+ olddir=/github/workspace/sources/nuttx
+ nuttdir=/github/workspace/sources/nuttx/boards/arm64/qemu/qemu-armv8a/configs/citest_smp/../../../../../../
+ cd /github/workspace/sources/nuttx/boards/arm64/qemu/qemu-armv8a/configs/citest_smp/../../../../../../
+ confpath=/github/workspace/sources/nuttx/boards/arm64/qemu/qemu-armv8a/configs/citest_smp/config.yaml
+ jsonconf=/github/workspace/sources/nuttx/boards/arm64/qemu/qemu-armv8a/configs/citest_smp/session.json
+ testpath=/github/workspace/nuttx-ntfc/external/nuttx-testing
+ ntfc test --testpath=/github/workspace/nuttx-ntfc/external/nuttx-testing --confpath=/github/workspace/sources/nuttx/boards/arm64/qemu/qemu-armv8a/configs/citest_smp/config.yaml --jsonconf=/github/workspace/sources/nuttx/boards/arm64/qemu/qemu-armv8a/configs/citest_smp/session.json
CPU information header not found in output
YAML config:
{'config': {'cwd': './'},
 'product': {'cores': {'core0': {'conf_path': './build/.config',
                                 'device': 'qemu',
                                 'elf_path': './build/nuttx',
                                 'exec_args': '-cpu cortex-a53 -nographic -smp '
                                              '4 -machine '
                                              'virt,virtualization=on,gic-version=3 '
                                              '-net none -chardev '
                                              'stdio,id=con,mux=on -serial '
                                              'chardev:con -mon '
                                              'chardev=con,mode=readline',
                                 'exec_path': 'qemu-system-aarch64',
                                 'name': 'main'}},
             'name': 'qemu-armv8a-smp'}}
JSON config:
{'args': {'kv': []},
 'module': {'exclude_module': ['Nuttx_System_Fs_Fs'],
            'include_module': [],
            'order': []}}

@linguini1

Copy link
Copy Markdown
Contributor

Can you please submit your patches in smaller PRs where possible in the future? It makes it much easier to review

@xiaoxiang781216
xiaoxiang781216 merged commit 3627cf6 into apache:master Aug 18, 2026
78 of 94 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: risc-v Issues related to the RISC-V (32-bit or 64-bit) architecture Area: Build system Board: risc-v Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants