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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ etctmp/
/cscope.*
/defconfig
/defconfig.tmp.bak
/Image-*
/Make.defs
/nuttx
/nuttx32
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
154 changes: 154 additions & 0 deletions Documentation/platforms/risc-v/eic7700x/boards/eic7700-evb/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
=================
ESWIN EIC7700 EVB
=================

.. tags:: chip:eic7700x, arch:risc-v, vendor:eswin, experimental

.. figure:: eic7700-evb.jpg
:align: center
:alt: The ESWIN EIC7700 EVB, a development board carrying the EIC7700X SoC

ESWIN EIC7700 EVB

The `EIC7700 EVB <https://www.eswincomputing.com/en/products/index/36.html>`_
is ESWIN's own evaluation board for the
:doc:`EIC7700X <../../index>` SoC. Where the
:doc:`PINE64 StarPro64 <../starpro64/index>` is a single board computer built
around the chip, the EVB brings out most of the SoC's interfaces, so it is the
board to develop drivers on.

Features
========

* ESWIN EIC7700X, 4 x RV64GC 1.4 GHz RISC-V cores
* 16 GB LPDDR5
* eMMC, microSD and SPI NOR flash, the last holding the boot firmware
* 2 x Ethernet (GMAC, RGMII)
* 2 x USB 3.0, host and device capable
* HDMI output, with CEC
* PCIe 3.0 slot, and two M.2 slots, for SATA and for a WiFi and Bluetooth
module
* USB serial console, RS232 on a DB9, and further UARTs on the headers
* Expansion headers carrying GPIO, I2C, SPI and PWM
* PWM fan header

.. warning::

This port is under development and drives a subset of the board.
`Peripheral Support`_ below records what it drives.

Serial Console
==============

The console is UART0 at **115200 8N1**. It is wired to the on-board FT4232
USB bridge, so a single USB cable carries it and no separate USB serial
adapter is needed. The bridge presents four ports, of which UART0 is the
third; on Linux that is usually ``/dev/ttyUSB2``, the first of the four
being the JTAG interface:

.. code:: console

$ screen /dev/ttyUSB2 115200

Buttons and LEDs
================

The board has four LEDs on GPIO lines 107 to 110 and one push button, ``OK``,
on GPIO line 6. NuttX does not drive any of them yet.

Power Supply
============

The board is powered through its barrel jack. The core rails, including the
NPU rail, are set by regulators on I2C bus 1, which NuttX leaves alone: the
firmware has already configured them by the time NuttX starts, and writing to
them changes a core voltage.

RISC-V Toolchain
================

Install `xPack GNU RISC-V Embedded GCC (riscv-none-elf)
<https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases>`_ and
add its ``bin`` directory to ``PATH``, as described for the
:doc:`PINE64 StarPro64 <../starpro64/index>`.

Building NuttX
==============

Configure and build:

.. code:: console

$ cd nuttx
$ tools/configure.sh eic7700-evb:nsh
$ make

Then build the applications filesystem and package it with the kernel:

.. code:: console

$ make export
$ pushd ../apps
$ tools/mkimport.sh -z -x ../nuttx/nuttx-export-*.tar.gz
$ make import
$ popd
$ boards/risc-v/eic7700x/common/tools/mkimage.sh

The image is the kernel, then padding, then a RAM disk holding the
applications. Use the script rather than padding by hand: the RAM disk is
found at run time by searching memory for its header, and that search runs
after BSS has been cleared, so the disk has to start above ``_ebss`` or it is
zeroed before anything looks for it. The script reads ``_ebss`` from the
kernel and pads to suit.

The result is ``Image-eic7700-evb``.

Booting NuttX
=============

The board boots over TFTP from U-Boot, as the
:doc:`PINE64 StarPro64 <../starpro64/index>` does. Copy
``Image-eic7700-evb`` and the device tree to the TFTP server:

.. code:: console

$ wget https://github.com/lupyuen/nuttx-starpro64/raw/refs/heads/main/eic7700-evb.dtb
$ scp Image-eic7700-evb eic7700-evb.dtb tftpserver:/tftpfolder/

Interrupt U-Boot with Ctrl-C at power on and boot the image:

.. code:: console

# Change to your TFTP Server
$ setenv tftp_server 192.168.x.x
$ saveenv
$ dhcp ${kernel_addr_r} ${tftp_server}:Image-eic7700-evb
$ tftpboot ${fdt_addr_r} ${tftp_server}:eic7700-evb.dtb
$ fdt addr ${fdt_addr_r}
$ booti ${kernel_addr_r} - ${fdt_addr_r}

NuttShell appears on the console.

Configurations
==============

.. code:: console

$ tools/configure.sh eic7700-evb:<config-name>

nsh
---

NuttShell on UART0 at 115200 8N1, with the RAM disk mounted and ``/proc``
available. Built-in applications are supported; none are enabled.

Peripheral Support
==================

NuttX for the EIC7700 EVB supports these peripherals:

======================== ======= =====
Peripheral Support NOTES
======================== ======= =====
UART Yes
======================== ======= =====
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
PINE64 StarPro64
================

