Skip to content
Open
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
7 changes: 7 additions & 0 deletions .github/workflows/test-build-aarch64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ on:
make-args:
required: false
type: string
extra-cflags:
# Extra flags appended to CFLAGS_EXTRA in .config (quoted, so spaces and
# multiple -D survive). Used for opt-in features such as GEM init.
required: false
type: string
psu-init-stub:
# Generate a build-only stub for the board psu_init_gpl.c (ZynqMP FSBL).
required: false
Expand Down Expand Up @@ -93,6 +98,8 @@ jobs:
make distclean

- name: Select config
env:
EXTRA_CFLAGS: ${{inputs.extra-cflags}}
run: |
cp ${{inputs.config-file}} .config
if [ -n "$EXTRA_CFLAGS" ]; then
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/test-configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,13 @@ jobs:
config-file: ./config/examples/zynqmp.config
make-args: CFLAGS_EXTRA=-DWOLFBOOT_ZYNQMP_PHY_INIT

zynqmp_gem_test:
uses: ./.github/workflows/test-build-aarch64.yml
with:
arch: aarch64
config-file: ./config/examples/zynqmp.config
extra-cflags: '-DWOLFBOOT_ZYNQMP_GEM_INIT -DZYNQMP_GEM_INIT_LIST={0xFF0B0000UL,1000},{0xFF0C0000UL,100}'

zynq7000_test:
uses: ./.github/workflows/test-build.yml
with:
Expand Down
19 changes: 19 additions & 0 deletions config/examples/zynqmp.config
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,22 @@ CFLAGS_EXTRA+=-DWOLFBOOT_SHA_BLOCK_SIZE=4096
#CFLAGS_EXTRA+=-DZYNQMP_GEM_BASE=0xFF0B0000UL
# A PHY behind the PL only responds once the FPGA bitstream is loaded, so the
# boot image (BOOT.BIN) must include it (bootgen [destination_device=pl]).

# Optional: GEM Ethernet datapath bring-up (fixed-link SGMII).
# Complements the PHY init above: use THAT for an external MDIO PHY, use THIS
# for a fixed link with no PHY (it configures the GEM MAC datapath itself). The
# two must target different GEMs.
# For ports on a fixed link (backplane, or SGMII with no PHY the OS driver
# auto-configures) that rely on the bootloader initializing the GEM. Replays
# U-Boot's zynq_gem datapath setup: NWCFG (SGMII/PCS/speed) + PCS control
# (fixed link). RX/TX are left for the OS to enable.
# List the GEMs as {base, speed_mbps} rows, directly:
#CFLAGS_EXTRA+=-DWOLFBOOT_ZYNQMP_GEM_INIT
#CFLAGS_EXTRA+=-DZYNQMP_GEM_INIT_LIST={0xFF0B0000UL,1000},{0xFF0C0000UL,1000}
# or from a board header:
#CFLAGS_EXTRA+=-DZYNQMP_GEM_INIT_HEADER='"myboard_gem.h"'
# where myboard_gem.h has, for example:
# #define ZYNQMP_GEM_INIT_LIST { 0xFF0B0000UL, 1000 }, { 0xFF0C0000UL, 1000 }
# (GEM0 0xFF0B0000 .. GEM3 0xFF0E0000; speed 1000/100/10; an unexpected speed is
# skipped, logged only when DEBUG_UART=1). Requires the GEM already clocked/out
# of reset by the FSBL psu_init.
19 changes: 19 additions & 0 deletions config/examples/zynqmp_sdcard.config
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,22 @@ WOLFBOOT_SECTOR_SIZE=0x1000
#CFLAGS_EXTRA+=-DZYNQMP_GEM_BASE=0xFF0B0000UL
# A PHY behind the PL only responds once the FPGA bitstream is loaded, so the
# boot image (BOOT.BIN) must include it (bootgen [destination_device=pl]).

# Optional: GEM Ethernet datapath bring-up (fixed-link SGMII).
# Complements the PHY init above: use THAT for an external MDIO PHY, use THIS
# for a fixed link with no PHY (it configures the GEM MAC datapath itself). The
# two must target different GEMs.
# For ports on a fixed link (backplane, or SGMII with no PHY the OS driver
# auto-configures) that rely on the bootloader initializing the GEM. Replays
# U-Boot's zynq_gem datapath setup: NWCFG (SGMII/PCS/speed) + PCS control
# (fixed link). RX/TX are left for the OS to enable.
# List the GEMs as {base, speed_mbps} rows, directly:
#CFLAGS_EXTRA+=-DWOLFBOOT_ZYNQMP_GEM_INIT
#CFLAGS_EXTRA+=-DZYNQMP_GEM_INIT_LIST={0xFF0B0000UL,1000},{0xFF0C0000UL,1000}
# or from a board header:
#CFLAGS_EXTRA+=-DZYNQMP_GEM_INIT_HEADER='"myboard_gem.h"'
# where myboard_gem.h has, for example:
# #define ZYNQMP_GEM_INIT_LIST { 0xFF0B0000UL, 1000 }, { 0xFF0C0000UL, 1000 }
# (GEM0 0xFF0B0000 .. GEM3 0xFF0E0000; speed 1000/100/10; an unexpected speed is
# skipped, logged only when DEBUG_UART=1). Requires the GEM already clocked/out
# of reset by the FSBL psu_init.
17 changes: 15 additions & 2 deletions docs/Targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -3795,9 +3795,22 @@ Key configuration options:
- `HASH=SHA3` - SHA3-384 hashing
- `ELF=1` - ELF loading support

