From 001f7e5f4c0f18a247443797eafc89bf8400d1c4 Mon Sep 17 00:00:00 2001 From: Tony Dinh Date: Wed, 10 Dec 2025 14:27:05 -0800 Subject: arm: kirkwood: Remove unnecessary watchdog GPIO for ZyXEL NSA325 board Watchdog was already disabled in board/zyxel/nsa325/kwbimage.cfg. Signed-off-by: Tony Dinh Reviewed-by: Stefan Roese --- board/zyxel/nsa325/nsa325.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 + * Copyright (C) 2014-2025 Tony Dinh * * Based on * Copyright (C) 2014 Jason Plum @@ -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 -- cgit v1.3.1 From 50b3c87e0e2b6037dfa4dd9ee1e0ddb42165e835 Mon Sep 17 00:00:00 2001 From: Vincent Jardin Date: Tue, 16 Dec 2025 01:53:52 +0100 Subject: net: mvpp2: fix NULL pointer dereference in mvpp2_phy_connect Fix two NULL pointer dereferences in mvpp2_phy_connect(): 1. port->phy_dev->dev is used in dev_warn() but port->phy_dev is not assigned yet (assigned later at line below). 2. port->phy_dev->dev is used in dev_err() inside the "if (!phy_dev)" block, which means phy_dev is NULL. Both cases would cause a crash if the PHY detection fails or returns a generic PHY. Use the already available 'dev' parameter instead. Fixes: 9db60ee470c2 ("net: mvpp2: Convert netdev_xxx to dev_xxx") Signed-off-by: Vincent Jardin --- drivers/net/mvpp2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index fc137df14c4..ae5920a0201 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -4528,7 +4528,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) */ if (phy_dev && phy_dev->drv->uid == 0xffffffff) {/* Generic phy */ - dev_warn(port->phy_dev->dev, + dev_warn(dev, "Marking phy as invalid, link will not be checked\n"); /* set phy_addr to invalid value */ port->phyaddr = PHY_MAX_ADDR; @@ -4540,7 +4540,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) port->phy_dev = phy_dev; if (!phy_dev) { - dev_err(port->phy_dev->dev, "cannot connect to phy\n"); + dev_err(dev, "cannot connect to phy\n"); return; } phy_dev->supported &= PHY_GBIT_FEATURES; -- cgit v1.3.1 From a9cc75a25eb6b97ae8e22bdb63ef0bd2c6c690c9 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 19 Dec 2025 11:59:34 +1300 Subject: mtd: nand: pxa3xx: Pass valid dev to dev_err() info->controller.active is not initialised so the dev_err() call ends up dereferencing a null pointer causing a crash instead of outputting the error. Add a dev member to struct pxa3xx_nand_info and use that instead of info->controller.active->mtd.dev. Fixes: 661c98121d49 ("mtd: nand: pxa3xx: Fix not calling dev_xxx with a device") Signed-off-by: Chris Packham Reviewed-by: Stefan Roese --- drivers/mtd/nand/raw/pxa3xx_nand.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index 7324dc72e0a..ef01d48acc0 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -184,6 +184,7 @@ struct pxa3xx_nand_host { struct pxa3xx_nand_info { struct nand_hw_control controller; struct pxa3xx_nand_platform_data *pdata; + struct udevice *dev; struct clk *clk; void __iomem *mmio_base; @@ -585,8 +586,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) ts = get_timer(0); while (!(nand_readl(info, NDSR) & NDSR_RDDREQ)) { if (get_timer(ts) > TIMEOUT_DRAIN_FIFO) { - dev_err(info->controller.active->mtd.dev, - "Timeout on RDDREQ while draining the FIFO\n"); + dev_err(info->dev, "Timeout on RDDREQ while draining the FIFO\n"); return; } } @@ -638,8 +638,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) DIV_ROUND_UP(info->step_spare_size, 4)); break; default: - dev_err(info->controller.active->mtd.dev, - "%s: invalid state %d\n", __func__, info->state); + dev_err(info->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -1557,8 +1556,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = 512; if (ecc_stepsize != 512 || !(nfc_layouts[i].strength)) { - dev_err(info->controller.active->mtd.dev, - "ECC strength %d at page size %d is not supported\n", + dev_err(info->dev, "ECC strength %d at page size %d is not supported\n", strength, page_size); return -ENODEV; } @@ -1799,6 +1797,7 @@ static int pxa3xx_nand_probe(struct udevice *dev) if (ret) return ret; + info->dev = dev; pdata = info->pdata; ret = alloc_nand_resource(dev, info); -- cgit v1.3.1 From c444ff30e18cea32746adba6766b0da4c0d585b4 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 19 Dec 2025 11:59:35 +1300 Subject: arm: mvebu: db-xc3-24g4xg: Remove marvell, nand-keep-config nand-keep-config is used to retain the NAND controller configuration from an earlier boot stage. In U-Boot's case there isn't an earlier boot stage so reconfiguring the NAND controller is required. Signed-off-by: Chris Packham Reviewed-by: Stefan Roese --- arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi b/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi index dc20643bfa3..ad64813e770 100644 --- a/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi +++ b/arch/arm/dts/armada-xp-db-xc3-24g4xg-u-boot.dtsi @@ -5,7 +5,6 @@ status = "okay"; label = "pxa3xx_nand-0"; nand-rb = <0>; - marvell,nand-keep-config; nand-on-flash-bbt; nand-ecc-strength = <4>; nand-ecc-step-size = <512>; -- cgit v1.3.1 From 59e13ed8f6d8b030c6aaf7e2af77f073fecc3b30 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Fri, 19 Dec 2025 11:59:36 +1300 Subject: arm: mvebu: Add Allied Telesis x220 Add the Allied Telesis x220 board. There are a number of other variants with the same CPU block that are sold under some different brand names but the x220 was first. The x220 uses the AlleyCat3 switch chip with integrated ARMv7 CPU. Because of this it is reliant on a binary blob for the DDR training. In upstream u-boot this is replaced by an empty file. Signed-off-by: Chris Packham Reviewed-by: Stefan Roese --- arch/arm/dts/Makefile | 1 + arch/arm/dts/armada-xp-atl-x220.dts | 162 +++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/Kconfig | 7 ++ board/alliedtelesis/x220/.gitattributes | 1 + board/alliedtelesis/x220/.gitignore | 1 + board/alliedtelesis/x220/MAINTAINERS | 8 ++ board/alliedtelesis/x220/Makefile | 14 +++ board/alliedtelesis/x220/binary.0 | 11 +++ board/alliedtelesis/x220/kwbimage.cfg.in | 12 +++ board/alliedtelesis/x220/x220.c | 67 +++++++++++++ configs/x220_defconfig | 76 +++++++++++++++ doc/board/alliedtelesis/index.rst | 11 +++ doc/board/alliedtelesis/x220.rst | 39 ++++++++ doc/board/index.rst | 1 + include/configs/x220.h | 20 ++++ 15 files changed, 431 insertions(+) create mode 100644 arch/arm/dts/armada-xp-atl-x220.dts create mode 100644 board/alliedtelesis/x220/.gitattributes create mode 100644 board/alliedtelesis/x220/.gitignore create mode 100644 board/alliedtelesis/x220/MAINTAINERS create mode 100644 board/alliedtelesis/x220/Makefile create mode 100644 board/alliedtelesis/x220/binary.0 create mode 100644 board/alliedtelesis/x220/kwbimage.cfg.in create mode 100644 board/alliedtelesis/x220/x220.c create mode 100644 configs/x220_defconfig create mode 100644 doc/board/alliedtelesis/index.rst create mode 100644 doc/board/alliedtelesis/x220.rst create mode 100644 include/configs/x220.h diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index b75f3ee4386..722a7a662b1 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -137,6 +137,7 @@ dtb-$(CONFIG_ARCH_MVEBU) += \ armada-388-gp.dtb \ armada-388-helios4.dtb \ armada-38x-controlcenterdc.dtb \ + armada-xp-atl-x220.dtb \ armada-xp-crs305-1g-4s.dtb \ armada-xp-crs305-1g-4s-bit.dtb \ armada-xp-crs326-24g-2s.dtb \ diff --git a/arch/arm/dts/armada-xp-atl-x220.dts b/arch/arm/dts/armada-xp-atl-x220.dts new file mode 100644 index 00000000000..5b3307ed288 --- /dev/null +++ b/arch/arm/dts/armada-xp-atl-x220.dts @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Device Tree file for x220 board + * + * Copyright (C) 2025 Allied Telesis Labs + */ + +/dts-v1/; +#include +#include "armada-xp-98dx3236.dtsi" +#include "mvebu-u-boot.dtsi" + +/ { + model = "x220"; + compatible = "marvell,armadaxp-98dx3236", "marvell,armadaxp-mv78260", + "marvell,armadaxp", "marvell,armada-370-xp"; + + chosen { + stdout-path = "serial0:115200n8"; + bootargs = "console=ttyS0,115200"; + }; + + aliases { + i2c0 = &i2c0; + spi0 = &spi0; + }; + + memory { + device_type = "memory"; + reg = <0x00000000 0x00000000 0x00000000 0x20000000>; + }; +}; + +&L2 { + arm,parity-enable; + marvell,ecc-enable; +}; + +&devbus_bootcs { + status = "okay"; + + /* Device Bus parameters are required */ + + /* Read parameters */ + devbus,bus-width = <16>; + devbus,turn-off-ps = <60000>; + devbus,badr-skew-ps = <0>; + devbus,acc-first-ps = <124000>; + devbus,acc-next-ps = <248000>; + devbus,rd-setup-ps = <0>; + devbus,rd-hold-ps = <0>; + + /* Write parameters */ + devbus,sync-enable = <0>; + devbus,wr-high-ps = <60000>; + devbus,wr-low-ps = <60000>; + devbus,ale-wr-ps = <60000>; +}; + +&uart0 { + status = "okay"; +}; + +&i2c0 { + clock-frequency = <100000>; + status = "okay"; + + rtc@68 { + compatible = "dallas,ds1340"; + reg = <0x68>; + }; + + adt7476a@2e { + compatible = "adi,adt7476"; + reg = <0x2e>; + }; + + sfpgpio: gpio@27 { + #address-cells = <2>; + #size-cells = <0>; + compatible = "nxp,pca9555"; + reg = <0x27>; + gpio-controller; + #gpio-cells = <2>; + }; + + systemgpio: gpio@25 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "nxp,pca9555"; + reg = <0x25>; + gpio-controller; + #gpio-cells = <2>; + + nand-protect { + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "nand-protect"; + }; + + usb-enable { + gpio-hog; + gpios = <9 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "usb-enable"; + }; + + phy-reset { + gpio-hog; + gpios = <5 GPIO_ACTIVE_LOW>; + output-high; + line-name = "phy-reset"; + }; + + led-enable { + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "led-enable"; + }; + }; +}; + +&watchdog { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +&spi0 { + status = "okay"; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spi-flash", "jedec,spi-nor"; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <20000000>; + }; +}; + +&nand_controller { + compatible = "marvell,armada370-nand-controller"; + label = "pxa3xx_nand-0"; + status = "okay"; + nand-rb = <0>; + nand-on-flash-bbt; + nand-ecc-strength = <4>; + nand-ecc-step-size = <512>; +}; + +&{/} { + boot-board { + compatible = "atl,boot-board"; + present-gpio = <&systemgpio 12 GPIO_ACTIVE_HIGH>; + override-gpio = <&gpio0 31 GPIO_ACTIVE_HIGH>; + }; +}; + diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 4afaee234ea..0b4df8e7be9 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -226,6 +226,10 @@ config TARGET_X240 select ALLEYCAT_5 imply BOOTSTD_DEFAULTS +config TARGET_X220 + bool "Support Allied Telesis x220" + select 98DX3336 + config TARGET_DB_XC3_24G4XG bool "Support DB-XC3-24G4XG" select 98DX3336 @@ -310,6 +314,7 @@ config SYS_BOARD default "x530" if TARGET_X530 default "x250" if TARGET_X250 default "x240" if TARGET_X240 + default "x220" if TARGET_X220 default "db-xc3-24g4xg" if TARGET_DB_XC3_24G4XG default "crs3xx-98dx3236" if TARGET_CRS3XX_98DX3236 default "mvebu_alleycat-5" if TARGET_MVEBU_ALLEYCAT5 @@ -335,6 +340,7 @@ config SYS_CONFIG_NAME default "x530" if TARGET_X530 default "x250" if TARGET_X250 default "x240" if TARGET_X240 + default "x220" if TARGET_X220 default "db-xc3-24g4xg" if TARGET_DB_XC3_24G4XG default "crs3xx-98dx3236" if TARGET_CRS3XX_98DX3236 default "mvebu_alleycat-5" if TARGET_MVEBU_ALLEYCAT5 @@ -360,6 +366,7 @@ config SYS_VENDOR default "alliedtelesis" if TARGET_X530 default "alliedtelesis" if TARGET_X250 default "alliedtelesis" if TARGET_X240 + default "alliedtelesis" if TARGET_X220 default "mikrotik" if TARGET_CRS3XX_98DX3236 default "Marvell" if TARGET_MVEBU_ALLEYCAT5 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 +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 +#include +#include +#include +#include +#include +#include +#include +#include + +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/configs/x220_defconfig b/configs/x220_defconfig new file mode 100644 index 00000000000..4318f5e6ef1 --- /dev/null +++ b/configs/x220_defconfig @@ -0,0 +1,76 @@ +CONFIG_ARM=y +CONFIG_ARCH_CPU_INIT=y +CONFIG_ARCH_MVEBU=y +CONFIG_SYS_KWD_CONFIG="board/alliedtelesis/x220/kwbimage.cfg" +CONFIG_TEXT_BASE=0x00800000 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0xff0000 +CONFIG_TARGET_X220=y +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_OFFSET=0x100000 +CONFIG_ENV_SECT_SIZE=0x40000 +CONFIG_DEFAULT_DEVICE_TREE="armada-xp-atl-x220" +CONFIG_SYS_LOAD_ADDR=0x800000 +CONFIG_PCI=y +CONFIG_SYS_MEMTEST_START=0x00800000 +CONFIG_SYS_MEMTEST_END=0x00ffffff +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_BEST_MATCH=y +CONFIG_USE_PREBOOT=y +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_SYS_MAXARGS=96 +CONFIG_CMD_MEMTEST=y +CONFIG_SYS_ALT_MEMTEST=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_CMD_MTDPARTS=y +CONFIG_MTDIDS_DEFAULT="nand0=nand" +CONFIG_MTDPARTS_DEFAULT="mtdparts=nand:112M(user),8M(errlog),8M(nand-bbt)" +CONFIG_CMD_UBI=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_SPI_FLASH=y +CONFIG_ENV_RELOC_GD_ENV_ADDR=y +CONFIG_ARP_TIMEOUT=200 +CONFIG_NET_RETRY_COUNT=50 +CONFIG_GPIO_HOG=y +CONFIG_DM_PCA953X=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_MVTWSI=y +# CONFIG_MMC is not set +CONFIG_MTD_RAW_NAND=y +CONFIG_SYS_NAND_USE_FLASH_BBT=y +CONFIG_NAND_PXA3XX=y +CONFIG_SYS_NAND_ONFI_DETECTION=y +CONFIG_SPI_FLASH_SFDP_SUPPORT=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +# CONFIG_SPI_FLASH_USE_4K_SECTORS is not set +CONFIG_PCI_MVEBU=y +CONFIG_SYS_NS16550=y +CONFIG_KIRKWOOD_SPI=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_HOST_ETHER=y +CONFIG_USB_ETHER_ASIX=y +CONFIG_USB_ETHER_ASIX88179=y +CONFIG_USB_ETHER_MCS7830=y +CONFIG_USB_ETHER_RTL8152=y +CONFIG_USB_ETHER_SMSC95XX=y +CONFIG_WDT=y +CONFIG_WDT_ORION=y diff --git a/doc/board/alliedtelesis/index.rst b/doc/board/alliedtelesis/index.rst new file mode 100644 index 00000000000..a8de2986609 --- /dev/null +++ b/doc/board/alliedtelesis/index.rst @@ -0,0 +1,11 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (C) 2026 Allied Telesis Labs + +Allied Telesis +============== + +.. toctree:: + :maxdepth: 2 + + x220 + diff --git a/doc/board/alliedtelesis/x220.rst b/doc/board/alliedtelesis/x220.rst new file mode 100644 index 00000000000..6ca5f61ec4e --- /dev/null +++ b/doc/board/alliedtelesis/x220.rst @@ -0,0 +1,39 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. Copyright (C) 2026 Allied Telesis Labs + +x220 Platforms +============== + +Introduction +------------ + +The x220 has is a range of L2+ switches using the Marvell AlleyCat3 switch with +integrated ARMv7 CPU. It is also sold under some different brands for different +markets. + +- x220-52GP +- x220-52GT +- x220-28GS +- GS980M/52PS +- GS980M/52 +- x230-52 + +DDR Traning (binhdr) +-------------------- + +The AlleyCat3 uses a binary blob for it's DDR training. This is launched by +the built-in bootloader prior to U-Boot starting. + +To generate binary.0 from Marvell's bin_hdr.elf use the following command + +.. prompt:: bash $ + + arm-softfloat-linux-gnueabi-objcopy -S -O binary bin_hdr.elf \ + board/alliedtelesis/x220/binary.0 + +Alternatively, it is possible to extract the binary.0 from an existing U-Boot +image + +.. prompt:: bash $ + + ./tools/dumpimage -T kwbimage -p 1 -o board/alliedtelesis/x220/binary.0 u-boot.kwb diff --git a/doc/board/index.rst b/doc/board/index.rst index fcb4224bae3..4103fef8d8f 100644 --- a/doc/board/index.rst +++ b/doc/board/index.rst @@ -10,6 +10,7 @@ Board-specific doc actions/index advantech/index andestech/index + alliedtelesis/index allwinner/index amlogic/index anbernic/index diff --git a/include/configs/x220.h b/include/configs/x220.h new file mode 100644 index 00000000000..3022ad491b7 --- /dev/null +++ b/include/configs/x220.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2025 Allied Telesis Labs + */ + +#ifndef _CONFIG_X220_H +#define _CONFIG_X220_H + +/* Keep device tree and initrd in lower memory so the kernel can access them */ +#define CFG_EXTRA_ENV_SETTINGS \ + "fdt_high=0x10000000\0" \ + "initrd_high=0x10000000\0" + +/* + * mv-common.h should be defined after CMD configs since it used them + * to enable certain macros + */ +#include "mv-common.h" + +#endif /* _CONFIG_X220_H */ -- cgit v1.3.1 From f64593af3d96f97bb618f170dd37f8a99f2ae714 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Feb 2026 23:31:09 +0100 Subject: board: Synology: legacy.c: Include asm/io.h Some boards building this source define CFG_SYS_TCLK as a term involving readl() which is undefined otherwise. Signed-off-by: Phil Sutter --- board/Synology/common/legacy.c | 1 + 1 file changed, 1 insertion(+) 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 #include #include +#include #include #include "legacy.h" -- cgit v1.3.1 From b2306246ddb461db0ff18d638ab54bd675533748 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 12 Feb 2026 23:31:10 +0100 Subject: board: Synology: common: Fix typo in Makefile Due to this, legacy.c was neither compiled nor linked into the binary and thus booting legacy DS414 firmware failed. Missing atag setup led to no console output (and probably stalled boot) after: | Uncompressing Linux... done, booting the kernel. Fixes: 9774462e34faa ("arm: Disable ATAGs support") Signed-off-by: Phil Sutter --- board/Synology/common/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 -obj-$(SUPPORT_PASSING_ATAGS) += legacy.o +obj-$(CONFIG_SUPPORT_PASSING_ATAGS) += legacy.o -- cgit v1.3.1 From bd75c262403062254dfec953bff34bc9cc467206 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 25 Feb 2026 08:10:08 +0100 Subject: serial: serial_octeon_bootcmd.c: use correct Kconfig symbol CONFIG_SYS_IS_IN_ENV does not exist. CONFIG_SYS_CONSOLE_IS_IN_ENV seems to be needed here. Fixes: f1054661e50f ("serial: serial_octeon_bootcmd.c: Add PCI remote console support") Signed-off-by: Heinrich Schuchardt Reviewed-by: Stefan Roese --- drivers/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5f8b98f0704..c6e457572b1 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1024,7 +1024,7 @@ config OCTEON_SERIAL_BOOTCMD bool "MIPS Octeon PCI remote bootcmd input" depends on ARCH_OCTEON depends on DM_SERIAL - select SYS_IS_IN_ENV + select SYS_CONSOLE_IS_IN_ENV select CONSOLE_MUX help This driver supports remote input over the PCIe bus from a host -- cgit v1.3.1 From 9b432691dceb41639e8d060dc7f997b95039fd69 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 25 Mar 2026 13:00:22 -0600 Subject: arm: mvebu: Drop unnecessary BOARD_EARLY_INIT_F usage All of these platforms enable CONFIG_BOARD_EARLY_INIT_F and then have a do-nothing board_early_init_f function. Change to not enabling the option and so not needing an empty function. Signed-off-by: Tom Rini Reviewed-by: Robert Marko --- board/Marvell/mvebu_armada-37xx/board.c | 5 ----- configs/eDPU_defconfig | 1 - configs/mvebu_db-88f3720_defconfig | 1 - configs/mvebu_espressobin-88f3720_defconfig | 1 - configs/mvebu_espressobin_ultra-88f3720_defconfig | 1 - configs/uDPU_defconfig | 1 - 6 files changed, 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/configs/eDPU_defconfig b/configs/eDPU_defconfig index 9bc08cd05e9..e227dba5a42 100644 --- a/configs/eDPU_defconfig +++ b/configs/eDPU_defconfig @@ -23,7 +23,6 @@ CONFIG_SYS_PBSIZE=1048 # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_DISPLAY_BOARDINFO_LATE=y -CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SYS_PROMPT="eDPU>> " CONFIG_SYS_MAXARGS=32 # CONFIG_CMD_ELF is not set diff --git a/configs/mvebu_db-88f3720_defconfig b/configs/mvebu_db-88f3720_defconfig index 14862e4d60c..ff0f412b6d0 100644 --- a/configs/mvebu_db-88f3720_defconfig +++ b/configs/mvebu_db-88f3720_defconfig @@ -22,7 +22,6 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_DISPLAY_BOARDINFO_LATE=y -CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SYS_MAXARGS=32 CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y diff --git a/configs/mvebu_espressobin-88f3720_defconfig b/configs/mvebu_espressobin-88f3720_defconfig index c6574ebe8d9..9f5eda244ac 100644 --- a/configs/mvebu_espressobin-88f3720_defconfig +++ b/configs/mvebu_espressobin-88f3720_defconfig @@ -24,7 +24,6 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_DISPLAY_BOARDINFO_LATE=y -CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_LATE_INIT=y CONFIG_SYS_MAXARGS=32 CONFIG_CMD_FUSE=y diff --git a/configs/mvebu_espressobin_ultra-88f3720_defconfig b/configs/mvebu_espressobin_ultra-88f3720_defconfig index b37d2b5907e..16e0e54f657 100644 --- a/configs/mvebu_espressobin_ultra-88f3720_defconfig +++ b/configs/mvebu_espressobin_ultra-88f3720_defconfig @@ -23,7 +23,6 @@ CONFIG_SYS_CONSOLE_INFO_QUIET=y # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_DISPLAY_BOARDINFO_LATE=y -CONFIG_BOARD_EARLY_INIT_F=y CONFIG_BOARD_LATE_INIT=y CONFIG_SYS_MAXARGS=32 CONFIG_CMD_FUSE=y diff --git a/configs/uDPU_defconfig b/configs/uDPU_defconfig index 93f7e709ce6..7c83ff17b9c 100644 --- a/configs/uDPU_defconfig +++ b/configs/uDPU_defconfig @@ -22,7 +22,6 @@ CONFIG_SYS_PBSIZE=1048 # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_DISPLAY_BOARDINFO is not set CONFIG_DISPLAY_BOARDINFO_LATE=y -CONFIG_BOARD_EARLY_INIT_F=y CONFIG_SYS_PROMPT="uDPU>> " CONFIG_SYS_MAXARGS=32 # CONFIG_CMD_ELF is not set -- cgit v1.3.1 From dd1084ed2e91ef013244d83301f817f77a5734c9 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 8 May 2026 14:21:56 +0200 Subject: pinctrl: armada-38x: Staticize and constify driver ops Set the ops structure as static const. The structure is not accessible from outside of this driver and is not going to be modified at runtime. Signed-off-by: Marek Vasut Reviewed-by: Stefan Roese --- drivers/pinctrl/mvebu/pinctrl-armada-38x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c index 78184d2860a..c18afe958dc 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c @@ -550,7 +550,7 @@ static int armada_38x_pinctrl_probe(struct udevice *dev) return 0; } -struct pinctrl_ops armada_37xx_pinctrl_ops = { +static const struct pinctrl_ops armada_37xx_pinctrl_ops = { .get_pins_count = armada_38x_pinctrl_get_pins_count, .get_pin_name = armada_38x_pinctrl_get_pin_name, .get_functions_count = armada_38x_pinctrl_get_functions_count, -- cgit v1.3.1 From a721ac0da778589cf449abaca4b1c89c3a48f082 Mon Sep 17 00:00:00 2001 From: Vincent Jardin Date: Fri, 8 May 2026 15:54:04 +0200 Subject: arm: mach-mvebu: armada8k: cpuinfo and SAR Add CPU information display for Armada 8040 platforms. The soc_info.c reads the AP806 Sample-At-Reset (SAR) register to determine the PLL clock configuration and converts it to actual CPU, DDR, and Fabric frequencies using the PLL frequency table. Signed-off-by: Vincent Jardin Reviewed-by: Stefan Roese --- arch/arm/mach-mvebu/armada8k/Makefile | 2 +- arch/arm/mach-mvebu/armada8k/cpu.c | 12 ++ arch/arm/mach-mvebu/armada8k/soc_info.c | 194 ++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/armada8k/soc_info.h | 14 +++ 4 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-mvebu/armada8k/soc_info.c create mode 100644 arch/arm/mach-mvebu/armada8k/soc_info.h diff --git a/arch/arm/mach-mvebu/armada8k/Makefile b/arch/arm/mach-mvebu/armada8k/Makefile index 0a4756717a3..723239d9894 100644 --- a/arch/arm/mach-mvebu/armada8k/Makefile +++ b/arch/arm/mach-mvebu/armada8k/Makefile @@ -2,4 +2,4 @@ # # Copyright (C) 2016 Stefan Roese -obj-y = cpu.o cache_llc.o dram.o +obj-y = cpu.o cache_llc.o dram.o soc_info.o diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index 3eb93c82387..220b32dd025 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -15,6 +15,8 @@ #include #include +#include "soc_info.h" + /* Armada 7k/8k */ #define MVEBU_RFU_BASE (MVEBU_REGISTER(0x6f0000)) #define RFU_GLOBAL_SW_RST (MVEBU_RFU_BASE + 0x84) @@ -111,3 +113,13 @@ int mmc_get_env_dev(void) return CONFIG_ENV_MMC_DEVICE_INDEX; } + +int print_cpuinfo(void) +{ + if (!IS_ENABLED(CONFIG_DISPLAY_CPUINFO)) + return 0; + + soc_print_clock_info(); + soc_print_soc_info(); + return 0; +} diff --git a/arch/arm/mach-mvebu/armada8k/soc_info.c b/arch/arm/mach-mvebu/armada8k/soc_info.c new file mode 100644 index 00000000000..18cc083c0db --- /dev/null +++ b/arch/arm/mach-mvebu/armada8k/soc_info.c @@ -0,0 +1,194 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 Marvell International Ltd. + * + * Marvell Armada 8K SoC info: SAR, Clock frequencies, LLC status + * Ported from Marvell U-Boot 2015.01 to mainline U-Boot. + */ + +#include +#include +#include +#include +#include +#include + +/* Clock frequency units */ +#define KHz 1000 +#define MHz 1000000 +#define GHz 1000000000 + +/* AP806 SAR (Sample-At-Reset) register */ +#define AP806_SAR_REG_BASE (SOC_REGS_PHY_BASE + 0x6F4400) +#define SAR_CLOCK_FREQ_MODE_OFFSET 0 +#define SAR_CLOCK_FREQ_MODE_MASK (0x1f << SAR_CLOCK_FREQ_MODE_OFFSET) + +/* LLC (Last Level Cache) registers */ +#define LLC_BASE (SOC_REGS_PHY_BASE + 0x8000) +#define LLC_CTRL 0x100 +#define LLC_CTRL_EN 0x1 +#define LLC_EXCLUSIVE_EN 0x100 + +/* MSS clock is fixed at 200MHz on AP806 */ +#define AP806_MSS_CLOCK (200 * MHz) + +/* Clock ID indices in PLL frequency table */ +#define CPU_CLOCK_ID 0 +#define DDR_CLOCK_ID 1 +#define RING_CLOCK_ID 2 + +/* Clocking options (SAR field values) */ +enum clocking_options { + CPU_2000_DDR_1200_RCLK_1200 = 0x0, + CPU_2000_DDR_1050_RCLK_1050 = 0x1, + CPU_1600_DDR_800_RCLK_800 = 0x4, + CPU_1800_DDR_1200_RCLK_1200 = 0x6, + CPU_1800_DDR_1050_RCLK_1050 = 0x7, + CPU_1600_DDR_900_RCLK_900 = 0x0b, + CPU_1600_DDR_1050_RCLK_1050 = 0x0d, + CPU_1600_DDR_900_RCLK_900_2 = 0x0e, + CPU_1000_DDR_650_RCLK_650 = 0x13, + CPU_1300_DDR_800_RCLK_800 = 0x14, + CPU_1300_DDR_650_RCLK_650 = 0x17, + CPU_1200_DDR_800_RCLK_800 = 0x19, + CPU_1400_DDR_800_RCLK_800 = 0x1a, + CPU_600_DDR_800_RCLK_800 = 0x1b, + CPU_800_DDR_800_RCLK_800 = 0x1c, + CPU_1000_DDR_800_RCLK_800 = 0x1d, +}; + +/* + * PLL frequency table: maps SAR clock mode to actual frequencies. + * Format: { CPU_freq, DDR_freq, RING_freq, SAR_value } + */ +static const u32 pll_freq_tbl[16][4] = { + /* CPU */ /* DDR */ /* Ring */ + {2000 * MHz, 1200 * MHz, 1200 * MHz, CPU_2000_DDR_1200_RCLK_1200}, + {2000 * MHz, 1050 * MHz, 1050 * MHz, CPU_2000_DDR_1050_RCLK_1050}, + {1800 * MHz, 1200 * MHz, 1200 * MHz, CPU_1800_DDR_1200_RCLK_1200}, + {1800 * MHz, 1050 * MHz, 1050 * MHz, CPU_1800_DDR_1050_RCLK_1050}, + {1600 * MHz, 1050 * MHz, 1050 * MHz, CPU_1600_DDR_1050_RCLK_1050}, + {1600 * MHz, 900 * MHz, 900 * MHz, CPU_1600_DDR_900_RCLK_900_2}, + {1300 * MHz, 800 * MHz, 800 * MHz, CPU_1300_DDR_800_RCLK_800}, + {1300 * MHz, 650 * MHz, 650 * MHz, CPU_1300_DDR_650_RCLK_650}, + {1600 * MHz, 800 * MHz, 800 * MHz, CPU_1600_DDR_800_RCLK_800}, + {1600 * MHz, 900 * MHz, 900 * MHz, CPU_1600_DDR_900_RCLK_900}, + {1000 * MHz, 650 * MHz, 650 * MHz, CPU_1000_DDR_650_RCLK_650}, + {1200 * MHz, 800 * MHz, 800 * MHz, CPU_1200_DDR_800_RCLK_800}, + {1400 * MHz, 800 * MHz, 800 * MHz, CPU_1400_DDR_800_RCLK_800}, + {600 * MHz, 800 * MHz, 800 * MHz, CPU_600_DDR_800_RCLK_800}, + {800 * MHz, 800 * MHz, 800 * MHz, CPU_800_DDR_800_RCLK_800}, + {1000 * MHz, 800 * MHz, 800 * MHz, CPU_1000_DDR_800_RCLK_800} +}; + +/* + * Get the clock frequency mode index from SAR register. + * Returns index into pll_freq_tbl, or -1 if not found. + */ +static int sar_get_clock_freq_mode(void) +{ + u32 i; + u32 clock_freq; + + clock_freq = (readl(AP806_SAR_REG_BASE) & SAR_CLOCK_FREQ_MODE_MASK) + >> SAR_CLOCK_FREQ_MODE_OFFSET; + + for (i = 0; i < ARRAY_SIZE(pll_freq_tbl); i++) { + if (pll_freq_tbl[i][3] == clock_freq) + return i; + } + + pr_err("SAR: unsupported clock freq mode %d\n", clock_freq); + return -1; +} + +/* + * Get CPU clock frequency in Hz. + */ +static u32 soc_cpu_clk_get(void) +{ + int mode = sar_get_clock_freq_mode(); + + if (mode < 0) + return 0; + return pll_freq_tbl[mode][CPU_CLOCK_ID]; +} + +/* + * Get DDR clock frequency in Hz. + */ +static u32 soc_ddr_clk_get(void) +{ + int mode = sar_get_clock_freq_mode(); + + if (mode < 0) + return 0; + return pll_freq_tbl[mode][DDR_CLOCK_ID]; +} + +/* + * Get Ring (Fabric) clock frequency in Hz. + */ +static u32 soc_ring_clk_get(void) +{ + int mode = sar_get_clock_freq_mode(); + + if (mode < 0) + return 0; + return pll_freq_tbl[mode][RING_CLOCK_ID]; +} + +/* + * Get MSS clock frequency in Hz. + */ +static u32 soc_mss_clk_get(void) +{ + return AP806_MSS_CLOCK; +} + +/* + * Get LLC status and mode. + * Returns 1 if LLC is enabled, 0 otherwise. + * If excl_mode is not NULL, sets it to 1 if exclusive mode is enabled. + */ +static int llc_mode_get(int *excl_mode) +{ + u32 val; + int ret = 0, excl = 0; + + val = readl(LLC_BASE + LLC_CTRL); + if (val & LLC_CTRL_EN) { + ret = 1; + if (val & LLC_EXCLUSIVE_EN) + excl = 1; + } + if (excl_mode) + *excl_mode = excl; + + return ret; +} + +/* + * Print SoC clock information. + */ +void soc_print_clock_info(void) +{ + printf("Clock: CPU %-4d [MHz]\n", soc_cpu_clk_get() / MHz); + printf("\tDDR %-4d [MHz]\n", soc_ddr_clk_get() / MHz); + printf("\tFABRIC %-4d [MHz]\n", soc_ring_clk_get() / MHz); + printf("\tMSS %-4d [MHz]\n", soc_mss_clk_get() / MHz); +} + +/* + * Print SoC-specific information: DDR width and LLC status. + */ +void soc_print_soc_info(void) +{ + int llc_en, llc_excl_mode; + + printf("\tDDR 64 Bit width\n"); + + llc_en = llc_mode_get(&llc_excl_mode); + printf("\tLLC %s%s\n", llc_en ? "Enabled" : "Disabled", + llc_excl_mode ? " (Exclusive Mode)" : ""); +} diff --git a/arch/arm/mach-mvebu/armada8k/soc_info.h b/arch/arm/mach-mvebu/armada8k/soc_info.h new file mode 100644 index 00000000000..41afe7a2508 --- /dev/null +++ b/arch/arm/mach-mvebu/armada8k/soc_info.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2015 Marvell International Ltd. + * + * Marvell Armada 8K SoC info functions + */ + +#ifndef _ARMADA8K_SOC_INFO_H_ +#define _ARMADA8K_SOC_INFO_H_ + +void soc_print_clock_info(void); +void soc_print_soc_info(void); + +#endif /* _ARMADA8K_SOC_INFO_H_ */ -- cgit v1.3.1 From 3457acc01465644fff255ccbcd65470b64d57184 Mon Sep 17 00:00:00 2001 From: Vincent Jardin Date: Fri, 8 May 2026 15:54:05 +0200 Subject: board: freebox: add Nodebox 10G board support Add board support for the Freebox Nodebox 10G based on the Marvell Armada 8040 SoC. This board features: - Quad-core ARMv8 AP806 with dual CP110 companions - eMMC storage via Xenon SDHCI controller - 1G SGMII Ethernet on CP0 lane 5 - I2C buses for peripheral access - NS16550 UART console at 115200 baud The implementation includes: - Device tree for the Nodebox 10G hardware - Dedicated board directory (board/freebox/nbx10g/) - Board-specific Kconfig and defconfig The U-Boot comphy bindings (phy-type/phy-speed) differ from the mainline Linux PHY framework bindings used by phy-mvebu-cp110-comphy, so U-Boot and the kernel each have their own device tree. Signed-off-by: Vincent Jardin Reviewed-by: Stefan Roese --- arch/arm/dts/Makefile | 1 + arch/arm/dts/armada-8040-nbx.dts | 259 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/Kconfig | 9 ++ board/freebox/nbx10g/Kconfig | 12 ++ board/freebox/nbx10g/MAINTAINERS | 6 + board/freebox/nbx10g/Makefile | 3 + board/freebox/nbx10g/board.c | 53 ++++++++ configs/mvebu_nbx_88f8040_defconfig | 75 +++++++++++ include/configs/nbx10g.h | 29 ++++ 9 files changed, 447 insertions(+) create mode 100644 arch/arm/dts/armada-8040-nbx.dts create mode 100644 board/freebox/nbx10g/Kconfig create mode 100644 board/freebox/nbx10g/MAINTAINERS create mode 100644 board/freebox/nbx10g/Makefile create mode 100644 board/freebox/nbx10g/board.c create mode 100644 configs/mvebu_nbx_88f8040_defconfig create mode 100644 include/configs/nbx10g.h diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index 722a7a662b1..c647379c5ac 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -163,6 +163,7 @@ dtb-$(CONFIG_ARCH_MVEBU) += \ armada-8040-clearfog-gt-8k.dtb \ armada-8040-db.dtb \ armada-8040-mcbin.dtb \ + armada-8040-nbx.dtb \ armada-8040-puzzle-m801.dtb \ cn9130-db-A.dtb \ cn9130-db-B.dtb \ diff --git a/arch/arm/dts/armada-8040-nbx.dts b/arch/arm/dts/armada-8040-nbx.dts new file mode 100644 index 00000000000..b8b7298b4f5 --- /dev/null +++ b/arch/arm/dts/armada-8040-nbx.dts @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Device Tree file for NBX board (Freebox Nodebox10G) + * Based on Marvell Armada 8040 SoC + * + * Copyright (C) 2024 + */ + +#include "armada-8040.dtsi" + +/ { + model = "NBX Armada 8040"; + compatible = "nbx,armada8040", "marvell,armada8040"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + i2c0 = &cp0_i2c0; + i2c1 = &cp0_i2c1; + gpio0 = &ap_gpio0; + gpio1 = &cp0_gpio0; + gpio2 = &cp0_gpio1; + }; + + memory@00000000 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x80000000>; /* 2GB */ + }; +}; + +/* AP806 UART - active */ +&uart0 { + status = "okay"; +}; + +/* AP806 pinctrl */ +&ap_pinctl { + /* + * MPP Bus: + * eMMC [0-10] + * UART0 [11,19] + */ + /* 0 1 2 3 4 5 6 7 8 9 */ + pin-func = < 1 1 1 1 1 1 1 1 1 1 + 1 3 0 0 0 0 0 0 0 3 >; +}; + +/* AP806 on-board eMMC */ +&ap_sdhci0 { + pinctrl-names = "default"; + pinctrl-0 = <&ap_emmc_pins>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +/* CP0 pinctrl */ +&cp0_pinctl { + /* + * MPP Bus: + * [0-31] = 0xff: Keep default CP0_shared_pins + * [32,34] GE_MDIO/MDC + * [35-36] I2C1 + * [37-38] I2C0 + * [57-58] MSS I2C + */ + /* 0 1 2 3 4 5 6 7 8 9 */ + pin-func = < 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + 0xff 0xff 7 0 7 2 2 2 2 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 2 2 0 + 0 0 0 >; + + cp0_smi_pins: cp0-smi-pins { + marvell,pins = <32 34>; + marvell,function = <7>; + }; +}; + +/* CP0 I2C0 */ +&cp0_i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&cp0_i2c0_pins>; + status = "okay"; + clock-frequency = <100000>; +}; + +/* CP0 I2C1 */ +&cp0_i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&cp0_i2c1_pins>; + status = "okay"; + clock-frequency = <100000>; +}; + +/* CP0 MSS I2C0 - Management SubSystem I2C (pins 57-58, func 2) */ +&cp0_mss_i2c0 { + status = "okay"; +}; + +/* CP0 MDIO for PHY */ +&cp0_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cp0_smi_pins>; + + nbx_phy0: ethernet-phy@0 { + reg = <0>; + }; +}; + +/* CP0 ComPhy - SerDes configuration */ +&cp0_comphy { + /* + * CP0 Serdes Configuration: + * Lane 0-3: Unconnected + * Lane 4: SFI (10G Ethernet) + * Lane 5: SGMII2 (1G Ethernet) + */ + phy0 { + phy-type = ; + }; + phy1 { + phy-type = ; + }; + phy2 { + phy-type = ; + }; + phy3 { + phy-type = ; + }; + phy4 { + phy-type = ; + phy-speed = ; + }; + phy5 { + phy-type = ; + phy-speed = ; + }; +}; + +/* CP0 Ethernet - only eth2 (MAC3) is active via SGMII */ +&cp0_ethernet { + status = "okay"; +}; + +&cp0_eth2 { + status = "okay"; + phy = <&nbx_phy0>; + phy-mode = "sgmii"; +}; + +/* CP0 UTMI PHY for USB */ +&cp0_utmi { + status = "okay"; +}; + +&cp0_utmi0 { + status = "okay"; +}; + +&cp0_utmi1 { + status = "okay"; +}; + +/* CP0 USB3 Host controllers */ +&cp0_usb3_0 { + status = "okay"; +}; + +&cp0_usb3_1 { + status = "okay"; +}; + +/* CP1 pinctrl */ +&cp1_pinctl { + /* + * MPP Bus: + * [0-26] = Unconfigured + * [27-28] GE_MDIO/MDC + * [29-30] MSS I2C + * [31] = Unconfigured + * [32-62] = 0xff: Keep default CP1_shared_pins + */ + /* 0 1 2 3 4 5 6 7 8 9 */ + pin-func = < 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 + 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x8 0x8 0x8 + 0x8 0x0 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff + 0xff 0xff 0xff>; + + cp1_mss_i2c_pins: cp1-mss-i2c-pins { + marvell,pins = <29 30>; + marvell,function = <8>; + }; +}; + +/* CP1 MSS I2C0 - Management SubSystem I2C (pins 29-30, func 8) */ +&cp1_mss_i2c0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cp1_mss_i2c_pins>; +}; + +/* CP1 ComPhy - SerDes configuration */ +&cp1_comphy { + /* + * CP1 Serdes Configuration: + * Lane 0: PCIe x1 + * Lane 1: USB3 Host + * Lane 2-3: Unconnected + * Lane 4: SFI (10G Ethernet) + * Lane 5: Unconnected + */ + phy0 { + phy-type = ; + }; + phy1 { + phy-type = ; + }; + phy2 { + phy-type = ; + }; + phy3 { + phy-type = ; + }; + phy4 { + phy-type = ; + phy-speed = ; + }; + phy5 { + phy-type = ; + }; +}; + +/* CP1 PCIe x1 on lane 0 */ +&cp1_pcie0 { + status = "okay"; +}; + +/* CP1 USB3 Host on lane 1 */ +&cp1_usb3_0 { + status = "okay"; +}; + +/* CP1 UTMI PHY for USB */ +&cp1_utmi { + status = "okay"; +}; + +&cp1_utmi0 { + status = "okay"; +}; diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 0b4df8e7be9..3465ccfc151 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -166,6 +166,14 @@ config TARGET_MVEBU_ARMADA_8K select BOARD_LATE_INIT imply SCSI +config TARGET_NBX10G + bool "Support Freebox Nodebox 10G" + select ARMADA_8K + select BOARD_LATE_INIT + help + Enable support for the Freebox Nodebox 10G board based on the + Marvell Armada 8040 SoC with dual CP110 companion chips. + config TARGET_MVEBU_ALLEYCAT5 bool "Support AlleyCat 5 platforms" select ALLEYCAT_5 @@ -515,5 +523,6 @@ config ARMADA_32BIT_SYSCON_SYSRESET source "board/solidrun/clearfog/Kconfig" source "board/kobol/helios4/Kconfig" +source "board/freebox/nbx10g/Kconfig" endif diff --git a/board/freebox/nbx10g/Kconfig b/board/freebox/nbx10g/Kconfig new file mode 100644 index 00000000000..18a169761b7 --- /dev/null +++ b/board/freebox/nbx10g/Kconfig @@ -0,0 +1,12 @@ +if TARGET_NBX10G + +config SYS_BOARD + default "nbx10g" + +config SYS_VENDOR + default "freebox" + +config SYS_CONFIG_NAME + default "nbx10g" + +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 +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..bf83bdf63ee --- /dev/null +++ b/board/freebox/nbx10g/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y := board.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 + * + * Freebox Nodebox 10G board support + */ + +#include +#include +#include + +/* 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/configs/mvebu_nbx_88f8040_defconfig b/configs/mvebu_nbx_88f8040_defconfig new file mode 100644 index 00000000000..85a3086d6a0 --- /dev/null +++ b/configs/mvebu_nbx_88f8040_defconfig @@ -0,0 +1,75 @@ +CONFIG_ARM=y +CONFIG_ARCH_CPU_INIT=y +CONFIG_ARCH_MVEBU=y +CONFIG_TEXT_BASE=0x00000000 +CONFIG_NR_DRAM_BANKS=2 +CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y +CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0xff0000 +CONFIG_TARGET_NBX10G=y +CONFIG_ENV_SIZE=0x10000 +CONFIG_ENV_OFFSET=0x180000 +CONFIG_DM_GPIO=y +CONFIG_DEFAULT_DEVICE_TREE="armada-8040-nbx" +CONFIG_FIT=y +CONFIG_SYS_BOOTM_LEN=0x1000000 +CONFIG_SYS_LOAD_ADDR=0x800000 +CONFIG_PCI=y +# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set +# CONFIG_EFI_LOADER is not set +CONFIG_USE_PREBOOT=y +CONFIG_PREBOOT="echo (CRC warning is normal: no env saved yet)" +CONFIG_SYS_PBSIZE=1048 +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_LAST_STAGE_INIT=y +CONFIG_SYS_PROMPT="nodebox10G>> " +CONFIG_SYS_MAXARGS=32 +CONFIG_CMD_BOOTZ=y +# CONFIG_BOOTM_VXWORKS is not set +# CONFIG_CMD_ELF is not set +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_MISC=y +CONFIG_CMD_MMC=y +CONFIG_CMD_PCI=y +# CONFIG_CMD_SF is not set +CONFIG_CMD_USB=y +CONFIG_CMD_DHCP=y +CONFIG_CMD_MII=y +CONFIG_CMD_PING=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_NBX_EMMCBOOT=y +CONFIG_CMD_NBX_FBXSERIAL=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_EFI_PARTITION=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_MMC=y +CONFIG_ENV_RELOC_GD_ENV_ADDR=y +CONFIG_ARP_TIMEOUT=200 +CONFIG_NET_RETRY_COUNT=50 +CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_MVTWSI=y +CONFIG_I2C_MUX=y +CONFIG_MISC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_XENON=y +# CONFIG_SPI_FLASH is not set +CONFIG_PHY_MARVELL=y +CONFIG_PHY_GIGE=y +CONFIG_MVPP2=y +CONFIG_PCIE_DW_MVEBU=y +CONFIG_PHY=y +CONFIG_MVEBU_COMPHY_SUPPORT=y +CONFIG_PINCTRL=y +CONFIG_PINCTRL_ARMADA_8K=y +CONFIG_SYS_NS16550=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_STORAGE=y diff --git a/include/configs/nbx10g.h b/include/configs/nbx10g.h new file mode 100644 index 00000000000..bd083b7e7d8 --- /dev/null +++ b/include/configs/nbx10g.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2017-2018 Freebox SA + * Copyright (C) 2026 Free Mobile, Vincent Jardin + * + * Configuration for Freebox Nodebox 10G + */ + +#ifndef _CONFIG_NBX10G_H +#define _CONFIG_NBX10G_H + +#include "mvebu_armada-8k.h" + +/* Override environment settings for NBX */ +#undef CFG_EXTRA_ENV_SETTINGS +#define CFG_EXTRA_ENV_SETTINGS \ + "hostname=nodebox10G\0" \ + "ethrotate=no\0" \ + "image_addr=0x7000000\0" \ + "image_name=Image.nodebox10G\0" \ + "fdt_addr=0x6f00000\0" \ + "fdt_name=nodebox10G.dtb\0" \ + "console=ttyS0,115200\0" \ + "tftpboot=setenv bootargs console=${console} bank=tftp; " \ + "dhcp ${image_addr} ${image_name}; " \ + "tftp ${fdt_addr} ${fdt_name}; " \ + "booti ${image_addr} - ${fdt_addr}\0" + +#endif /* _CONFIG_NBX10G_H */ -- cgit v1.3.1 From 3db9d9abc105f48eeb34bdccdce0516065ed76ed Mon Sep 17 00:00:00 2001 From: Vincent Jardin Date: Fri, 8 May 2026 15:54:06 +0200 Subject: board: freebox: nbx10g: add emmcboot for dual-bank eMMC boot Add the emmcboot command as board-specific support for the Nodebox 10G. This is a legacy boot format that has been in production on this board for many years so it cannot change anymore. It implements a dual-bank boot system for reliable firmware updates: - Bank0: Stable/fallback boot image - Bank1: Newer/test boot image with reboot tracking The boot order depends on the nrboot counter stored in eMMC: - Healthy state (counter < 4): Try Bank1 first, then Bank0 - Degraded state (counter >= 4): Try Bank0 first, then Bank1 Each bank stores an image tag with CRC32 validation. The counter uses a bit-counting scheme for wear leveling and tracks consecutive failed boots to trigger automatic fallback. Signed-off-by: Vincent Jardin Reviewed-by: Stefan Roese --- board/freebox/nbx10g/Kconfig | 53 ++++++ board/freebox/nbx10g/Makefile | 1 + board/freebox/nbx10g/nbx_emmcboot.c | 357 ++++++++++++++++++++++++++++++++++++ board/freebox/nbx10g/nbx_imagetag.h | 78 ++++++++ board/freebox/nbx10g/nbx_nrboot.h | 34 ++++ 5 files changed, 523 insertions(+) create mode 100644 board/freebox/nbx10g/nbx_emmcboot.c create mode 100644 board/freebox/nbx10g/nbx_imagetag.h create mode 100644 board/freebox/nbx10g/nbx_nrboot.h diff --git a/board/freebox/nbx10g/Kconfig b/board/freebox/nbx10g/Kconfig index 18a169761b7..d21153eae75 100644 --- a/board/freebox/nbx10g/Kconfig +++ b/board/freebox/nbx10g/Kconfig @@ -9,4 +9,57 @@ config SYS_VENDOR 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 + endif diff --git a/board/freebox/nbx10g/Makefile b/board/freebox/nbx10g/Makefile index bf83bdf63ee..a3b3d3a1fe3 100644 --- a/board/freebox/nbx10g/Makefile +++ b/board/freebox/nbx10g/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y := board.o +obj-$(CONFIG_CMD_NBX_EMMCBOOT) += nbx_emmcboot.o 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 (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_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 + +#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 + +/** + * 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 */ -- cgit v1.3.1 From 35ae4491bf7d6296f48baa79a6539aa63b23b0bc Mon Sep 17 00:00:00 2001 From: Vincent Jardin Date: Fri, 8 May 2026 15:54:07 +0200 Subject: board: freebox: nbx10g: add device serial and MAC address initialization Read device identification data from a dedicated eMMC region. This provides: - Unique device serial number for identification and tracking - Factory-programmed MAC address for network interfaces - Bundle information for device variant identification The serial structure includes CRC32 validation to detect corruption. On read failure or invalid data, sensible defaults are used to ensure the system remains bootable. The fbxserial command provides two subcommands: - fbxserial show: Display serial info (default) - fbxserial init: Initialize ethaddr from serial info Use CONFIG_PREBOOT="fbxserial init" to automatically set MAC addresses during boot. This approach avoids patching shared board code. Signed-off-by: Vincent Jardin Reviewed-by: Stefan Roese --- board/freebox/nbx10g/Kconfig | 29 ++++ board/freebox/nbx10g/Makefile | 1 + board/freebox/nbx10g/nbx_fbxserial.c | 286 +++++++++++++++++++++++++++++++++++ board/freebox/nbx10g/nbx_fbxserial.h | 156 +++++++++++++++++++ 4 files changed, 472 insertions(+) create mode 100644 board/freebox/nbx10g/nbx_fbxserial.c create mode 100644 board/freebox/nbx10g/nbx_fbxserial.h diff --git a/board/freebox/nbx10g/Kconfig b/board/freebox/nbx10g/Kconfig index d21153eae75..958c8fdd4c3 100644 --- a/board/freebox/nbx10g/Kconfig +++ b/board/freebox/nbx10g/Kconfig @@ -62,4 +62,33 @@ config NBX_MMC_PART_BANK1_SIZE 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/Makefile b/board/freebox/nbx10g/Makefile index a3b3d3a1fe3..4b70d94e14d 100644 --- a/board/freebox/nbx10g/Makefile +++ b/board/freebox/nbx10g/Makefile @@ -2,3 +2,4 @@ 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/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +/* + * 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 */ -- cgit v1.3.1 From 7e9312917368ac4d6467158ce00f36b92b6d64b0 Mon Sep 17 00:00:00 2001 From: Vincent Jardin Date: Fri, 8 May 2026 15:54:08 +0200 Subject: arm: dts: armada-8040-nbx: add U-Boot dtsi for conditional OP-TEE Add armada-8040-nbx-u-boot.dtsi with the firmware/optee node guarded by CONFIG_OPTEE. This allows U-Boot to probe the OP-TEE driver only when OP-TEE support is enabled in the configuration. Signed-off-by: Vincent Jardin Reviewed-by: Stefan Roese --- arch/arm/dts/armada-8040-nbx-u-boot.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 arch/arm/dts/armada-8040-nbx-u-boot.dtsi diff --git a/arch/arm/dts/armada-8040-nbx-u-boot.dtsi b/arch/arm/dts/armada-8040-nbx-u-boot.dtsi new file mode 100644 index 00000000000..dec473b7156 --- /dev/null +++ b/arch/arm/dts/armada-8040-nbx-u-boot.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Free Mobile, Vincent Jardin + */ + +#ifdef CONFIG_OPTEE +/ { + firmware { + optee { + compatible = "linaro,optee-tz"; + method = "smc"; + }; + }; +}; +#endif -- cgit v1.3.1 From eab66c3a9085e07b227847b0c442ee8d2efb241d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Tue, 26 May 2026 15:53:06 +0800 Subject: timer: orion: Use dev_remap_addr_index() Use dev_remap_addr_index() which supports both live device tree and flat DT backends, avoiding direct dependency on devfdt_* helpers. No functional changes. Signed-off-by: Peng Fan --- drivers/timer/orion-timer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/timer/orion-timer.c b/drivers/timer/orion-timer.c index 821b681a232..4d1c6b5cef2 100644 --- a/drivers/timer/orion-timer.c +++ b/drivers/timer/orion-timer.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -113,7 +114,7 @@ static int orion_timer_probe(struct udevice *dev) enum input_clock_type type = dev_get_driver_data(dev); struct orion_timer_priv *priv = dev_get_priv(dev); - priv->base = devfdt_remap_addr_index(dev, 0); + priv->base = dev_remap_addr_index(dev, 0); if (!priv->base) { debug("unable to map registers\n"); return -ENOMEM; -- cgit v1.3.1