.. tags:: chip:eic7700x, arch:risc-v, vendor:pine64, experimental

`PINE64 StarPro64 <https://lupyuen.github.io/articles/starpro64>`_
is a RISC-V Single-Board Computer based on the ESWIN EIC7700X RISC-V SoC
with Quad-Core 64-bit RISC-V CPU, 32 GB LPDDR5 RAM and 100 Mbps Ethernet.
Expand Down Expand Up @@ -89,16 +91,21 @@ This produces the NuttX Kernel ``nuttx.bin``. Next, build the NuttX Apps Filesy
$ tools/mkimport.sh -z -x ../nuttx/nuttx-export-*.tar.gz
$ make import
$ popd
$ genromfs -f initrd -d ../apps/bin -V "NuttXBootVol"

This generates the Initial RAM Disk ``initrd``.

Package the NuttX Kernel and Initial RAM Disk into a NuttX Image:
Package the NuttX Kernel and the applications into a NuttX Image:

.. code:: console

$ head -c 65536 /dev/zero >/tmp/nuttx.pad
$ cat nuttx.bin /tmp/nuttx.pad initrd >Image-starpro64
$ boards/risc-v/eic7700x/common/tools/mkimage.sh

The image is the kernel, then padding, then a RAM disk holding the
applications. Use the script rather than padding by hand. The RAM disk is
found at run time by searching memory for its header, and that search runs
after BSS has been cleared, so the disk has to start above ``_ebss`` or it
is zeroed before anything looks for it. The script reads ``_ebss`` from the
kernel and pads to suit; a fixed pad works only until BSS grows past it, and
when it does the board hangs during start up with nothing on the console at
all, because the failure happens before there is a console to report it.

The NuttX Image ``Image-starpro64`` will be copied to the TFTP Server in the next step.

Expand Down
2 changes: 2 additions & 0 deletions Documentation/platforms/risc-v/eic7700x/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
ESWIN EIC7700X
==============

.. tags:: chip:eic7700x, arch:risc-v, vendor:eswin

`ESWIN EIC7700X <https://www.eswincomputing.com/en/products/index/36.html>`_ is a 64-bit RISC-V SoC with 4 RISC-V Cores:

- **Processors:** 4 x RV64GC 1.4 GHz 64-bit RISC-V Cores
Expand Down
2 changes: 2 additions & 0 deletions arch/risc-v/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ config ARCH_CHIP_SG2000

config ARCH_CHIP_EIC7700X
bool "ESWIN EIC7700X"
select ARCH_BOARD_COMMON
select ARCH_HAVE_ELF_EXECUTABLE
select ARCH_RV64
select ARCH_RV_ISA_M
select ARCH_RV_ISA_A
Expand Down
12 changes: 8 additions & 4 deletions arch/risc-v/src/eic7700x/chip.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,17 @@
#include "riscv_percpu.h"

/****************************************************************************
* Public Data
* Pre-processor Definitions
****************************************************************************/

/* Hart ID that booted NuttX (0 to 3) */
/* The firmware does not hand over on a fixed Hart, so every Hart needs an
* idle stack of its own. With fewer than four, the Hart the firmware picked
* may have no slot and stops in __start before it can restart on Hart 0,
* which fails on some resets and not others. Fail the build instead.
*/

#ifndef __ASSEMBLY__
extern int g_eic7700x_boot_hart;
#if defined(CONFIG_SMP) && CONFIG_SMP_NCPUS < 4
# error "CONFIG_SMP_NCPUS must be 4: the firmware may boot NuttX on any Hart"
#endif

/****************************************************************************
Expand Down
31 changes: 27 additions & 4 deletions arch/risc-v/src/eic7700x/eic7700x_head.S
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,42 @@ __start:

real_start:

/* Load the number of CPUs that the kernel supports */
/* Take an idle stack. a0 holds the Hart ID, placed there by whoever
* entered us: the firmware on the first Hart in, and SBI on every Hart
* started afterwards.
*/

#ifdef CONFIG_SMP

/* One slot per CPU, indexed by Hart ID. A Hart outside the set NuttX
* knows about has no slot of its own and must not borrow one, so it stops
* here instead. chip.h refuses to build a configuration in which that
* could be the Hart the firmware handed over on.
*/

li t1, CONFIG_SMP_NCPUS
blt a0, t1, 1f

2:
csrw CSR_SIE, zero
wfi
j 2b

1:
riscv_set_inital_sp EIC7700X_IDLESTACK_BASE, SMP_STACK_SIZE, a0

#else
li t1, 1
#endif

/* Set stack pointer to the idle thread stack. Assume Hart 0. */
/* One CPU, so one slot, and it belongs to Hart 0. Any other Hart is here
* only to restart on Hart 0 and park, so it borrows the same slot; the two
* briefly overlap, which is why the SMP path above does not do this.
*/

li a2, 0
riscv_set_inital_sp EIC7700X_IDLESTACK_BASE, SMP_STACK_SIZE, a2

#endif

/* Disable all interrupts (i.e. timer, external) in sie */

csrw CSR_SIE, zero
Expand Down
6 changes: 2 additions & 4 deletions arch/risc-v/src/eic7700x/eic7700x_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,7 @@ void up_disable_irq(int irq)