### Ethernet PHY init (optional)
### ZynqMP Ethernet bring-up (optional)

Opt-in (off by default), wolfBoot can replay a board's U-Boot Ethernet PHY register sequence over the GEM MDIO management plane so the PHY is ready before the OS runs. Enable with `CFLAGS_EXTRA+=-DWOLFBOOT_ZYNQMP_PHY_INIT`. The default targets the ZCU102 on-board PHY (TI DP83867 at MDIO `0x0C` on GEM3, `0xFF0E0000`) and just reads the PHY ID as a diagnostic (printed with `DEBUG_UART=1`). A board supplies its own sequence by keeping its values in a small header selected with one line, `CFLAGS_EXTRA+=-DZYNQMP_PHY_INIT_HEADER='"myboard_phy.h"'`, where that header `#define`s any of `ZYNQMP_GEM_BASE`, `ZYNQMP_PHY_ADDR`, `ZYNQMP_PHY_GPIO_ADDR`, `ZYNQMP_GEM_MDC_DIV`, and the `{op, arg0, arg1}` step array `ZYNQMP_PHY_INIT_STEPS`; scalars can also be set directly with `-D`, and anything omitted falls back to the ZCU102 defaults (see `hal/zynq.h` and the commented example in `config/examples/zynqmp.config`). Where the PHY is behind the PL, the boot image must include the FPGA bitstream (bootgen `[destination_device=pl] system.bit`) or the transactions are no-ops.
wolfBoot has no network stack, but on ZynqMP it can leave the Ethernet hardware in the state the OS expects when it replaces U-Boot. There are two independent, opt-in helpers; choose by what the port actually needs:

- A port with a real external MDIO PHY that needs register setup before the OS (auto-negotiation, errata, LEDs) uses the **PHY init** helper (`WOLFBOOT_ZYNQMP_PHY_INIT`) - it drives the MDIO management plane to read/write the PHY chip.
- A port on a fixed link with no PHY to configure (a backplane, or SGMII where the OS driver does not bring the MAC up) uses the **GEM datapath bring-up** helper (`WOLFBOOT_ZYNQMP_GEM_INIT`) - it configures the GEM MAC's own SGMII/PCS (the OS then enables RX/TX). Tell-tale: the port has no MDIO PHY (a scan reads back `0xFFFF`) yet works under U-Boot, because U-Boot's driver initialized the MAC datapath, not a PHY.

The two are independent and can both be enabled on the same board, but for different ports - a given GEM is either a PHY port or a fixed-link port, not both.

#### Ethernet PHY init

Opt-in (off by default), wolfBoot can replay a board's U-Boot Ethernet PHY register sequence over the GEM MDIO management plane so the PHY is ready before the OS runs. Enable with `CFLAGS_EXTRA+=-DWOLFBOOT_ZYNQMP_PHY_INIT`. The default targets the ZCU102 on-board PHY (TI DP83867 at MDIO `0x0C` on GEM3, `0xFF0E0000`) and just reads the PHY ID as a diagnostic (printed with `DEBUG_UART=1`). A board supplies its own sequence by keeping its values in a small header selected with one line, `CFLAGS_EXTRA+=-DZYNQMP_PHY_INIT_HEADER='"myboard_phy.h"'`, where that header `#define`s any of `ZYNQMP_GEM_BASE`, `ZYNQMP_PHY_ADDR`, `ZYNQMP_PHY_GPIO_ADDR`, `ZYNQMP_GEM_MDC_DIV`, and the `{op, arg0, arg1}` step array `ZYNQMP_PHY_INIT_STEPS`; scalars can also be set directly with `-D`, and anything omitted falls back to the ZCU102 defaults (see `hal/zynq.h` and the commented example in `config/examples/zynqmp.config`). Where the PHY is behind the PL, the boot image must include the FPGA bitstream (bootgen `[destination_device=pl] system.bit`) or the transactions are no-ops. For a fixed-link port with no PHY to configure, use the GEM datapath bring-up below instead of this.

