diff options
| author | Tom Rini <[email protected]> | 2026-06-10 09:18:15 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-06-10 09:18:15 -0600 |
| commit | 953653936cfc9e12f52df1165080fa6c7cbae1bc (patch) | |
| tree | 407487ab8999b482dfe367b0561347c0f22f261a /board | |
| parent | 45cfba58dba911685700d6574b01f39329dce99c (diff) | |
| parent | eab66c3a9085e07b227847b0c442ee8d2efb241d (diff) | |
Merge tag 'u-boot-marvell-next-20260610' of https://source.denx.de/u-boot/custodians/u-boot-marvell into next
CI: https://source.denx.de/u-boot/custodians/u-boot-marvell/-/pipelines/30414
u-boot-marvell changes 2026-06-10:
- arm: kirkwood: Remove unnecessary watchdog GPIO for ZyXEL NSA325 board (Tony)
- net: mvpp2: fix NULL pointer dereference in mvpp2_phy_connect (Vincent)
- mtd: nand: pxa3xx: Pass valid dev to dev_err() (Chris)
- arm: mvebu: db-xc3-24g4xg: Remove marvell, nand-keep-config (Chris)
- arm: mvebu: Add Allied Telesis x220 (Chris)
- board: Synology: legacy.c: Include asm/io.h (Phil)
- board: Synology: common: Fix typo in Makefile (Phil)
- serial: serial_octeon_bootcmd.c: use correct Kconfig symbol (Heinrich)
- arm: mvebu: Drop unnecessary BOARD_EARLY_INIT_F usage (Tom)
- pinctrl: armada-38x: Staticize and constify driver ops (Marek)
- arm: mach-mvebu: armada8k: cpuinfo and SAR (Vincent)
- board: freebox: add Nodebox 10G board support (Vincent)
- board: freebox: nbx10g: add emmcboot for dual-bank eMMC boot (Vincent)
- board: freebox: nbx10g: add device serial and MAC address initialization (Vincent)
- arm: dts: armada-8040-nbx: add U-Boot dtsi for conditional OP-TEE (Vincent)
- timer: orion: Use dev_remap_addr_index() (Peng)
Diffstat (limited to 'board')
| -rw-r--r-- | board/Marvell/mvebu_armada-37xx/board.c | 5 | ||||
| -rw-r--r-- | board/Synology/common/Makefile | 2 | ||||
| -rw-r--r-- | board/Synology/common/legacy.c | 1 | ||||
| -rw-r--r-- | board/alliedtelesis/x220/.gitattributes | 1 | ||||
| -rw-r--r-- | board/alliedtelesis/x220/.gitignore | 1 | ||||
| -rw-r--r-- | board/alliedtelesis/x220/MAINTAINERS | 8 | ||||
| -rw-r--r-- | board/alliedtelesis/x220/Makefile | 14 | ||||
| -rw-r--r-- | board/alliedtelesis/x220/binary.0 | 11 | ||||
| -rw-r--r-- | board/alliedtelesis/x220/kwbimage.cfg.in | 12 | ||||
| -rw-r--r-- | board/alliedtelesis/x220/x220.c | 67 | ||||
| -rw-r--r-- | board/freebox/nbx10g/Kconfig | 94 | ||||
| -rw-r--r-- | board/freebox/nbx10g/MAINTAINERS | 6 | ||||
| -rw-r--r-- | board/freebox/nbx10g/Makefile | 5 | ||||
| -rw-r--r-- | board/freebox/nbx10g/board.c | 53 | ||||
| -rw-r--r-- | board/freebox/nbx10g/nbx_emmcboot.c | 357 | ||||
| -rw-r--r-- | board/freebox/nbx10g/nbx_fbxserial.c | 286 | ||||
| -rw-r--r-- | board/freebox/nbx10g/nbx_fbxserial.h | 156 | ||||
| -rw-r--r-- | board/freebox/nbx10g/nbx_imagetag.h | 78 | ||||
| -rw-r--r-- | board/freebox/nbx10g/nbx_nrboot.h | 34 | ||||
| -rw-r--r-- | board/zyxel/nsa325/nsa325.c | 7 |
20 files changed, 1188 insertions, 10 deletions
diff --git a/board/Marvell/mvebu_armada-37xx/board.c b/board/Marvell/mvebu_armada-37xx/board.c index e44b713f96d..c30fca6cffd 100644 --- a/board/Marvell/mvebu_armada-37xx/board.c +++ b/board/Marvell/mvebu_armada-37xx/board.c @@ -102,11 +102,6 @@ static bool is_edpu_plus(void) return false; } -int board_early_init_f(void) -{ - return 0; -} - int board_init(void) { /* adress of boot parameters */ diff --git a/board/Synology/common/Makefile b/board/Synology/common/Makefile index f688b549063..87be53321ee 100644 --- a/board/Synology/common/Makefile +++ b/board/Synology/common/Makefile @@ -2,4 +2,4 @@ # # Copyright (C) 2021 Phil Sutter <[email protected]> -obj-$(SUPPORT_PASSING_ATAGS) += legacy.o +obj-$(CONFIG_SUPPORT_PASSING_ATAGS) += legacy.o diff --git a/board/Synology/common/legacy.c b/board/Synology/common/legacy.c index 2e3aa660eaa..5b7d07bc2ee 100644 --- a/board/Synology/common/legacy.c +++ b/board/Synology/common/legacy.c @@ -10,6 +10,7 @@ #include <vsprintf.h> #include <env.h> #include <net.h> +#include <asm/io.h> #include <asm/setup.h> #include "legacy.h" diff --git a/board/alliedtelesis/x220/.gitattributes b/board/alliedtelesis/x220/.gitattributes new file mode 100644 index 00000000000..2aeb4eee641 --- /dev/null +++ b/board/alliedtelesis/x220/.gitattributes @@ -0,0 +1 @@ +binary.0 binary diff --git a/board/alliedtelesis/x220/.gitignore b/board/alliedtelesis/x220/.gitignore new file mode 100644 index 00000000000..775b9346b85 --- /dev/null +++ b/board/alliedtelesis/x220/.gitignore @@ -0,0 +1 @@ +kwbimage.cfg diff --git a/board/alliedtelesis/x220/MAINTAINERS b/board/alliedtelesis/x220/MAINTAINERS new file mode 100644 index 00000000000..63da2725f71 --- /dev/null +++ b/board/alliedtelesis/x220/MAINTAINERS @@ -0,0 +1,8 @@ +x220 BOARD +M: Chris Packham <[email protected]> +S: Maintained +F: board/alliedtelesis/x220 +F: include/configs/x220.h +F: configs/x220_defconfig +F: arch/arm/dts/armada-xp-atl-x220.dts +F: doc/board/alliedtelesis/x220.rst diff --git a/board/alliedtelesis/x220/Makefile b/board/alliedtelesis/x220/Makefile new file mode 100644 index 00000000000..a74f0a76948 --- /dev/null +++ b/board/alliedtelesis/x220/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2025 Allied Telesis Labs + +obj-y := x220.o +extra-y := kwbimage.cfg + +quiet_cmd_sed = SED $@ + cmd_sed = sed $(SEDFLAGS_$(@F)) $< >$(dir $@)$(@F) + +SEDFLAGS_kwbimage.cfg =-e "s|^BINARY.*|BINARY $(srctree)/$(@D)/binary.0 0000005b 00000068|" +$(obj)/kwbimage.cfg: $(src)/kwbimage.cfg.in include/autoconf.mk \ + include/config/auto.conf + $(call if_changed,sed) diff --git a/board/alliedtelesis/x220/binary.0 b/board/alliedtelesis/x220/binary.0 new file mode 100644 index 00000000000..8dd687286a0 --- /dev/null +++ b/board/alliedtelesis/x220/binary.0 @@ -0,0 +1,11 @@ +-------- +WARNING: +-------- +This file should contain the bin_hdr generated by the original Marvell +U-Boot implementation. As this is currently not included in this +U-Boot version, we have added this placeholder, so that the U-Boot +image can be generated without errors. + +If you have a known to be working bin_hdr for your board, then you +just need to replace this text file here with the binary header +and recompile U-Boot. diff --git a/board/alliedtelesis/x220/kwbimage.cfg.in b/board/alliedtelesis/x220/kwbimage.cfg.in new file mode 100644 index 00000000000..8beda907ba4 --- /dev/null +++ b/board/alliedtelesis/x220/kwbimage.cfg.in @@ -0,0 +1,12 @@ +# +# Copyright (C) 2025 Allied Telesis Labs +# + +# Armada XP uses version 1 image format +VERSION 1 + +# Boot Media configurations +BOOT_FROM spi + +# Binary Header (bin_hdr) with DDR3 training code +BINARY board/alliedtelesis/x220/binary.0 0000005b 00000068 diff --git a/board/alliedtelesis/x220/x220.c b/board/alliedtelesis/x220/x220.c new file mode 100644 index 00000000000..7c9a73de9a2 --- /dev/null +++ b/board/alliedtelesis/x220/x220.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025 Allied Telesis Labs + */ + +#include <i2c.h> +#include <init.h> +#include <asm/global_data.h> +#include <asm/gpio.h> +#include <linux/bitops.h> +#include <linux/mbus.h> +#include <linux/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/soc.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define X220_GPP_OUT_ENA_LOW (~(BIT(12) | BIT(17) | BIT(18) | BIT(31))) +#define X220_GPP_OUT_ENA_MID (~(0)) +#define X220_GPP_OUT_VAL_LOW (BIT(12) | BIT(18)) +#define X220_GPP_OUT_VAL_MID 0x0 +#define X220_GPP_POL_LOW 0x0 +#define X220_GPP_POL_MID 0x0 + +int board_early_init_f(void) +{ + /* Configure MPP */ + writel(0x44042222, MVEBU_MPP_BASE + 0x00); + writel(0x11000004, MVEBU_MPP_BASE + 0x04); + writel(0x44444004, MVEBU_MPP_BASE + 0x08); + writel(0x04444444, MVEBU_MPP_BASE + 0x0c); + writel(0x00000004, MVEBU_MPP_BASE + 0x10); + + /* Set GPP Out value */ + writel(X220_GPP_OUT_VAL_LOW, MVEBU_GPIO0_BASE + 0x00); + writel(X220_GPP_OUT_VAL_MID, MVEBU_GPIO1_BASE + 0x00); + + /* Set GPP Polarity */ + writel(X220_GPP_POL_LOW, MVEBU_GPIO0_BASE + 0x0c); + writel(X220_GPP_POL_MID, MVEBU_GPIO1_BASE + 0x0c); + + /* Set GPP Out Enable */ + writel(X220_GPP_OUT_ENA_LOW, MVEBU_GPIO0_BASE + 0x04); + writel(X220_GPP_OUT_ENA_MID, MVEBU_GPIO1_BASE + 0x04); + + return 0; +} + +int board_init(void) +{ + /* address of boot parameters */ + gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100; + + /* Disable MBUS Err Prop - in order to avoid data aborts */ + clrbits_le32(MVEBU_CPU_WIN_BASE + 0x200, (1 << 8)); + + return 0; +} + +#ifdef CONFIG_DISPLAY_BOARDINFO +int checkboard(void) +{ + puts("Board: Allied Telesis x220\n"); + + return 0; +} +#endif diff --git a/board/freebox/nbx10g/Kconfig b/board/freebox/nbx10g/Kconfig new file mode 100644 index 00000000000..958c8fdd4c3 --- /dev/null +++ b/board/freebox/nbx10g/Kconfig @@ -0,0 +1,94 @@ +if TARGET_NBX10G + +config SYS_BOARD + default "nbx10g" + +config SYS_VENDOR + default "freebox" + +config SYS_CONFIG_NAME + default "nbx10g" + +config CMD_NBX_EMMCBOOT + bool "emmcboot command" + depends on MMC_SDHCI_XENON + help + Enable the emmcboot command for dual-bank boot from eMMC. + This is a legacy boot format used on this board for many years. + It implements a boot system with two image banks and automatic + fallback on boot failures. The boot order depends on a reboot + tracking counter (nrboot): + - If healthy: try Bank1 (newer) first, then Bank0 (stable) + - If degraded (>= 4 failures): try Bank0 first, then Bank1 + + Requires image_addr and fdt_addr environment variables to be set. + +if CMD_NBX_EMMCBOOT + +config NBX_MMC_PART_NRBOOT_OFFSET + hex "NRBoot counter offset in eMMC" + default 0x802000 + help + Byte offset in eMMC where the reboot tracking counter is stored. + Default: 0x802000 (8MB + 8KB) + +config NBX_MMC_PART_BANK0_OFFSET + hex "Bank0 image offset in eMMC" + default 0x804000 + help + Byte offset in eMMC where the stable (Bank0) boot image starts. + Default: 0x804000 (8MB + 16KB) + +config NBX_MMC_PART_BANK0_SIZE + hex "Bank0 image maximum size" + default 0x10000000 + help + Maximum size of the Bank0 boot image. + Default: 0x10000000 (256MB) + +config NBX_MMC_PART_BANK1_OFFSET + hex "Bank1 image offset in eMMC" + default 0x10804000 + help + Byte offset in eMMC where the newer (Bank1) boot image starts. + Default: 0x10804000 (264MB + 16KB) + +config NBX_MMC_PART_BANK1_SIZE + hex "Bank1 image maximum size" + default 0x10000000 + help + Maximum size of the Bank1 boot image. + Default: 0x10000000 (256MB) + +endif + +config CMD_NBX_FBXSERIAL + bool "fbxserial command" + depends on MMC_SDHCI_XENON + help + Enable the fbxserial command to read and display device + serial information from eMMC. This includes: + - Device serial number (type, version, manufacturer, date, number) + - MAC address (used to set ethaddr environment variables) + - Bundle information (if present) + + The serial info is stored at a fixed offset in the eMMC user area. + + Subcommands: + - fbxserial show: display serial info (default) + - fbxserial init: initialize ethaddr from serial info + + Use CONFIG_PREBOOT="fbxserial init" to auto-initialize at boot. + +if CMD_NBX_FBXSERIAL + +config NBX_MMC_PART_SERIAL_OFFSET + hex "Serial info offset in eMMC" + default 0x800000 + help + Byte offset in eMMC where the serial info structure is stored. + Default: 0x800000 (8MB) + +endif + +endif diff --git a/board/freebox/nbx10g/MAINTAINERS b/board/freebox/nbx10g/MAINTAINERS new file mode 100644 index 00000000000..2e31eed45b9 --- /dev/null +++ b/board/freebox/nbx10g/MAINTAINERS @@ -0,0 +1,6 @@ +NBX10G BOARD +M: Vincent Jardin <[email protected]> +S: Maintained +F: board/freebox/nbx10g/ +F: configs/mvebu_nbx_88f8040_defconfig +F: arch/arm/dts/armada-8040-nbx* diff --git a/board/freebox/nbx10g/Makefile b/board/freebox/nbx10g/Makefile new file mode 100644 index 00000000000..4b70d94e14d --- /dev/null +++ b/board/freebox/nbx10g/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y := board.o +obj-$(CONFIG_CMD_NBX_EMMCBOOT) += nbx_emmcboot.o +obj-$(CONFIG_CMD_NBX_FBXSERIAL) += nbx_fbxserial.o diff --git a/board/freebox/nbx10g/board.c b/board/freebox/nbx10g/board.c new file mode 100644 index 00000000000..7d16010ec7e --- /dev/null +++ b/board/freebox/nbx10g/board.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017-2018 Freebox SA + * Copyright (C) 2026 Free Mobile, Vincent Jardin <[email protected]> + * + * Freebox Nodebox 10G board support + */ + +#include <init.h> +#include <asm/gpio.h> +#include <linux/delay.h> + +/* Management PHY reset GPIO */ +#define NBX_PHY_RESET_GPIO 83 + +/* Nodebox 10G ASCII art logo */ +static const char * const nbx_logo = + " _ _ _ _ __ ___ _____\n" + " | \\ | | | | | | /_ |/ _ \\ / ____|\n" + " | \\| | ___ __| | ___| |__ _____ __ | | | | | | __\n" + " | . ` |/ _ \\ / _` |/ _ \\ '_ \\ / _ \\ \\/ / | | | | | | |_ |\n" + " | |\\ | (_) | (_| | __/ |_) | (_) > < | | |_| | |__| |\n" + " |_| \\_|\\___/ \\__,_|\\___|_.__/ \\___/_/\\_\\ |_|\\___/ \\_____|\n"; + +int checkboard(void) +{ + printf("%s\n", nbx_logo); + return 0; +} + +int board_init(void) +{ + return 0; +} + +int board_late_init(void) +{ + int ret; + + /* Reset the management PHY */ + ret = gpio_request(NBX_PHY_RESET_GPIO, "phy-reset"); + if (ret) { + printf("Failed to request PHY reset GPIO: %d\n", ret); + return 0; + } + + gpio_direction_output(NBX_PHY_RESET_GPIO, 0); + mdelay(100); + gpio_set_value(NBX_PHY_RESET_GPIO, 1); + mdelay(100); + + return 0; +} diff --git a/board/freebox/nbx10g/nbx_emmcboot.c b/board/freebox/nbx10g/nbx_emmcboot.c new file mode 100644 index 00000000000..0bea96fadd9 --- /dev/null +++ b/board/freebox/nbx10g/nbx_emmcboot.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Nodebox 10G dual-bank eMMC boot command with automatic fallback + * + * Copyright (C) 2026 Free Mobile, Freebox + * + * This implements a dual-bank boot system with automatic fallback: + * - Bank0: Stable/fallback boot image + * - Bank1: Newer/test boot image + * + * The boot order depends on the reboot tracking counter (nrboot): + * - If healthy: try Bank1 first, then Bank0 + * - If degraded (>= 4 failures): try Bank0 first, then Bank1 + */ + +#include <command.h> +#include <env.h> +#include <mmc.h> +#include <malloc.h> +#include <memalign.h> +#include <vsprintf.h> +#include <u-boot/crc.h> +#include <u-boot/schedule.h> +#include <asm/byteorder.h> +#include <linux/errno.h> +#include "nbx_imagetag.h" +#include "nbx_nrboot.h" + +/* Partition offsets defined in Kconfig (CONFIG_NBX_MMC_PART_*) */ + +/* Image Tag Functions */ + +static int mvebu_imagetag_check(struct mvebu_image_tag *tag, + unsigned long maxsize, const char *name) +{ + if (be32_to_cpu(tag->magic) != MVEBU_IMAGE_TAG_MAGIC) { + if (name) + printf("%s: invalid TAG magic: %.8x\n", name, + be32_to_cpu(tag->magic)); + return -EINVAL; + } + + if (be32_to_cpu(tag->version) != MVEBU_IMAGE_TAG_VERSION) { + if (name) + printf("%s: invalid TAG version: %.8x\n", name, + be32_to_cpu(tag->version)); + return -EINVAL; + } + + if (be32_to_cpu(tag->total_size) < sizeof(*tag)) { + if (name) + printf("%s: tag size is too small!\n", name); + return -EINVAL; + } + + if (be32_to_cpu(tag->total_size) > maxsize) { + if (name) + printf("%s: tag size is too big!\n", name); + return -EINVAL; + } + + if (be32_to_cpu(tag->device_tree_offset) < sizeof(*tag) || + be32_to_cpu(tag->device_tree_offset) + + be32_to_cpu(tag->device_tree_size) > maxsize) { + if (name) + printf("%s: bogus device tree offset/size!\n", name); + return -EINVAL; + } + + if (be32_to_cpu(tag->kernel_offset) < sizeof(*tag) || + be32_to_cpu(tag->kernel_offset) + + be32_to_cpu(tag->kernel_size) > maxsize) { + if (name) + printf("%s: bogus kernel offset/size!\n", name); + return -EINVAL; + } + + if (be32_to_cpu(tag->rootfs_offset) < sizeof(*tag) || + be32_to_cpu(tag->rootfs_offset) + + be32_to_cpu(tag->rootfs_size) > maxsize) { + if (name) + printf("%s: bogus rootfs offset/size!\n", name); + return -EINVAL; + } + + if (name) { + /* + * Ensure null-termination within the 32-byte fields + * before printing to avoid displaying garbage. + */ + tag->image_name[sizeof(tag->image_name) - 1] = '\0'; + tag->build_date[sizeof(tag->build_date) - 1] = '\0'; + tag->build_user[sizeof(tag->build_user) - 1] = '\0'; + + printf("%s: Found valid tag: %s / %s / %s\n", name, + tag->image_name, tag->build_date, tag->build_user); + } + + return 0; +} + +static int mvebu_imagetag_crc(struct mvebu_image_tag *tag, const char *name) +{ + u32 crc = ~0; + + crc = crc32(crc, ((unsigned char *)tag) + 4, + be32_to_cpu(tag->total_size) - 4); + + if (be32_to_cpu(tag->crc) != crc) { + if (name) + printf("%s: invalid tag CRC!\n", name); + return -EINVAL; + } + + return 0; +} + +/* NRBoot (Reboot Tracking) Functions */ + +struct mvebu_nrboot { + u16 nrboot; + u16 nrsuccess; +}; + +#define MVEBU_MAX_FAILURE 4 + +static int mvebu_count_bits(u16 val) +{ + int i, found = 0; + + for (i = 0; i < 16; i++) { + if (val & (1 << i)) + found++; + } + return found; +} + +int mvebu_check_nrboot(struct mmc *mmc, unsigned long offset) +{ + struct blk_desc *bd = mmc_get_blk_desc(mmc); + struct mvebu_nrboot *nr; + uint blk_start = ALIGN(offset, bd->blksz) / bd->blksz; + uint blk_cnt = ALIGN(sizeof(*nr), bd->blksz) / bd->blksz; + uint n; + + ALLOC_CACHE_ALIGN_BUFFER(char, buf, blk_cnt * bd->blksz); + nr = (void *)buf; + + n = blk_dread(bd, blk_start, blk_cnt, buf); + if (n != blk_cnt) + return 0; + + printf(" - nr.nrboot = %04x\n", nr->nrboot); + printf(" - nr.nrsuccess = %04x\n", nr->nrsuccess); + + /* Sanity check on values */ + if (mvebu_count_bits(~nr->nrboot + 1) <= 1 && + mvebu_count_bits(~nr->nrsuccess + 1) <= 1) { + int boot, success; + + boot = 16 - mvebu_count_bits(nr->nrboot); + success = 16 - mvebu_count_bits(nr->nrsuccess); + + printf(" - Nrboot: %d / Nrsuccess: %d\n", boot, success); + + if (boot == 16 || boot < success || + boot - success >= MVEBU_MAX_FAILURE) { + printf(" - Nrboot exceeded\n"); + return 0; + } + + /* Increment boot attempt counter */ + boot++; + nr->nrboot = ~((1 << boot) - 1); + + printf(" - Setting Nrboot to %d\n", boot); + + n = blk_dwrite(bd, blk_start, blk_cnt, buf); + if (n != blk_cnt) + return 0; + + return 1; + } + + printf(" - Invalid NR values\n"); + + return 0; +} + +/* emmcboot Command */ + +static void mvebu_try_emmcboot(struct mmc *mmc, unsigned long offset, + unsigned long maxsize, const char *bank) +{ + struct blk_desc *bd = mmc_get_blk_desc(mmc); + struct mvebu_image_tag *tag; + ulong image_addr = 0; + ulong fdt_addr = 0; + ulong tag_addr; + uint tag_blk_start = ALIGN(offset, bd->blksz) / bd->blksz; + uint tag_blk_cnt = ALIGN(sizeof(*tag), bd->blksz) / bd->blksz; + uint n; + + ALLOC_CACHE_ALIGN_BUFFER(char, tag_buf, tag_blk_cnt * bd->blksz); + tag = (void *)tag_buf; + + schedule(); + + printf("## Trying %s boot...\n", bank); + + /* Load tag header */ + n = blk_dread(bd, tag_blk_start, tag_blk_cnt, tag_buf); + if (n != tag_blk_cnt) { + printf("%s: failed to read tag header\n", bank); + return; + } + + if (mvebu_imagetag_check(tag, maxsize, bank) != 0) + return; + + if (tag->rootfs_size != 0) { + printf("%s: rootfs in tag not supported\n", bank); + return; + } + + /* Get image and device tree load addresses from environment */ + image_addr = env_get_ulong("image_addr", 16, 0); + if (!image_addr) { + puts("emmcboot needs image_addr\n"); + return; + } + + fdt_addr = env_get_ulong("fdt_addr", 16, 0); + if (!fdt_addr) { + puts("emmcboot needs fdt_addr\n"); + return; + } + + tag_addr = image_addr; + + /* Load full image, temporarily reuse image_addr for this */ + { + uint data_blk_start = ALIGN(offset, bd->blksz) / bd->blksz; + uint data_blk_cnt = ALIGN(mvebu_imagetag_total_size(tag), + bd->blksz) / bd->blksz; + + n = blk_dread(bd, data_blk_start, data_blk_cnt, (void *)tag_addr); + if (n != data_blk_cnt) { + printf("%s: failed to read full image\n", bank); + return; + } + + if (mvebu_imagetag_crc((void *)tag_addr, bank) != 0) + return; + } + + schedule(); + + /* Copy image and device tree to the right addresses */ + /* We assume that image_addr + tag_size < fdt_addr */ + { + tag = (void *)tag_addr; + memcpy((void *)fdt_addr, + ((void *)tag_addr) + mvebu_imagetag_device_tree_offset(tag), + mvebu_imagetag_device_tree_size(tag)); + memmove((void *)image_addr, + ((void *)tag_addr) + mvebu_imagetag_kernel_offset(tag), + mvebu_imagetag_kernel_size(tag)); + } + + schedule(); + + /* Set bootargs and boot */ + { + char bootargs[256]; + char *console_env; + + console_env = env_get("console"); + if (console_env) + snprintf(bootargs, sizeof(bootargs), "%s bank=%s", + console_env, bank); + else + snprintf(bootargs, sizeof(bootargs), "bank=%s", bank); + + env_set("bootargs", bootargs); + + printf("## Booting kernel from %s...\n", bank); + printf(" Image addr: 0x%lx\n", image_addr); + printf(" FDT addr: 0x%lx\n", fdt_addr); + + /* Build and run booti command */ + { + char cmd[128]; + + snprintf(cmd, sizeof(cmd), "booti 0x%lx - 0x%lx", + image_addr, fdt_addr); + run_command(cmd, 0); + } + } + + printf("## %s boot failed\n", bank); +} + +static int do_emmcboot(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int dev; + struct mmc *mmc; + + dev = 0; + if (argc >= 2) + dev = dectoul(argv[1], NULL); + + mmc = find_mmc_device(dev); + if (!mmc) { + printf("No MMC device %d found\n", dev); + return CMD_RET_FAILURE; + } + + if (mmc_init(mmc)) { + puts("MMC init failed\n"); + return CMD_RET_FAILURE; + } + + /* Switch to partition 0 (user data area) */ + if (blk_select_hwpart_devnum(UCLASS_MMC, dev, 0)) { + puts("MMC partition switch failed\n"); + return CMD_RET_FAILURE; + } + + if (mvebu_check_nrboot(mmc, CONFIG_NBX_MMC_PART_NRBOOT_OFFSET)) { + /* System is healthy: try newer bank first */ + mvebu_try_emmcboot(mmc, CONFIG_NBX_MMC_PART_BANK1_OFFSET, + CONFIG_NBX_MMC_PART_BANK1_SIZE, "bank1"); + mvebu_try_emmcboot(mmc, CONFIG_NBX_MMC_PART_BANK0_OFFSET, + CONFIG_NBX_MMC_PART_BANK0_SIZE, "bank0"); + } else { + /* System is degraded: use stable bank first */ + mvebu_try_emmcboot(mmc, CONFIG_NBX_MMC_PART_BANK0_OFFSET, + CONFIG_NBX_MMC_PART_BANK0_SIZE, "bank0"); + mvebu_try_emmcboot(mmc, CONFIG_NBX_MMC_PART_BANK1_OFFSET, + CONFIG_NBX_MMC_PART_BANK1_SIZE, "bank1"); + } + + puts("emmcboot: all boot attempts failed\n"); + return CMD_RET_FAILURE; +} + +U_BOOT_CMD( + emmcboot, 2, 0, do_emmcboot, + "boot from MVEBU eMMC image banks", + "[dev]\n" + " - Boot from eMMC device <dev> (default 0)\n" + " - Requires image_addr and fdt_addr environment variables\n" + " - Uses dual-bank boot with automatic fallback\n" + " - Bank selection based on reboot tracking (nrboot)" +); diff --git a/board/freebox/nbx10g/nbx_fbxserial.c b/board/freebox/nbx10g/nbx_fbxserial.c new file mode 100644 index 00000000000..088133a9496 --- /dev/null +++ b/board/freebox/nbx10g/nbx_fbxserial.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NBX Freebox Serial Info Support + * + * Copyright (C) 2025 Free Mobile, Freebox + * + * Reads device serial number and MAC address from eMMC. + * The serial info is stored at a fixed offset in the eMMC user area. + * + * Serial format: TTTT-VV-M-(YY)WW-NN-NNNNN / FLAGS + * Where: + * TTTT = Device type (e.g., 9018) + * VV = Board version + * M = Manufacturer code (ASCII) + * YY = Year (BCD) + * WW = Week (1-53) + * NNNNN = Serial number + * FLAGS = Feature flags + */ + +#include <command.h> +#include <dm/device.h> +#include <env.h> +#include <event.h> +#include <mmc.h> +#include <malloc.h> +#include <memalign.h> +#include <vsprintf.h> +#include <u-boot/crc.h> +#include <asm/byteorder.h> +#include <linux/ctype.h> +#include <linux/errno.h> +#include "nbx_fbxserial.h" + +/* Partition offset defined in Kconfig (CONFIG_NBX_MMC_PART_SERIAL_OFFSET) */ + +/* + * Validate serial info structure + */ +static int nbx_fbx_check_serial(struct nbx_fbx_serial *fs) +{ + unsigned int sum, len; + + /* Check magic first */ + if (be32_to_cpu(fs->magic) != NBX_FBXSERIAL_MAGIC) { + printf("Invalid magic for serial info (%08x != %08x)!\n", + be32_to_cpu(fs->magic), NBX_FBXSERIAL_MAGIC); + return -EINVAL; + } + + /* Check struct version */ + if (be32_to_cpu(fs->struct_version) > NBX_FBXSERIAL_VERSION) { + printf("Version too big for fbxserial info (0x%08x)!\n", + be32_to_cpu(fs->struct_version)); + return -EINVAL; + } + + /* Check for silly len */ + len = be32_to_cpu(fs->len); + if (len > NBX_FBXSERIAL_MAX_SIZE) { + printf("Silly len for serial info (%d)\n", len); + return -EINVAL; + } + + /* Validate CRC (crc32_no_comp: no one's complement) */ + sum = crc32_no_comp(0, (void *)fs + 4, len - 4); + if (be32_to_cpu(fs->crc32) != sum) { + printf("Invalid checksum for serial info (%08x != %08x)\n", + sum, be32_to_cpu(fs->crc32)); + return -EINVAL; + } + + return 0; +} + +int nbx_fbx_read_serial(int dev_num, unsigned long offset, + struct nbx_fbx_serial *fs) +{ + struct mmc *mmc; + struct blk_desc *bd; + uint blk_start, blk_cnt; + uint n; + + ALLOC_CACHE_ALIGN_BUFFER(char, buf, ALIGN(sizeof(*fs), 512)); + mmc = find_mmc_device(dev_num); + if (!mmc) { + printf("No MMC device %d found\n", dev_num); + nbx_fbxserial_set_default(fs); + return -ENODEV; + } + + if (mmc_init(mmc)) { + puts("MMC init failed\n"); + nbx_fbxserial_set_default(fs); + return -EIO; + } + + /* Switch to partition 0 (user data area) */ + if (blk_select_hwpart_devnum(UCLASS_MMC, dev_num, 0)) { + puts("MMC partition switch failed\n"); + nbx_fbxserial_set_default(fs); + return -EIO; + } + + bd = mmc_get_blk_desc(mmc); + if (!bd) { + puts("Failed to get MMC block descriptor\n"); + nbx_fbxserial_set_default(fs); + return -EIO; + } + + blk_start = ALIGN(offset, bd->blksz) / bd->blksz; + blk_cnt = ALIGN(sizeof(*fs), bd->blksz) / bd->blksz; + + memset(fs, 0x42, sizeof(*fs)); + + n = blk_dread(bd, blk_start, blk_cnt, buf); + if (n != blk_cnt) { + printf("Failed to read serial info from MMC\n"); + nbx_fbxserial_set_default(fs); + return -EIO; + } + + memcpy(fs, buf, sizeof(*fs)); + + if (nbx_fbx_check_serial(fs) != 0) { + nbx_fbxserial_set_default(fs); + return -EINVAL; + } + + return 0; +} + +void nbx_fbx_dump_serial(struct nbx_fbx_serial *fs) +{ + int i; + + printf("Serial: %04u-%02u-%c-(%02u)%02u-%02u-%05u / %08x\n", + ntohs(fs->type), + fs->version, + isprint(fs->manufacturer) ? fs->manufacturer : '?', + ntohs(fs->year) / 100, + ntohs(fs->year) % 100, + fs->week, + ntohl(fs->number), + ntohl(fs->flags)); + + printf("Mac: %02X:%02X:%02X:%02X:%02X:%02X\n", + fs->mac_addr_base[0], + fs->mac_addr_base[1], + fs->mac_addr_base[2], + fs->mac_addr_base[3], + fs->mac_addr_base[4], + fs->mac_addr_base[5]); + + /* Show bundle info */ + for (i = 0; i < be32_to_cpu(fs->extinfo_count); i++) { + struct nbx_serial_extinfo *p; + + if (i >= NBX_EXTINFO_MAX_COUNT) + break; + + p = &fs->extinfos[i]; + if (be32_to_cpu(p->type) == NBX_EXTINFO_TYPE_EXTDEV && + be32_to_cpu(p->u.extdev.type) == NBX_EXTDEV_TYPE_BUNDLE) { + /* Ensure null termination */ + p->u.extdev.serial[sizeof(p->u.extdev.serial) - 1] = 0; + printf("Bundle: %s\n", p->u.extdev.serial); + } + } + + printf("\n"); +} + +int nbx_fbx_init_ethaddr(int dev_num, unsigned long offset) +{ + struct nbx_fbx_serial fs; + char mac[32]; + int ret; + + ret = nbx_fbx_read_serial(dev_num, offset, &fs); + + /* Even on error, fs has default values set */ + snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", + fs.mac_addr_base[0], fs.mac_addr_base[1], + fs.mac_addr_base[2], fs.mac_addr_base[3], + fs.mac_addr_base[4], fs.mac_addr_base[5]); + + nbx_fbx_dump_serial(&fs); + + env_set("ethaddr", mac); + env_set("eth1addr", mac); + env_set("eth2addr", mac); + + return ret; +} + +/* + * fbxserial show - display serial info from eMMC + */ +static int do_fbxserial_show(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct nbx_fbx_serial fs; + int dev = 0; + unsigned long offset = CONFIG_NBX_MMC_PART_SERIAL_OFFSET; + + if (argc >= 1) + dev = dectoul(argv[0], NULL); + + if (argc >= 2) + offset = hextoul(argv[1], NULL); + + if (nbx_fbx_read_serial(dev, offset, &fs) != 0) + printf("Warning: Using default serial info\n"); + + nbx_fbx_dump_serial(&fs); + + return CMD_RET_SUCCESS; +} + +/* + * fbxserial init - initialize ethaddr from serial info + */ +static int do_fbxserial_init(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int dev = 0; + unsigned long offset = CONFIG_NBX_MMC_PART_SERIAL_OFFSET; + + if (argc >= 1) + dev = dectoul(argv[0], NULL); + + if (argc >= 2) + offset = hextoul(argv[1], NULL); + + return nbx_fbx_init_ethaddr(dev, offset); +} + +static struct cmd_tbl cmd_fbxserial_sub[] = { + U_BOOT_CMD_MKENT(show, 3, 0, do_fbxserial_show, "", ""), + U_BOOT_CMD_MKENT(init, 3, 0, do_fbxserial_init, "", ""), +}; + +static int do_fbxserial(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct cmd_tbl *cp; + + /* Default to 'show' if no subcommand */ + if (argc < 2) + return do_fbxserial_show(cmdtp, flag, 0, NULL); + + cp = find_cmd_tbl(argv[1], cmd_fbxserial_sub, + ARRAY_SIZE(cmd_fbxserial_sub)); + + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc - 2, argv + 2); +} + +U_BOOT_CMD( + fbxserial, 5, 0, do_fbxserial, + "NBX serial info and MAC address initialization", + "show [dev] [offset] - display serial info from eMMC\n" + "fbxserial init [dev] [offset] - initialize ethaddr from serial info\n" + " dev - MMC device number (default 0)\n" + " offset - offset in eMMC in hex (default from Kconfig)" +); + +/* + * Early init hook: Set MAC address from eMMC serial info before + * network driver probes. EVT_SETTINGS_R is triggered after MMC + * is available but before initr_net(). + */ +static int nbx_fbx_settings_r(void) +{ + if (!of_machine_is_compatible("nbx,armada8040")) + return 0; + + nbx_fbx_init_ethaddr(0, CONFIG_NBX_MMC_PART_SERIAL_OFFSET); + return 0; +} + +EVENT_SPY_SIMPLE(EVT_SETTINGS_R, nbx_fbx_settings_r); diff --git a/board/freebox/nbx10g/nbx_fbxserial.h b/board/freebox/nbx10g/nbx_fbxserial.h new file mode 100644 index 00000000000..7bcaef09fe3 --- /dev/null +++ b/board/freebox/nbx10g/nbx_fbxserial.h @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * NBX Freebox Serial Info Support + * + * Copyright (C) 2025 Free Mobile, Freebox + * + * Reads device serial number and MAC address from eMMC. + * Used to identify the board and set network MAC addresses. + */ + +#ifndef NBX_FBXSERIAL_H +#define NBX_FBXSERIAL_H + +#include <linux/types.h> + +/* + * Extended info structure - variable data depending on type + */ +#define NBX_EXTINFO_SIZE 128 +#define NBX_EXTINFO_MAX_COUNT 16 + +/* Extended info types */ +#define NBX_EXTINFO_TYPE_EXTDEV 1 + +/* Extended device types */ +#define NBX_EXTDEV_TYPE_BUNDLE 1 +#define NBX_EXTDEV_TYPE_MAX 2 + +struct nbx_serial_extinfo { + u32 type; + + union { + /* extdev */ + struct { + u32 type; + u32 model; + char serial[64]; + } extdev; + + /* raw access */ + unsigned char data[NBX_EXTINFO_SIZE]; + } u; +} __packed; + +/* + * Master serial structure + */ +#define NBX_FBXSERIAL_VERSION 1 +#define NBX_FBXSERIAL_MAGIC 0x2d9521ab + +#define NBX_MAC_ADDR_SIZE 6 +#define NBX_RANDOM_DATA_SIZE 32 + +/* Maximum size for CRC validation */ +#define NBX_FBXSERIAL_MAX_SIZE 8192 + +struct nbx_fbx_serial { + u32 crc32; + u32 magic; + u32 struct_version; + u32 len; + + /* Board serial */ + u16 type; + u8 version; + u8 manufacturer; + u16 year; + u8 week; + u32 number; + u32 flags; + + /* MAC address base */ + u8 mac_addr_base[NBX_MAC_ADDR_SIZE]; + + /* MAC address count */ + u8 mac_count; + + /* Random data used to derive keys */ + u8 random_data[NBX_RANDOM_DATA_SIZE]; + + /* Last update of data (seconds since epoch) */ + u32 last_modified; + + /* Count of following extinfo tags */ + u32 extinfo_count; + + /* Beginning of extended info */ + struct nbx_serial_extinfo extinfos[NBX_EXTINFO_MAX_COUNT]; +} __packed; + +/** + * nbx_fbxserial_set_default() - Initialize serial structure with defaults + * @serial: Pointer to serial structure to initialize + * + * Sets the serial structure to default values (Freebox OUI, type 9018). + * Used as fallback when serial info cannot be read from eMMC. + */ +static inline void nbx_fbxserial_set_default(struct nbx_fbx_serial *serial) +{ + static const struct nbx_fbx_serial def = { + .crc32 = 0, + .magic = NBX_FBXSERIAL_MAGIC, + .struct_version = NBX_FBXSERIAL_VERSION, + .len = sizeof(struct nbx_fbx_serial), + .type = 9018, + .version = 0, + .manufacturer = '_', + .year = 0, + .week = 0, + .number = 0, + .flags = 0, + .mac_addr_base = { 0x00, 0x07, 0xCB, 0x00, 0x00, 0xFD }, + .mac_count = 1, + .random_data = { 0 }, + .last_modified = 0, + .extinfo_count = 0, + }; + + memcpy(serial, &def, sizeof(def)); +} + +/** + * nbx_fbx_read_serial() - Read serial info from eMMC + * @dev_num: MMC device number + * @offset: Byte offset in eMMC where serial info is stored + * @fs: Pointer to serial structure to fill + * + * Reads and validates the serial info from eMMC. On failure, + * the structure is filled with default values. + * + * Return: 0 on success, negative on error (defaults still set) + */ +int nbx_fbx_read_serial(int dev_num, unsigned long offset, + struct nbx_fbx_serial *fs); + +/** + * nbx_fbx_dump_serial() - Print serial info to console + * @fs: Pointer to serial structure to display + * + * Prints the serial number, MAC address, and bundle info (if present). + */ +void nbx_fbx_dump_serial(struct nbx_fbx_serial *fs); + +/** + * nbx_fbx_init_ethaddr() - Initialize Ethernet addresses from serial info + * @dev_num: MMC device number + * @offset: Byte offset in eMMC where serial info is stored + * + * Reads serial info and sets ethaddr, eth1addr, eth2addr environment + * variables from the MAC address in the serial structure. + * + * Return: 0 on success, negative on error + */ +int nbx_fbx_init_ethaddr(int dev_num, unsigned long offset); + +#endif /* NBX_FBXSERIAL_H */ diff --git a/board/freebox/nbx10g/nbx_imagetag.h b/board/freebox/nbx10g/nbx_imagetag.h new file mode 100644 index 00000000000..999293dd58a --- /dev/null +++ b/board/freebox/nbx10g/nbx_imagetag.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * MVEBU Image Tag header + * + * Copyright (C) 2026 Free Mobile, Freebox + */ + +#ifndef __MVEBU_IMAGETAG_H +#define __MVEBU_IMAGETAG_H + +#include <linux/types.h> + +#define MVEBU_IMAGE_TAG_MAGIC 0x8d7c90bc +#define MVEBU_IMAGE_TAG_VERSION 1 + +/** + * struct mvebu_image_tag - MVEBU boot image tag structure + * + * All multi-byte fields are stored in big-endian format. + */ +struct mvebu_image_tag { + u32 crc; /* CRC32-LE checksum (from offset 4) */ + u32 magic; /* Magic: 0x8d7c90bc */ + u32 version; /* Version: 1 */ + u32 total_size; /* Total image size including tag */ + u32 flags; /* Feature flags (reserved) */ + + u32 device_tree_offset; /* Offset from tag start to DTB */ + u32 device_tree_size; /* DTB size in bytes */ + + u32 kernel_offset; /* Offset from tag start to kernel */ + u32 kernel_size; /* Kernel size in bytes */ + + u32 rootfs_offset; /* Offset from tag start to rootfs */ + u32 rootfs_size; /* Rootfs size (must be 0) */ + + char image_name[32]; /* Image name (null-terminated) */ + char build_user[32]; /* Build user info */ + char build_date[32]; /* Build date info */ +}; + +/* Accessor functions for big-endian fields */ +static inline u32 mvebu_imagetag_device_tree_offset(struct mvebu_image_tag *tag) +{ + return be32_to_cpu(tag->device_tree_offset); +} + +static inline u32 mvebu_imagetag_device_tree_size(struct mvebu_image_tag *tag) +{ + return be32_to_cpu(tag->device_tree_size); +} + +static inline u32 mvebu_imagetag_kernel_offset(struct mvebu_image_tag *tag) +{ + return be32_to_cpu(tag->kernel_offset); +} + +static inline u32 mvebu_imagetag_kernel_size(struct mvebu_image_tag *tag) +{ + return be32_to_cpu(tag->kernel_size); +} + +static inline u32 mvebu_imagetag_rootfs_offset(struct mvebu_image_tag *tag) +{ + return be32_to_cpu(tag->rootfs_offset); +} + +static inline u32 mvebu_imagetag_rootfs_size(struct mvebu_image_tag *tag) +{ + return be32_to_cpu(tag->rootfs_size); +} + +static inline u32 mvebu_imagetag_total_size(struct mvebu_image_tag *tag) +{ + return be32_to_cpu(tag->total_size); +} + +#endif /* __MVEBU_IMAGETAG_H */ diff --git a/board/freebox/nbx10g/nbx_nrboot.h b/board/freebox/nbx10g/nbx_nrboot.h new file mode 100644 index 00000000000..91c9fb2e57b --- /dev/null +++ b/board/freebox/nbx10g/nbx_nrboot.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * MVEBU NRBoot (Number of Reboots) tracking header + * + * Copyright (C) 2026 Free Mobile, Freebox + */ + +#ifndef __MVEBU_NRBOOT_H +#define __MVEBU_NRBOOT_H + +#include <mmc.h> + +/** + * mvebu_check_nrboot() - Check and update reboot tracking counter + * @mmc: MMC device + * @offset: Byte offset in MMC where nrboot data is stored + * + * This function reads the reboot tracking counter, checks if we've + * exceeded the maximum number of failed boots (4), and updates the + * counter for the current boot attempt. + * + * The counter uses a bit-field encoding: + * - nrboot: Running count of boot attempts + * - nrsuccess: Count of successful boots + * + * If boot - success >= MAX_FAILURE (4), the system is considered + * degraded and should use the fallback boot bank. + * + * Return: 1 if system is healthy (try newer bank first), + * 0 if system is degraded (use stable bank first) + */ +int mvebu_check_nrboot(struct mmc *mmc, unsigned long offset); + +#endif /* __MVEBU_NRBOOT_H */ diff --git a/board/zyxel/nsa325/nsa325.c b/board/zyxel/nsa325/nsa325.c index 38340b33c8b..894c2ef293c 100644 --- a/board/zyxel/nsa325/nsa325.c +++ b/board/zyxel/nsa325/nsa325.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2014-2023 Tony Dinh <[email protected]> + * Copyright (C) 2014-2025 Tony Dinh <[email protected]> * * Based on * Copyright (C) 2014 Jason Plum <[email protected]> @@ -51,11 +51,10 @@ DECLARE_GLOBAL_DATA_PTR; #define HDD1_GREEN_LED BIT(9) #define HDD1_RED_LED BIT(10) #define HDD2_POWER BIT(15) -#define WATCHDOG_SIGNAL BIT(14) #define NSA325_OE_HIGH (~(COPY_GREEN_LED | COPY_RED_LED | \ - HDD1_GREEN_LED | HDD1_RED_LED | HDD2_POWER | WATCHDOG_SIGNAL)) -#define NSA325_VAL_HIGH (WATCHDOG_SIGNAL | HDD2_POWER) + HDD1_GREEN_LED | HDD1_RED_LED | HDD2_POWER)) +#define NSA325_VAL_HIGH (HDD2_POWER) #define BTN_POWER 46 #define BTN_RESET 36 |