if (0 <= extirq && extirq <= EIC7700X_PLIC_IRQS)
{
addr = EIC7700X_PLIC_ENABLE0 +
(g_eic7700x_boot_hart * EIC7700X_PLIC_ENABLE_HART);
addr = EIC7700X_PLIC_ENABLE_CPU0;
modifyreg32(addr + (4 * (extirq / 32)),
1 << (extirq % 32), 0);
}
Expand Down Expand Up @@ -200,8 +199,7 @@ void up_enable_irq(int irq)

if (0 <= extirq && extirq <= EIC7700X_PLIC_IRQS)
{
addr = EIC7700X_PLIC_ENABLE0 +
(g_eic7700x_boot_hart * EIC7700X_PLIC_ENABLE_HART);
addr = EIC7700X_PLIC_ENABLE_CPU0;
modifyreg32(addr + (4 * (extirq / 32)),
0, 1 << (extirq % 32));
}
Expand Down
3 changes: 1 addition & 2 deletions arch/risc-v/src/eic7700x/eic7700x_irq_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@
void *riscv_dispatch_irq(uintptr_t vector, uintptr_t *regs)
{
int irq = (vector >> RV_IRQ_MASK) | (vector & 0xf);
uintptr_t claim = EIC7700X_PLIC_CLAIM0 +
(g_eic7700x_boot_hart * EIC7700X_PLIC_CLAIM_HART);
uintptr_t claim = EIC7700X_PLIC_CLAIM_CPU0;

/* Firstly, check if the irq is machine external interrupt */

Expand Down
18 changes: 17 additions & 1 deletion arch/risc-v/src/eic7700x/eic7700x_mm_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,16 @@ void eic7700x_kernel_mappings(void)
binfo("map kernel text\n");
map_region(KFLASH_START, KFLASH_START, KFLASH_SIZE, MMU_KTEXT_FLAGS);

/* The kernel data region is mapped with 2 MiB pages rather than through
* map_region()'s 4 KiB ones. Everything in it, data, bss, the page
* tables, the idle stacks and the whole kernel heap, carries the same
* permissions, so the finer granularity buys nothing while costing one L3
* slab per 2 MiB from a pool of exactly two.
*/

binfo("map kernel data\n");
map_region(KSRAM_START, KSRAM_START, KSRAM_SIZE, MMU_KDATA_FLAGS);
mmu_ln_map_region(2, PGT_L2_VBASE, KSRAM_START, KSRAM_START,
KSRAM_SIZE, MMU_KDATA_FLAGS);

/* Connect the L1 and L2 page tables for the kernel text and data */

Expand All @@ -250,6 +258,14 @@ void eic7700x_kernel_mappings(void)
binfo("map the page pool\n");
mmu_ln_map_region(2, PGT_L2_VBASE, PGPOOL_START, PGPOOL_START,
PGPOOL_SIZE, MMU_KDATA_FLAGS);

/* Map the RAM disk. The page pool no longer covers it, so it needs its
* own mapping or the first read of /dev/ram0 faults.
*/

binfo("map the RAM disk\n");
mmu_ln_map_region(2, PGT_L2_VBASE, RAMDISK_START, RAMDISK_START,
RAMDISK_SIZE, MMU_KDATA_FLAGS);
}

/****************************************************************************
Expand Down
27 changes: 27 additions & 0 deletions arch/risc-v/src/eic7700x/eic7700x_pgalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@
#include <nuttx/debug.h>
#include <arch/board/board_memorymap.h>

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

/* The granule allocator behind mm_pgalloc() counts its pages in a uint16_t,
* and gran_initialize() refuses a pool with more than UINT16_MAX of them,
* returning NULL. mm_pginitialize() then asserts, so an oversized pool is a
* board that does not boot rather than a board with less memory than asked
* for. See mm/mm_gran/mm_gran.h and mm/mm_gran/mm_graninit.c.
*/

#if (CONFIG_ARCH_PGPOOL_SIZE / CONFIG_MM_PGSIZE) > 65535
# error "Page pool has more pages than the granule allocator can count"
#endif

/****************************************************************************
* Public Functions
****************************************************************************/
Expand All @@ -50,6 +65,18 @@ void up_allocate_pgheap(void **heap_start, size_t *heap_size)
{
DEBUGASSERT(heap_start && heap_size);

/* The linker script and Kconfig describe this pool separately, and both
* descriptions are used: the size below comes from the linker, while
* riscv_pgvaddr() decides whether a page is in the pool using the Kconfig
* values. If they disagree, pages outside the smaller of the two get a
* virtual address of zero and are then written through, which on this SoC
* lands on the identity mapped low memory rather than faulting. Say so
* here instead of finding out that way.
*/

DEBUGASSERT(PGPOOL_START == CONFIG_ARCH_PGPOOL_PBASE);
DEBUGASSERT(PGPOOL_SIZE == CONFIG_ARCH_PGPOOL_SIZE);

*heap_start = (void *)PGPOOL_START;
*heap_size = (size_t)PGPOOL_SIZE;
}
Loading
Loading