#### GEM Ethernet datapath bring-up

Some ZynqMP ports are on a fixed link (a backplane, or an SGMII connection with no PHY that the OS driver auto-configures) and rely on the bootloader having brought the GEM datapath up. U-Boot's `zynq_gem` driver does this the first time it uses an interface (for example a `tftpboot`); when wolfBoot replaces U-Boot that step is lost and those ports stay down even though the OS enumerates them. Enable `CFLAGS_EXTRA+=-DWOLFBOOT_ZYNQMP_GEM_INIT` and list the affected GEMs as `{gem_base, speed_mbps}` rows in `ZYNQMP_GEM_INIT_LIST`, either directly (`CFLAGS_EXTRA+=-DZYNQMP_GEM_INIT_LIST={0xFF0B0000UL,1000},{0xFF0C0000UL,1000}`, no spaces) or from a header (`CFLAGS_EXTRA+=-DZYNQMP_GEM_INIT_HEADER='"myboard_gem.h"'` with `#define ZYNQMP_GEM_INIT_LIST { 0xFF0B0000UL, 1000 }, { 0xFF0C0000UL, 1000 }`) - GEM0 `0xFF0B0000` .. GEM3 `0xFF0E0000`, speed 1000/100/10. For each GEM wolfBoot writes `NWCFG` (SGMII + PCS select + speed) and the PCS control register (fixed link, auto-negotiation disabled) - the same registers U-Boot's driver sets. RX/TX are deliberately left off: the OS driver enables them after it programs its DMA descriptor rings (wolfBoot has none), so enabling RX here could DMA a received frame to an arbitrary address during image verify. The GEM must already be clocked and out of reset by the FSBL `psu_init`. This is distinct from the PHY init above (which configures an external MDIO PHY); the two helpers must target different GEMs, and if both name the same base this full `NWCFG` write wins - override `GEMI_CFG_MDCDIV` to reconcile the MDC divisor.

### Building with Xilinx tools (Vitis IDE)

Expand Down
56 changes: 56 additions & 0 deletions hal/zynq.c
Original file line number Diff line number Diff line change
Expand Up @@ -2176,6 +2176,58 @@ static void zynq_phy_init(void)
}
#endif /* WOLFBOOT_ZYNQMP_PHY_INIT */

#ifdef WOLFBOOT_ZYNQMP_GEM_INIT
/* Bring up the listed GEM datapaths for a fixed-link SGMII connection, the way
* U-Boot's zynq_gem driver does: program NWCFG (SGMII + PCS + speed) and the
* PCS control register (fixed link, auto-neg off). RX/TX are left disabled -
* the OS driver enables them after programming its DMA descriptor rings; with
* no rings, enabling RX here could DMA a received frame to an arbitrary address
* during image verify. The GEM must already be clocked and out of reset (FSBL
* psu_init). See hal/zynq.h. */
static void zynqmp_gem_init(void)
{
static const struct {
uintptr_t base;
uint16_t speed;
} gems[] = { ZYNQMP_GEM_INIT_LIST };
uint32_t i, nwcfg, pcs, rb;

for (i = 0; i < (sizeof(gems) / sizeof(gems[0])); i++) {
nwcfg = GEMI_CFG_SGMII_BASE;
if (gems[i].speed == 1000) {
nwcfg |= GEMI_CFG_GIGE;
pcs = GEMI_PCS_1000;
}
else if (gems[i].speed == 100) {
nwcfg |= GEMI_CFG_SPEED100;
pcs = GEMI_PCS_100;
}
else if (gems[i].speed == 10) {
pcs = GEMI_PCS_10;
}
else {
wolfBoot_printf("GEM init @0x%08x: bad speed %d, skipped\n",
(unsigned int)gems[i].base, (int)gems[i].speed);
continue;
}
/* NWCFG (with PCS_SEL) must be written before the PCS control write. */
*((volatile uint32_t*)(gems[i].base + GEMI_NWCFG)) = nwcfg;
*((volatile uint32_t*)(gems[i].base + GEMI_PCS)) = pcs;
/* Read NWCFG back: a clock-gated / in-reset GEM will not latch it. */
rb = *((volatile uint32_t*)(gems[i].base + GEMI_NWCFG));
if (rb != nwcfg) {
wolfBoot_printf("GEM init @0x%08x NWCFG 0x%08x != 0x%08x "
"(gated/in reset?)\n", (unsigned int)gems[i].base,
(unsigned int)rb, (unsigned int)nwcfg);
}
else {
wolfBoot_printf("GEM init @0x%08x %dMbps\n",
(unsigned int)gems[i].base, (int)gems[i].speed);
}
}
}
#endif /* WOLFBOOT_ZYNQMP_GEM_INIT */

/* public HAL functions */
void hal_init(void)
{
Expand Down Expand Up @@ -2214,6 +2266,10 @@ void hal_init(void)
zynq_phy_init();
#endif

#ifdef WOLFBOOT_ZYNQMP_GEM_INIT
zynqmp_gem_init();
#endif

#if defined(EXT_FLASH) && (EXT_FLASH == 1)
qspi_init();
#endif
Expand Down
63 changes: 63 additions & 0 deletions hal/zynq.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,69 @@
#endif /* WOLFBOOT_ZYNQMP_PHY_INIT */


#ifdef WOLFBOOT_ZYNQMP_GEM_INIT
/* GEM (Ethernet MAC) datapath bring-up for fixed-link SGMII ports.
*
* Some ZynqMP boards have GEM ports on a fixed link (a backplane, or an SGMII
* connection with no PHY that the OS driver auto-configures) that rely on the
* bootloader having brought the GEM datapath up. U-Boot's zynq_gem driver does
* this the first time it uses an interface; wolfBoot has no network stack, so
* this option replays the equivalent register writes: NWCFG (SGMII + PCS +
* speed) and the PCS control register (fixed link, auto-negotiation disabled).
* The values mirror the Cadence GEM driver's zynq_gem_init(). RX/TX are left
* disabled: the OS driver enables them after it programs its DMA descriptor
* rings (wolfBoot has none), so enabling RX here would be unsafe. The GEM must
* already be clocked and out of reset by the FSBL psu_init.
*
* This is separate from WOLFBOOT_ZYNQMP_PHY_INIT: a GEM is either a PHY port
* (that helper) or a fixed-link port (this one) - the two must not name the
* same GEM base. If they do, this full NWCFG write wins and overrides the PHY
* init MDC divisor; override GEMI_CFG_MDCDIV to reconcile.
*
* The board supplies ZYNQMP_GEM_INIT_LIST as {gem_base, speed_mbps} rows,
* directly or from a header selected with one line:
* CFLAGS_EXTRA+=-DZYNQMP_GEM_INIT_HEADER='"myboard_gem.h"'
* one row per GEM base (GEM0 0xFF0B0000 .. GEM3 0xFF0E0000) at 1000/100/10, e.g.
* #define ZYNQMP_GEM_INIT_LIST \
* { 0xFF0B0000UL, 1000 }, { 0xFF0C0000UL, 1000 }
*/
#ifdef ZYNQMP_GEM_INIT_HEADER
#include ZYNQMP_GEM_INIT_HEADER
#endif
#ifndef ZYNQMP_GEM_INIT_LIST
#error "WOLFBOOT_ZYNQMP_GEM_INIT set but ZYNQMP_GEM_INIT_LIST not defined (see hal/zynq.h)"
#endif

/* GEM register offsets from a GEM base. */
#define GEMI_NWCFG 0x004
#define GEMI_PCS 0x200

/* NWCFG bits. */
#define GEMI_CFG_SPEED100 (1UL << 0)
#define GEMI_CFG_FDEN (1UL << 1)
#define GEMI_CFG_GIGE (1UL << 10)
#define GEMI_CFG_PCSSEL (1UL << 11)
#define GEMI_CFG_FCSREM (1UL << 17)
#define GEMI_CFG_DBUS64 (1UL << 21)
#define GEMI_CFG_SGMIIEN (1UL << 27)
/* MDC divisor (NWCFG[20:18]); default pclk/64 as U-Boot uses. Overridable for
* a board whose pclk needs a different divisor to stay under the 2.5MHz MDC
* max (only relevant if MDIO is later used on the same GEM). */
#ifndef GEMI_CFG_MDCDIV
#define GEMI_CFG_MDCDIV (0x4UL << 18) /* MDC = pclk/64 */
#endif
/* Common config for all speeds (U-Boot NWCFG_INIT plus SGMII/PCS select). */
#define GEMI_CFG_SGMII_BASE \
(GEMI_CFG_DBUS64 | GEMI_CFG_FDEN | GEMI_CFG_FCSREM | GEMI_CFG_MDCDIV | \
GEMI_CFG_SGMIIEN | GEMI_CFG_PCSSEL)

/* PCS control (clause-22 BMCR layout), fixed full-duplex link, auto-neg off. */
#define GEMI_PCS_1000 0x0140UL /* 1Gbps, full duplex */
#define GEMI_PCS_100 0x2100UL /* 100Mbps, full duplex */
#define GEMI_PCS_10 0x0100UL /* 10Mbps, full duplex */
#endif /* WOLFBOOT_ZYNQMP_GEM_INIT */


/* Configuration Security Unit (CSU) */
/* Triple-Dedundant MicroBlaze processor */
/* 128 KB CSU ROM (immutable) */
Expand Down
Loading