diff --git a/.github/workflows/build-boot.yml b/.github/workflows/build-boot.yml index 43ea5d18a..26b62920c 100644 --- a/.github/workflows/build-boot.yml +++ b/.github/workflows/build-boot.yml @@ -30,6 +30,7 @@ jobs: - rpi64_boot - sama7g54_ek_emmc_boot - sama7g54_ek_sd_boot + - tactical_boot env: MAKEFLAGS: -j5 steps: diff --git a/README.md b/README.md index a1e17c263..44e1e585b 100644 --- a/README.md +++ b/README.md @@ -143,9 +143,9 @@ compromised service or container can't rewrite the OS underneath it. - - - bitSign - Code Signing + + + bitSign - Code Signing diff --git a/board/aarch64/Config.in b/board/aarch64/Config.in index dc4fbce90..18e429bee 100644 --- a/board/aarch64/Config.in +++ b/board/aarch64/Config.in @@ -11,6 +11,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/marvell-cn9130-crb/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/marvell-espressobin/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/microchip-ev23x71a/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/microchip-sparx5-pcb135/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/novarq-tactical-1000/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/raspberrypi-rpi64/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/styx-dcp-sc-28p/Config.in" diff --git a/board/aarch64/microchip-ev23x71a/README.md b/board/aarch64/microchip-ev23x71a/README.md index 195d5534c..7ccf57208 100644 --- a/board/aarch64/microchip-ev23x71a/README.md +++ b/board/aarch64/microchip-ev23x71a/README.md @@ -52,9 +52,8 @@ up DDR and loads BL31 and U-Boot as BL33. > [!NOTE] > The vendor U-Boot has neither `blkmap`, SquashFS support nor `sysboot`, so > it cannot map a signed `rootfs.itb` and read `/boot/syslinux/*.conf` out of -> it, which is how Infix boots. It is possible to [Netboot](#netboot) from -> it, though we recommend going for the adapted [Bootloader](#bootloader) to -> be able to boot properly from eMMC. +> it, which is how Infix boots. [Netboot](#netboot) works from it, but +> booting properly from eMMC needs the adapted [Bootloader](#bootloader). ## Boot Mode Strapping @@ -119,12 +118,6 @@ build needs mbed TLS to parse X.509 in BL1 and BL2. That comes from the `mbedtls-atf` package, pinned to the 2.28 series ATF 2.8 builds against, since Buildroot's `mbedtls` tracks 3.x. -This defconfig builds the `mchp_lan969x_defconfig` plus local fragments, which -add `blkmap`, SquashFS, `sysboot`, and the signed image validation the Infix -boot flow needs, and pin the control device tree to this board. The board -environment, `lan969x-env.dtsi`, sets the load addresses and names the kernel -device tree to pick out of the SquashFS. - Two build variables are not obvious. `KEY_ALG=ecdsa`, because the LAN969x crypto driver is built around the Silex ECDSA engine and will not compile against an mbed TLS configured for RSA only. And `GENERATE_COT=1`, because @@ -148,8 +141,8 @@ see [`ERRATA.md`][5] in the Microchip Trusted Firmware tree. ## Installing -The bootloader and the Linux image are separate builds, combined into one eMMC -image using the `mkimage.sh` script: +The bootloader and the Linux image are separate builds, combined into one +eMMC image with `mkimage.sh`: ```bash make laguna_boot_defconfig O=x-boot-laguna && make O=x-boot-laguna @@ -210,8 +203,8 @@ environment, so it is only there when booting the NOR image. ## Netboot -Once the Infix U-Boot is in place, netbooting needs no script at all: hand out -a `rootfs.itb` as the DHCP boot file and `ixprepdhcp` fetches, validates, and +With the Infix U-Boot in place netbooting needs no script: hand out a +`rootfs.itb` as the DHCP boot file and `ixprepdhcp` fetches, validates, and boots it, see the [netboot HowTo][1]. The recipe below is for boards still running the vendor U-Boot, before our FIP @@ -284,10 +277,18 @@ build, flash, and boot cycle. ## Switch Core The board reports part `0x969b` revision 0, a LAN9696RED (lan969x-60-RED). -The driver reads `GCB_CHIP_ID` at probe but never prints it, so read it out: +The driver reads `GCB_CHIP_ID` at probe but never prints it, so read it out. + +From Linux: ``` -devmem 0xe2010000 32 +$ devmem 0xe2010000 32 +``` + +or from U-Boot: + +``` +m => md.l 0xe2010000 1 ``` Bits 27:12 hold the part, 31:28 the revision. Which part it is decides what @@ -320,11 +321,14 @@ without either. | `0x0556` | SparX-5-160i | Industrial | yes | | `0x0558` | SparX-5-200i | Industrial | yes | +`0x9697` is a LAN9696TSN, the [Novarq Tactical +1000](../novarq-tactical-1000/README.md). + The register is the same on SparX-5, only the address differs, since `TARGET_GCB` sits elsewhere in that family's register map: ``` -devmem 0x611010000 32 +$ devmem 0x611010000 32 ``` The RED in the part number is hardware HSR/PRP RedBox support. @@ -332,9 +336,8 @@ The RED in the part number is hardware HSR/PRP RedBox support. ## Interfaces The sparx5 driver leaves naming to the kernel, which hands out `eth0` and up -in probe order, this makes it off-by-one from the numbering in the official -documentation. The product specific `90-ev23x71a-rename-ifaces.rules` renames -them to the usual interface names: +in probe order, one off from the numbering in the official documentation. The +product specific `90-ev23x71a-rename-ifaces.rules` renames them: | **Device tree** | **Interface** | **Port** | |--------------------|----------------|---------------------| @@ -342,10 +345,8 @@ them to the usual interface names: | `port@24..port@27` | `e25` .. `e28` | 10G SFP+ | | `port@29` | `e29` | 1G RGMII management | -Attaching 29 PHYs takes the driver a good half second each, far longer than -the ten seconds `hw-wait` waits for slow devices by default. The product -therefore raises it in `/etc/default/hw-wait`, so that services which expect -the ports to exist do not start ahead of them. +Attaching 29 PHYs takes about half a second each, far longer than `hw-wait`'s +ten second default, so the product raises it in `/etc/default/hw-wait`. ## LEDs @@ -385,7 +386,7 @@ state there: Reading `is2_0` after a `tc filter add` shows what the classifier actually programmed, which is the quickest way to separate an unsupported match from a broken one. The per port files show which key sets each lookup is configured -for, which is what decides whether a rule can match on a given port at all. +for, which decides whether a rule can match on that port at all. Every port netdev links to its device tree node, so they can be mapped back to switch ports whatever order they probed in: diff --git a/board/aarch64/microchip-ev23x71a/uboot/lan969x-env.dtsi b/board/aarch64/microchip-ev23x71a/uboot/lan969x-env.dtsi deleted file mode 100644 index e065757d3..000000000 --- a/board/aarch64/microchip-ev23x71a/uboot/lan969x-env.dtsi +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Board environment, applied on top of the common Infix one. DRAM - * starts at 0x60000000, and the addresses mirror the layout used on - * other Infix boards: the kernel is staged 64 MiB in, clear of where - * booti relocates it to at the start of DRAM. - */ -/ { - config { - /* - * Name the partition holding the environment, rather than - * inheriting the offset from lan969x.dtsi, which points - * into the middle of the Infix layout. - */ - u-boot,mmc-env-partition = "Env"; - }; -}; - -&env { - bootcmd = "run ixboot"; - boot_targets = "mmc0"; - - board = "microchip,ev23x71a"; - fdtfile = "microchip/lan9696-ev23x71a.dtb"; - - loadaddr = "0x63000000"; - fdt_addr_r = "0x63f00000"; - kernel_addr_r = "0x64000000"; - fdtoverlay_addr_r = "0x67f00000"; - scriptaddr = "0x68000000"; - ramdisk_addr_r = "0x6a000000"; - - /* This is a development board, keep developer mode enabled. */ - ixbtn-devmode = "setenv dev_mode yes; echo Enabled"; - - /* No front panel button to hold, and no button command built. */ - ixbtn-factory = "echo Unavailable"; -}; diff --git a/board/aarch64/microchip-ev23x71a/uboot/extras.config b/board/aarch64/microchip-lan969x/uboot/extras.config similarity index 68% rename from board/aarch64/microchip-ev23x71a/uboot/extras.config rename to board/aarch64/microchip-lan969x/uboot/extras.config index db23bdc15..5c7f69e8c 100644 --- a/board/aarch64/microchip-ev23x71a/uboot/extras.config +++ b/board/aarch64/microchip-lan969x/uboot/extras.config @@ -1,8 +1,10 @@ -# One board, one control device tree. The vendor defconfig carries a -# device tree for each LAN969x board and selects between them with -# MULTI_DTB_FIT, which also makes fit_conf_get_node() match FIT -# configurations by compatible string instead of honoring the default -# property, see the board README. +# One control device tree for every Laguna board. U-Boot drives the +# same peripherals on each, and the Linux device tree is chosen at boot, +# see lan969x-env.dtsi. The vendor defconfig instead carries a control +# device tree per board and selects between them with MULTI_DTB_FIT, +# which also makes fit_conf_get_node() match FIT configurations by +# compatible string instead of honoring the default property, see the +# EV23X71A README. CONFIG_DEFAULT_DEVICE_TREE="lan969x_ev23x71a" CONFIG_OF_LIST="lan969x_ev23x71a" # CONFIG_MULTI_DTB_FIT is not set diff --git a/board/aarch64/microchip-lan969x/uboot/lan969x-env.dtsi b/board/aarch64/microchip-lan969x/uboot/lan969x-env.dtsi new file mode 100644 index 000000000..cf5f1f682 --- /dev/null +++ b/board/aarch64/microchip-lan969x/uboot/lan969x-env.dtsi @@ -0,0 +1,50 @@ +/* + * Laguna board environment, applied on top of the common Infix one and + * shared by every LAN969x board. U-Boot drives the same console, eMMC, + * I2C, and GPIO on all of them, so one control device tree serves; only + * the Linux device tree differs, and that is picked at boot, see ixboard. + * + * DRAM starts at 0x60000000 on all of them too, and the addresses mirror + * the layout used on other Infix boards: the kernel is staged 64 MiB in, + * clear of where booti relocates it to at the start of DRAM. + */ +/ { + config { + /* + * Name the partition holding the environment, rather than + * inheriting the offset from lan969x.dtsi, which points + * into the middle of the Infix layout. + */ + u-boot,mmc-env-partition = "Env"; + }; +}; + +&env { + bootcmd = "run ixboard; run ixboot"; + boot_targets = "mmc0"; + + /* + * Which board this is. The EV23X71A is the default, so a Laguna + * board this knows nothing about boots as one, which is what it + * did before. The Tactical 1000 is told apart by its part number, + * bits 27:12 of GCB_CHIP_ID: 0x9697 against the eval board's + * 0x969b. That is the SoC variant rather than the board, and the + * best there is until Novarq give us a real board ID. + */ + board = "microchip,ev23x71a"; + fdtfile = "microchip/lan9696-ev23x71a.dtb"; + ixboard = "if setexpr.l cid *0xe2010000 && setexpr cid ${cid} / 0x1000 && setexpr cid ${cid} % 0x10000 && test ${cid} = 9697; then setenv board novarq,tactical-1000; setenv fdtfile microchip/lan9696-tactical-1000.dtb; fi"; + + loadaddr = "0x63000000"; + fdt_addr_r = "0x63f00000"; + kernel_addr_r = "0x64000000"; + fdtoverlay_addr_r = "0x67f00000"; + scriptaddr = "0x68000000"; + ramdisk_addr_r = "0x6a000000"; + + /* Development boards and test rigs, keep developer mode enabled. */ + ixbtn-devmode = "setenv dev_mode yes; echo Enabled"; + + /* No button command built, whether or not the board has one. */ + ixbtn-factory = "echo Unavailable"; +}; diff --git a/board/aarch64/novarq-tactical-1000/Config.in b/board/aarch64/novarq-tactical-1000/Config.in new file mode 100644 index 000000000..4c66e6205 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/Config.in @@ -0,0 +1,7 @@ +config BR2_PACKAGE_NOVARQ_TACTICAL_1000 + bool "Novarq Tactical 1000 (Laguna)" + depends on BR2_aarch64 + help + Support for the Novarq Tactical 1000, based on the LAN969x + (Laguna) family of TSN capable switches. 24 GbE copper ports, + 4 SFP+ ports, and a separate management port. diff --git a/board/aarch64/novarq-tactical-1000/LICENSE b/board/aarch64/novarq-tactical-1000/LICENSE new file mode 100644 index 000000000..8cdb30a3a --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2026 The KernelKit Authors + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/board/aarch64/novarq-tactical-1000/README.md b/board/aarch64/novarq-tactical-1000/README.md new file mode 100644 index 000000000..350304878 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/README.md @@ -0,0 +1,154 @@ +# Novarq Tactical-1000 + + +The board + + +A 28-port switch built on the Microchip LAN969x (Laguna) family, a cut down +version of the EV23X71A (EVB) reference design. See [Tactical-1000][0]. + +| **Property** | **Value** | +|--------------|------------------------------------------| +| SoC | LAN9696TSN, ARM Cortex-A53 single-core | +| Memory | 2 GiB DDR4 @ 2400 MHz, ECC disabled | +| Storage | eMMC on SDMMC0, QSPI NOR | +| Switch | 24 x GbE copper, 4 x SFP+, 1 x RGMII NPI | +| Console | `ttyAT0`, 115200 8N1 | + +The chip reports `0x9697` in `GCB_CHIP_ID`, a LAN9696TSN. The [EV23X71A][3] +is a `0x969b`, a LAN9696RED. + +## Boot Mode + +VCORE[3:0] and the SoC reset line are GPIOs on the MCP2200 behind the USB-C +console port: GP2..GP5 are VCORE0..3, GP0 is reset. Novarq's +[`mcp2200ctl.py`][5] drives them over hidraw. The kernel's `hid_mcp2200` +GPIO driver claims that interface first and has to go; the console, +`ttyACM0`, is `cdc_acm` and unaffected: + +```bash +echo 'blacklist hid_mcp2200' | sudo tee /etc/modprobe.d/mcp2200.conf +sudo rmmod hid_mcp2200 +echo 'SUBSYSTEM=="hidraw", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="00df", MODE="0660", TAG+="uaccess"' \ + | sudo tee /etc/udev/rules.d/70-mcp2200.rules +sudo udevadm control --reload +``` + +Replug the console cable. Then the tool, in a venv: + +```bash +git clone https://github.com/novarq/mcp2200py.git && cd mcp2200py +python3 -m venv .venv && . .venv/bin/activate +pip install -r requirements.txt +python3 mcp2200ctl.py get-gpio +``` + +`get-gpio` reports `0x01` as shipped: VCORE 0000, reset released. The SoC +samples the straps on reset: + +```bash +python3 mcp2200ctl.py set-tactical-1000-boot-mode tfa-monitor +python3 mcp2200ctl.py reset-tactical-1000 +``` + +| **VCORE[3:0]** | **Mode** | **Console** | +|----------------|------------------|---------------------------------| +| 0000 | `emmc-trace` | ROM boot trace, 115200, default | +| 0011 | `emmc` | no ROM trace | +| 1010 | `tfa-monitor` | TF-A monitor, 115200 | +| 1011 | `tfa-monitor-hs` | TF-A monitor, 921600 | + +The monitor is on the same USB console and takes a FIP from +[`fwu-lan969x_a0-release.html`][1], so a FIP that hangs is recoverable. +Full table and persistent defaults in Novarq's [boot modes][6] document. + +## Bootloader + +Currently board-specific: + +```bash +make tactical_boot_defconfig O=x-boot-tactical && make O=x-boot-tactical +``` + +Install to `fip` and leave the vendor FIP in `fip.bak`. BL1 falls back to +it if `fip` fails to load, but not if `fip` loads and hangs; for that, see +[Boot Mode](#boot-mode). + +`/usr/libexec/infix/prod/provision-tactical` lays out the eMMC for Infix, +asking before each step. Netboot with `init=/bin/sh` appended to `bootargs` +and run it from there, nothing from the eMMC may be mounted. + +The vendor U-Boot saves its environment at `0x10100000` and `0x10300000`, +the second of which is past the 2 MiB `Env` partition; the script grows +`Env` to 4 MiB. + +```bash +scp x-boot-tactical/images/fip.bin admin@board:/tmp +ssh admin@board 'sudo dd if=/tmp/fip.bin of=/dev/mmcblk0p1 conv=fsync' +``` + +## Installing + +The bootloader and the Linux image are separate builds, combined into one +eMMC image with `mkimage.sh`: + +```bash +make tactical_boot_defconfig O=x-boot-tactical && make O=x-boot-tactical +make aarch64_defconfig && make +utils/mkimage.sh -b x-boot-tactical -r output -t emmc novarq-tactical-1000 +``` + +The image carries the Infix FIP in both `fip` and `fip.bak`. Netboot the +board and stream the image to the eMMC, see [Installing to Onboard +Storage][7]. A unit still on the vendor U-Boot netboots as described in +[Netboot with a Vendor U-Boot][8]. The first boot grows `var` to fill the +eMMC and reboots once by itself. + +## Device Tree + +Cherry-picked from [Novarq's kernel tree][2]. One commit adapts it to +6.18 and is to be reverted on the next LTS kernel, it drops: + +- the `&qspi0` flash node +- the `tmon` fan PWM +- the cooling maps for that fan, the `gpio-fan` gets one trip + +## Interfaces + +The copper ports run **backwards within each QSGMII quad**: `port@0` is `lan4`, +`port@3` is `lan1`, `port@4` is `lan8`, and so on in fours. The SFP and +management ports are in order. + +| **Device tree** | **Interface** | **Port** | +|------------------------|-----------------------------------------------|---------------------| +| `port@0` .. `port@23` | `e4`,`e3`,`e2`,`e1`, `e8`,`e7`,`e6`,`e5`, ... | 1G copper, QSGMII | +| `port@24` .. `port@27` | `e25` .. `e28` | 10G SFP+ | +| `port@29` | `mgmt` | 1G RGMII management | + +`90-tactical-1000-rename-ifaces.rules` matches on `OF_FULLNAME`, so `e1` is +the port marked 1 on the front panel. + +## LEDs + +One software controlled status LED, and a green and yellow pair per SFP cage, +driven over SGPIO: + +``` +green:status front panel status +green:lan-0 .. green:lan-3 SFP1 .. SFP4, green +yellow:lan-0 .. yellow:lan-3 SFP1 .. SFP4, yellow +``` + +`green:status` blinks at 1 Hz while booting, steady once `startup-config` +has been applied, 5 Hz for a fail-safe boot or a panic. The green SFP LEDs +have the netdev trigger, bound to `e25` through `e28`. The yellow ones are +unused. + +[0]: https://novarq.com/pages/tactical-1000 +[1]: https://github.com/microchip-ung/arm-trusted-firmware/releases/latest +[2]: https://github.com/novarq/linux +[3]: ../microchip-ev23x71a/README.md +[5]: https://github.com/novarq/mcp2200py +[6]: https://github.com/novarq/tactical-1000/blob/main/docs/boot-modes.md +[7]: ../../../doc/netboot.md#installing-to-onboard-storage +[8]: ../../../doc/netboot.md#netboot-with-a-vendor-u-boot diff --git a/board/aarch64/novarq-tactical-1000/dts/Makefile b/board/aarch64/novarq-tactical-1000/dts/Makefile new file mode 100644 index 000000000..580b03306 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/dts/Makefile @@ -0,0 +1 @@ +dtb-y += microchip/lan9696-tactical-1000.dtb diff --git a/board/aarch64/novarq-tactical-1000/dts/microchip/infix.dtsi b/board/aarch64/novarq-tactical-1000/dts/microchip/infix.dtsi new file mode 100644 index 000000000..e39f876f8 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/dts/microchip/infix.dtsi @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Common Infix OS defaults + */ + +/ { + chosen { + infix { + /* Default admin user password: 'admin' */ + factory-password-hash = "$5$mI/zpOAqZYKLC2WU$i7iPzZiIjOjrBF3NyftS9CCq8dfYwHwrmUK097Jca9A"; + usb-ports = <&usb>; + usb-port-names = "USB"; + }; + }; +}; diff --git a/board/aarch64/novarq-tactical-1000/dts/microchip/lan9696-tactical-1000.dts b/board/aarch64/novarq-tactical-1000/dts/microchip/lan9696-tactical-1000.dts new file mode 100644 index 000000000..b1830dbff --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/dts/microchip/lan9696-tactical-1000.dts @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Infix OS device tree for Novarq Tactical 1000 (Laguna) + */ + +#include +#include "infix.dtsi" diff --git a/board/aarch64/novarq-tactical-1000/genimage.cfg.in b/board/aarch64/novarq-tactical-1000/genimage.cfg.in new file mode 100644 index 000000000..bd9818689 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/genimage.cfg.in @@ -0,0 +1,81 @@ +image cfg.ext4 { + empty = true + temporary = true + size = 128M + ext4 { + label = "cfg" + use-mke2fs = true + features = "uninit_bg" + extraargs = "-m 0 -i 4096" + } +} + +# The /var partition will be expanded automatically at first boot +# to use the full size of the eMMC. +image var.ext4 { + empty = true + temporary = true + size = 128M + ext4 { + label = "var" + use-mke2fs = true + features = "uninit_bg" + extraargs = "-m 0 -i 4096" + } +} + +image #IX_ID##VERSION#-tactical-1000-#TARGET#.img { + hdimage { + partition-table-type = "gpt" + gpt-no-backup = true + } + + # BL1, in ROM, looks up the FIP by GPT partition name, so these + # two must keep their names. Microchip's own layout gives them + # 128 MiB each, which a 1 MiB image does not need. + partition fip { + image = "fip.bin" + offset = 1M + size = 4M + } + + partition fip.bak { + image = "fip.bin" + size = 4M + } + + # Not used by Infix, its boot logic is stateless, but kept so a + # vendor U-Boot has somewhere of its own to save an environment. + partition Env { + size = 2M + } + + partition aux { + partition-uuid = D4EF35A0-0652-45A1-B3DE-D63339C82035 + image = "aux.ext4" + } + + partition primary { + partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4 + bootable = true + size = 250M + image = "rootfs.squashfs" + } + + partition secondary { + partition-type-uuid = 0FC63DAF-8483-4772-8E79-3D69D8477DE4 + bootable = true + size = 250M + image = "rootfs.squashfs" + } + + partition cfg { + partition-uuid = 7aa497f0-73b5-47e5-b2ab-8752d8a48105 + image = "cfg.ext4" + } + + partition var { + partition-uuid = 8046A06A-E45A-4A14-A6AD-6684704A393F + image = "var.ext4" + } +} diff --git a/board/aarch64/novarq-tactical-1000/novarq-board-details.webp b/board/aarch64/novarq-tactical-1000/novarq-board-details.webp new file mode 100644 index 000000000..eba62e970 Binary files /dev/null and b/board/aarch64/novarq-tactical-1000/novarq-board-details.webp differ diff --git a/board/aarch64/novarq-tactical-1000/novarq-tactical-1000.hash b/board/aarch64/novarq-tactical-1000/novarq-tactical-1000.hash new file mode 100644 index 000000000..2b1e74432 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/novarq-tactical-1000.hash @@ -0,0 +1,2 @@ +# Locally calculated +sha256 d48246c717b505cc11df95171f2fd548b389e1a463f1af4c68d0b69fe0d1009b LICENSE diff --git a/board/aarch64/novarq-tactical-1000/novarq-tactical-1000.mk b/board/aarch64/novarq-tactical-1000/novarq-tactical-1000.mk new file mode 100644 index 000000000..a15a6d010 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/novarq-tactical-1000.mk @@ -0,0 +1,47 @@ +# Novarq Tactical 1000 (Laguna) kernel configuration fixups +define NOVARQ_TACTICAL_1000_LINUX_CONFIG_FIXUPS + # LAN969x SoC + $(call KCONFIG_ENABLE_OPT,CONFIG_ARCH_LAN969X) + $(call KCONFIG_ENABLE_OPT,CONFIG_COMMON_CLK_LAN966X) + $(call KCONFIG_ENABLE_OPT,CONFIG_PINCTRL_OCELOT) + + # Serial console (FLEXCOM), ttyAT naming to match the bootloader + $(call KCONFIG_ENABLE_OPT,CONFIG_MFD_ATMEL_FLEXCOM) + $(call KCONFIG_ENABLE_OPT,CONFIG_SERIAL_ATMEL) + $(call KCONFIG_ENABLE_OPT,CONFIG_SERIAL_ATMEL_CONSOLE) + $(call KCONFIG_ENABLE_OPT,CONFIG_SERIAL_ATMEL_TTYAT) + + # Switch core, SerDes, and MDIO + $(call KCONFIG_ENABLE_OPT,CONFIG_SPARX5_SWITCH) + $(call KCONFIG_ENABLE_OPT,CONFIG_LAN969X_SWITCH) + $(call KCONFIG_ENABLE_OPT,CONFIG_PHY_SPARX5_SERDES) + $(call KCONFIG_ENABLE_OPT,CONFIG_MDIO_MSCC_MIIM) + $(call KCONFIG_SET_OPT,CONFIG_MICROSEMI_PHY,m) + + # eMMC + $(call KCONFIG_ENABLE_OPT,CONFIG_MMC_SDHCI_PLTFM) + $(call KCONFIG_ENABLE_OPT,CONFIG_MMC_SDHCI_OF_AT91) + + # I2C and DMA. The SFP cages, RTC, and temperature sensor all sit + # behind a GPIO controlled mux on i2c3. + $(call KCONFIG_ENABLE_OPT,CONFIG_I2C_AT91) + $(call KCONFIG_ENABLE_OPT,CONFIG_I2C_MUX_GPIO) + $(call KCONFIG_ENABLE_OPT,CONFIG_AT_XDMAC) + + # Watchdog and entropy + $(call KCONFIG_ENABLE_OPT,CONFIG_DW_WATCHDOG) + $(call KCONFIG_SET_OPT,CONFIG_HW_RANDOM_ATMEL,m) + + # Front panel reset button + $(call KCONFIG_ENABLE_OPT,CONFIG_KEYBOARD_GPIO) + + # RTC, temperature sensor, and case fan, none of which the EV23X71A + # has. The hwmon drivers are modules, as on the other boards that + # add a fan or sensor driver. + $(call KCONFIG_ENABLE_OPT,CONFIG_RTC_DRV_DS1307) + $(call KCONFIG_SET_OPT,CONFIG_SENSORS_LM75,m) + $(call KCONFIG_SET_OPT,CONFIG_SENSORS_GPIO_FAN,m) +endef + +$(eval $(ix-board)) +$(eval $(generic-package)) diff --git a/board/aarch64/novarq-tactical-1000/rootfs/usr/libexec/infix/prod/provision-tactical b/board/aarch64/novarq-tactical-1000/rootfs/usr/libexec/infix/prod/provision-tactical new file mode 100755 index 000000000..c5983fa79 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/rootfs/usr/libexec/infix/prod/provision-tactical @@ -0,0 +1,125 @@ +#!/bin/sh +# Carve Infix partitions out of the stock Tactical 1000 eMMC. +# +# STOPGAP. Board specific, and only until this board runs a bootloader +# of ours. When it does, prod/provision does the whole disk and this +# goes away. +# +# The board ships a GPT that describes 723 MiB of a 14.6 GiB eMMC, with +# the vendor OS in 'kernel' and 'rootfs' and no room for A/B slots, so +# the upgrade tests have nowhere to run. Extend the GPT to the whole +# device, drop the vendor pair, and lay down the Infix set after 'Env'. +# +# What it will not do is touch fip, fip.bak, or Env. BL1 lives in mask +# ROM and finds the FIP by GPT partition name, and this board has no +# strapping to reach NOR or the TF-A monitor, so a FIP it cannot find is +# a board nobody can recover. Every step that writes asks first. + +set -e + +disk=${1:-/dev/mmcblk0} +backup=${2:-/tmp/gpt-backup.bin} + +die() +{ + echo "$@" >&2 + exit 1 +} + +ask() +{ + printf "%s [y/N] " "$1" + read -r yn + case "$yn" in + [Yy]*) return 0 ;; + *) return 1 ;; + esac +} + +# Meant to run from init=/bin/sh, where none of these are mounted yet. +[ -e /proc/self ] || mount -t proc proc /proc +[ -d /sys/firmware ] || mount -t sysfs sys /sys +[ -w /tmp ] || mount -t tmpfs tmp /tmp + +# Refuse anywhere but the board this was written for, and only while the +# disk still looks like the one described above. +compat=$(tr '\0' '\n' /dev/null | head -1) +[ "$compat" = "novarq,tactical-1000" ] || die "Not a Novarq Tactical 1000, refusing" +[ -b "$disk" ] || die "$disk is not a block device" + +# With cfg or var mounted from here the kernel keeps the old table, and +# mkfs on the renumbered nodes would hit the wrong sectors. +grep -q "^$disk" /proc/mounts && die "$disk is in use, boot with init=/bin/sh and run this again" + +. /etc/partition-uuid + +for n in 1:fip 2:fip.bak 3:Env; do + num=${n%:*} + want=${n#*:} + have=$(sgdisk -i"$num" "$disk" | sed -n 's/^Partition name: .\(.*\).$/\1/p') + [ "$have" = "$want" ] || die "partition $num is '$have', expected '$want', refusing" +done + +echo "Disk $disk, current layout:" +sgdisk -p "$disk" | sed -n '/^Number/,$p' +echo + +sgdisk --backup="$backup" "$disk" >/dev/null +echo "GPT saved to $backup. Copy it off the board, this is a tmpfs." +echo + +ask "Extend the GPT to the whole $(sgdisk -p "$disk" | sed -n 's/^Disk .*, \(.*\)$/\1/p') device?" && + sgdisk -e "$disk" >/dev/null + +# 4 and 5 hold the vendor OS; 4 to 8 are ours when run a second time. +for n in 4 5 6 7 8; do + name=$(sgdisk -i"$n" "$disk" | sed -n 's/^Partition name: .\(.*\).$/\1/p') + [ -n "$name" ] || continue + ask "Delete partition $n '$name'?" && + sgdisk -d"$n" "$disk" >/dev/null +done + +# The vendor U-Boot keeps its environment at 0x10100000 and, the +# redundant copy, at 0x10300000: the end of a 2 MiB Env. Every other +# saveenv lands on the partition after it. Grow Env to cover both. +env_start=$(sgdisk -i3 "$disk" | sed -n 's/^First sector: \([0-9]*\).*/\1/p') +env_end=$(sgdisk -i3 "$disk" | sed -n 's/^Last sector: \([0-9]*\).*/\1/p') +if [ $((env_end - env_start + 1)) -lt 8192 ]; then + ask "Grow partition 3 'Env' to 4 MiB, for both copies of the vendor U-Boot environment?" && + sgdisk -d3 -n3:"$env_start":+4M -t3:8300 -c3:Env "$disk" >/dev/null +fi + +# Sized as prod/fdisk does, from what the disk actually holds. +total=$(( $(sgdisk -p "$disk" | sed -n 's/^Disk .*: \([0-9]*\) sectors.*/\1/p') / 2048 )) +if [ "$total" -ge 4096 ]; then imgsize=1024M; cfgsize=512M +elif [ "$total" -ge 2048 ]; then imgsize=512M; cfgsize=256M +elif [ "$total" -ge 1024 ]; then imgsize=256M; cfgsize=64M +else die "$disk is only ${total}M, at least 1024M is required" +fi + +if ask "Create aux, primary ${imgsize}, secondary ${imgsize}, cfg ${cfgsize}, and var?"; then + sgdisk -a 2048 \ + -n4::+8M -t4:8301 -c4:aux -u4:"${AUX_UUID}" \ + -n5::+"$imgsize" -t5:8300 -c5:primary -u5:"${PRIMARY_UUID}" \ + -n6::+"$imgsize" -t6:8300 -c6:secondary -u6:"${SECONDARY_UUID}" \ + -n7::+"$cfgsize" -t7:8302 -c7:cfg \ + -n8:: -t8:8310 -c8:var \ + "$disk" >/dev/null + partprobe "$disk" || true + + # Infix mounts by filesystem label, and mnt resizes var to the + # end of the disk on first boot unless aux says it is done. The + # partition already reaches the end, so say so, or the resize + # rewrites the table and reboots on every boot. + mkfs.ext4 -qF -L aux -m 0 -i 4096 -O ^metadata_csum,^metadata_csum_seed,uninit_bg "${disk}p4" + mkfs.ext4 -qF -L cfg -m 0 -i 4096 -O uninit_bg "${disk}p7" + mkfs.ext4 -qF -L var -m 0 -i 4096 -O uninit_bg "${disk}p8" + mnt=$(mktemp -d) + mount -t ext4 "${disk}p4" "$mnt" + echo 1 >"$mnt"/resized + umount "$mnt" + rmdir "$mnt" +fi + +echo +sgdisk -p "$disk" | sed -n '/^Number/,$p' diff --git a/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/default/hw-wait b/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/default/hw-wait new file mode 100644 index 000000000..490decc90 --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/default/hw-wait @@ -0,0 +1,3 @@ +# The LAN969x switch core attaches 29 PHYs, one at a time, taking a good +# half second each, so the default ten seconds is not enough. +HW_WAIT_TIMEOUT=60 diff --git a/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/iitod.json b/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/iitod.json new file mode 100644 index 000000000..b80a3b8bd --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/iitod.json @@ -0,0 +1,65 @@ +{ + "input": { + "path": { + "locate": { "path": "/run/led/locate" }, + + "startup": { "path": "/run/finit/cond/usr/startup-config-ok" }, + "fail-safe": { "path": "/run/finit/cond/usr/failure-config-ok" }, + "panic": { "path": "/run/finit/cond/usr/failure-config-error" } + } + }, + + "output": { + "led": { + "green:status": { + "rules": [ + { "if": "locate", "then": "@blink-1hz" }, + { "if": "panic", "then": "@blink-5hz" }, + { "if": "fail-safe", "then": "@blink-5hz" }, + { "if": "startup", "then": "@on" }, + { "if": "true", "then": "@blink-1hz" } + ] + }, + + "green:lan-0": { + "rules": [ + { "if": "true", "then": { "trigger": "netdev", "device_name": "e25", "link": 1, "rx": 1, "tx": 1 } } + ] + }, + "green:lan-1": { + "rules": [ + { "if": "true", "then": { "trigger": "netdev", "device_name": "e26", "link": 1, "rx": 1, "tx": 1 } } + ] + }, + "green:lan-2": { + "rules": [ + { "if": "true", "then": { "trigger": "netdev", "device_name": "e27", "link": 1, "rx": 1, "tx": 1 } } + ] + }, + "green:lan-3": { + "rules": [ + { "if": "true", "then": { "trigger": "netdev", "device_name": "e28", "link": 1, "rx": 1, "tx": 1 } } + ] + } + } + }, + + "aliases": { + "on": { + "brightness": true + }, + "off": { + "brightness": false + }, + "blink-1hz": { + "trigger": "timer", + "delay_on": 500, + "delay_off": 500 + }, + "blink-5hz": { + "trigger": "timer", + "delay_on": 100, + "delay_off": 100 + } + } +} diff --git a/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/udev/rules.d/90-tactical-1000-rename-ifaces.rules b/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/udev/rules.d/90-tactical-1000-rename-ifaces.rules new file mode 100644 index 000000000..9b1b5084d --- /dev/null +++ b/board/aarch64/novarq-tactical-1000/rootfs/usr/share/product/novarq,tactical-1000/etc/udev/rules.d/90-tactical-1000-rename-ifaces.rules @@ -0,0 +1,58 @@ +# Rename LAN969x switch ports by device tree node path. +# +# The sparx5 driver leaves naming to the kernel, which hands out eth0 +# and up in probe order. Match on OF_FULLNAME instead, which the port +# netdevs carry now that their of_node is populated, and give them the +# names on the front panel. +# +# The copper ports run backwards within each QSGMII quad, so port@0 is +# lan4 and port@3 is lan1. Numbering them by probe order, the way the +# EV23X71A rule does, would reverse every group of four without saying +# so. The SFP and management ports are in order. +# +# udev has no trailing comments, a '#' mid-line is a parse error, so the +# device tree label for each rule goes on the line above it. + + +# port@0..port@3: lan4, lan3, lan2, lan1 +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@0", NAME="e4" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@1", NAME="e3" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@2", NAME="e2" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@3", NAME="e1" + +# port@4..port@7: lan8, lan7, lan6, lan5 +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@4", NAME="e8" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@5", NAME="e7" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@6", NAME="e6" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@7", NAME="e5" + +# port@8..port@11: lan12, lan11, lan10, lan9 +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@8", NAME="e12" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@9", NAME="e11" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@10", NAME="e10" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@11", NAME="e9" + +# port@12..port@15: lan16, lan15, lan14, lan13 +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@12", NAME="e16" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@13", NAME="e15" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@14", NAME="e14" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@15", NAME="e13" + +# port@16..port@19: lan20, lan19, lan18, lan17 +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@16", NAME="e20" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@17", NAME="e19" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@18", NAME="e18" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@19", NAME="e17" + +# port@20..port@23: lan24, lan23, lan22, lan21 +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@20", NAME="e24" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@21", NAME="e23" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@22", NAME="e22" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@23", NAME="e21" + +# SFP cages and the management port, in order +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@24", NAME="e25" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@25", NAME="e26" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@26", NAME="e27" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@27", NAME="e28" +ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@29", NAME="mgmt" diff --git a/board/common/Config.in b/board/common/Config.in index e9d0576b3..f81d61451 100644 --- a/board/common/Config.in +++ b/board/common/Config.in @@ -2,6 +2,7 @@ menu "Images" source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-rootfs/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-aux/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-boot/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-qcow/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-gns3a/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/board/common/image/image-itb-rauc/Config.in" diff --git a/board/common/image/image-itb-boot/Config.in b/board/common/image/image-itb-boot/Config.in new file mode 100644 index 000000000..07fb9042a --- /dev/null +++ b/board/common/image/image-itb-boot/Config.in @@ -0,0 +1,57 @@ +menuconfig IX_IMAGE_ITB_BOOT + bool "boot.itb" + depends on IX_IMAGE_ITB_ROOTFS + select BR2_PACKAGE_HOST_UBOOT_TOOLS + help + Create a FIT holding the kernel, the root filesystem, and every + device tree in the build, with one configuration per device + tree, so that a single U-Boot 'bootm #' boots the + system on any board the build supports. + + Infix normally netboots from rootfs.itb alone: the bootloader + maps the SquashFS inside it and runs sysboot, which reads the + kernel and device tree from /boot. That require BLKMAP, SquashFS, + and sysboot, which vendor bootloaders rarely have enabled. This + image a way around that. + + Unsigned, unlike rootfs.itb: a bootloader that needs this image + cannot check a signature anyway, and the verified path stays + rootfs.itb by way of sysboot. + +config IX_IMAGE_ITB_BOOT_DTB + string "default device tree" + depends on IX_IMAGE_ITB_BOOT + default "microchip/lan9696-tactical-1000.dtb" if BR2_PACKAGE_NOVARQ_TACTICAL_1000 + help + The device tree behind the 'boot' configuration, which is the + one the boot script uses, as a path below /boot. Every other + device tree in the build gets a configuration named after it. + +config IX_IMAGE_ITB_BOOT_STRIP_KERNEL + bool "leave the kernel out of the rootfs" + depends on IX_IMAGE_ITB_BOOT + default y + help + The root filesystem carries a copy of the kernel in /boot for + the bootloaders that read it from there. This image already + has the kernel, so drop that copy, about 13 MiB compressed. + Costs an unsquash and resquash of the rootfs on every build, + and means the booted rootfs is not byte for byte the one in + rootfs.itb. + +config IX_IMAGE_ITB_BOOT_ADDR + string "image load address" + depends on IX_IMAGE_ITB_BOOT + default "0x70000000" if BR2_PACKAGE_NOVARQ_TACTICAL_1000 + help + Where the boot script fetches the image to. The only address + anywhere in this: the image itself carries none, so the same + image boots any board in the build, and this is what has to + suit the board the script is for. + +config IX_IMAGE_ITB_BOOT_CONSOLE + string "console" + depends on IX_IMAGE_ITB_BOOT + default "ttyAT0,115200" if BR2_PACKAGE_NOVARQ_TACTICAL_1000 + help + Console for the kernel command line in the boot script. diff --git a/board/common/image/image-itb-boot/generate.sh b/board/common/image/image-itb-boot/generate.sh new file mode 100755 index 000000000..9884a6cf5 --- /dev/null +++ b/board/common/image/image-itb-boot/generate.sh @@ -0,0 +1,174 @@ +#!/bin/sh +# Pack the kernel, every device tree, and the root filesystem into one FIT, +# so that a bootloader without BLKMAP, SquashFS, and sysboot can still boot +# Infix, with a single bootm and a single file to fetch. +# +# One configuration per device tree, named after it, so the same image +# boots any board in the build with bootm #. The 'boot' +# configuration is the board this build was configured for, and is what +# the boot script uses. +# +# Nothing in the image is tied to a memory map. The kernel is a +# compressed kernel_noload, so U-Boot finds room to unpack it and then +# moves it to wherever the board's DRAM begins; the ramdisk and device +# trees stay where they were fetched. The one address there is lives in +# the boot script, and says where to fetch to. +# +# The image is not signed. Nothing that needs it can check a signature, +# the verified path is rootfs.itb by way of sysboot, and mkimage 2024.04 +# reports an error signing a FIT of this shape that we have not run to +# ground. + +set -e + +kernel="${BINARIES_DIR}"/Image +squash="${BINARIES_DIR}"/rootfs.squashfs +itb="${BINARIES_DIR}"/boot.itb +scr="${BINARIES_DIR}"/boot.scr +work="${WORKDIR}" + +dtb="${TARGET_DIR}"/boot/"${DTB}" +if [ ! -f "${dtb}" ]; then + echo "NO SUCH DEVICE TREE: ${DTB}" >&2 + exit 1 +fi +default=$(basename "${DTB}" .dtb) + +# A third of the transfer is kernel, and it compresses three to one. +gzip -9 -n <"${kernel}" >"${work}"/Image.gz + +# Leave out the copy of the kernel the rootfs carries in /boot, it is +# already in the FIT. Under fakeroot so ownership survives the round +# trip, and with the same options the rootfs was built with. +if [ "${STRIP_KERNEL}" = "y" ]; then + bs=$(unsquashfs -s "${squash}" | sed -n 's/^Block size //p') + comp=$(unsquashfs -s "${squash}" | sed -n 's/^Compression //p') + rm -rf "${work}"/rootfs + fakeroot -- sh -c " + unsquashfs -n -d '${work}/rootfs' '${squash}' && + rm -f '${work}'/rootfs/boot/*Image && + mksquashfs '${work}/rootfs' '${work}/rootfs.squashfs' \ + -noappend -no-progress -processors $(nproc) \ + -b ${bs} -comp ${comp}" + squash="${work}"/rootfs.squashfs +fi + +# One fdt image and one configuration per device tree. The device trees +# go last in the image on purpose: U-Boot grows the selected tree in +# place to add the kernel command line and the ramdisk bounds, and after +# the ramdisk that growth only ever reaches another board's tree or the +# end of the image. +: >"${work}"/fdts.itsi +: >"${work}"/cfgs.itsi +for f in $(find "${TARGET_DIR}"/boot -name '*.dtb' | sort); do + name=$(basename "${f}" .dtb) + + cat >>"${work}"/fdts.itsi <>"${work}"/cfgs.itsi <"${work}"/boot.its <; + + images { + kernel { + description = "Linux"; + type = "kernel_noload"; + arch = "arm64"; + os = "linux"; + compression = "gzip"; + /* + * Ignored for a compressed kernel_noload, U-Boot + * allocates the decompression buffer and relocates the + * arm64 Image itself, but bootm_find_os() refuses a + * kernel node without them. + */ + load = <0>; + entry = <0>; + data = /incbin/("${work}/Image.gz"); + }; + + rootfs { + description = "rootfs"; + type = "ramdisk"; + arch = "arm64"; + os = "linux"; + compression = "none"; + data = /incbin/("${squash}"); + }; + +$(cat "${work}"/fdts.itsi) + }; + + configurations { + default = "boot"; + + boot { + description = "${ARTIFACT}, ${default}"; + kernel = "kernel"; + fdt = "fdt-${default}"; + ramdisk = "rootfs"; + }; + +$(cat "${work}"/cfgs.itsi) + }; +}; +EOF + +# External data, each blob on a 4 KiB boundary. No fixed offset for it, +# unlike rootfs.itb: with a configuration per board the header outgrows +# 4 KiB, and mkimage places the data after it either way. +mkimage -E -B 0x1000 -f "${work}"/boot.its "${itb}" + +# Boot script for handing out as the DHCP boot file, so a test system +# needs no typing at the prompt. The image sits next to this script on +# the server, so its name comes from ${bootfile} rather than being built +# in, and the script works wherever the two are served from. +# +# A board that cannot fetch its image resets and tries again rather than +# falling through to whatever bootcmd has left, which on a rack of test +# units is the vendor OS on eMMC. The pause keeps a server that is down +# from being hammered by the whole rack at once. +cat >"${work}"/boot.cmd </dev/null # Mark stage 1 complete, stage 2 will happen after reboot - echo "1" > /mnt/aux/resized.pending + if ! echo "1" > /mnt/aux/resized.pending; then + resize_err "cannot write resize marker to aux" + return 1 + fi sync - print_end 0 "Resizing /var partition on sdcard, done. Rebooting ..." + print_end 0 "Resizing /var partition, done. Rebooting ..." logger $opt -p user.notice -t "$nm" "Partition expanded, rebooting to resize filesystem" reboot -f diff --git a/configs/aarch64_defconfig b/configs/aarch64_defconfig index df537efb7..c697b866e 100644 --- a/configs/aarch64_defconfig +++ b/configs/aarch64_defconfig @@ -144,6 +144,7 @@ BR2_PACKAGE_FRIENDLYARM_NANOPI_R2S=y BR2_PACKAGE_MARVELL_CN9130_CRB=y BR2_PACKAGE_MARVELL_ESPRESSOBIN=y BR2_PACKAGE_MICROCHIP_EV23X71A=y +BR2_PACKAGE_NOVARQ_TACTICAL_1000=y BR2_PACKAGE_RASPBERRYPI_RPI64=y BR2_PACKAGE_STYX_DCP_SC_28P=y IX_VENDOR_HOME="https://www.kernelkit.org" diff --git a/configs/laguna_boot_defconfig b/configs/laguna_boot_defconfig index 1fcfb6640..f0e8aa2d3 100644 --- a/configs/laguna_boot_defconfig +++ b/configs/laguna_boot_defconfig @@ -30,8 +30,8 @@ BR2_TARGET_UBOOT_CUSTOM_GIT=y BR2_TARGET_UBOOT_CUSTOM_REPO_URL="https://github.com/microchip-ung/u-boot.git" BR2_TARGET_UBOOT_CUSTOM_REPO_VERSION="bsp-v2024.04-2026.06" BR2_TARGET_UBOOT_BOARD_DEFCONFIG="mchp_lan969x" -BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/microchip-ev23x71a/uboot/extras.config" -BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/microchip-ev23x71a/uboot/lan969x-env.dtsi" +BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/microchip-lan969x/uboot/extras.config" +BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/microchip-lan969x/uboot/lan969x-env.dtsi" BR2_TARGET_UBOOT_NEEDS_DTC=y BR2_PACKAGE_HOST_BMAP_TOOLS=y BR2_PACKAGE_HOST_GENIMAGE=y diff --git a/configs/tactical_boot_defconfig b/configs/tactical_boot_defconfig new file mode 100644 index 000000000..30c7d870c --- /dev/null +++ b/configs/tactical_boot_defconfig @@ -0,0 +1,44 @@ +BR2_aarch64=y +BR2_cortex_a53=y +BR2_TOOLCHAIN_EXTERNAL=y +BR2_TOOLCHAIN_EXTERNAL_BOOTLIN=y +BR2_DL_DIR="$(BR2_EXTERNAL_INFIX_PATH)/dl" +BR2_CCACHE=y +BR2_CCACHE_DIR="$(BR2_EXTERNAL_INFIX_PATH)/.ccache" +BR2_ENABLE_DEBUG=y +BR2_PACKAGE_OVERRIDE_FILE="$(BR2_EXTERNAL_INFIX_PATH)/local.mk" +BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_INFIX_PATH)/patches" +BR2_SSP_NONE=y +BR2_INIT_NONE=y +BR2_SYSTEM_BIN_SH_NONE=y +# BR2_PACKAGE_BUSYBOX is not set +# BR2_PACKAGE_IFUPDOWN_SCRIPTS is not set +# BR2_TARGET_ROOTFS_TAR is not set +BR2_PACKAGE_MBEDTLS_ATF=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_GIT=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_REPO_URL="https://github.com/microchip-ung/arm-trusted-firmware.git" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_CUSTOM_REPO_VERSION="0317e2ebb555d02ad694c5a7157b7db5b51a4ea4" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_PLATFORM="novarq_tactical_1000_v3" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_FIP=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_UBOOT_AS_BL33=y +BR2_TARGET_ARM_TRUSTED_FIRMWARE_ADDITIONAL_VARIABLES="KEY_ALG=ecdsa GENERATE_COT=1 LOG_LEVEL=30" +BR2_TARGET_ARM_TRUSTED_FIRMWARE_IMAGES="fip.bin" +BR2_TARGET_UBOOT=y +BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y +BR2_TARGET_UBOOT_CUSTOM_GIT=y +BR2_TARGET_UBOOT_CUSTOM_REPO_URL="https://github.com/microchip-ung/u-boot.git" +BR2_TARGET_UBOOT_CUSTOM_REPO_VERSION="bsp-v2024.04-2026.06" +BR2_TARGET_UBOOT_BOARD_DEFCONFIG="mchp_lan969x" +BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL_INFIX_PATH}/board/common/uboot/extras.config ${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/microchip-lan969x/uboot/extras.config" +BR2_TARGET_UBOOT_CUSTOM_DTS_PATH="${BR2_EXTERNAL_INFIX_PATH}/board/aarch64/microchip-lan969x/uboot/lan969x-env.dtsi" +BR2_TARGET_UBOOT_NEEDS_DTC=y +BR2_PACKAGE_HOST_BMAP_TOOLS=y +BR2_PACKAGE_HOST_GENIMAGE=y +BR2_PACKAGE_HOST_RAUC=y +BR2_PACKAGE_HOST_UBOOT_TOOLS=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SUPPORT=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FIT_SIGNATURE_SUPPORT=y +BR2_PACKAGE_HOST_UBOOT_TOOLS_FDT_ADD_PUBKEY=y +IX_TRUSTED_KEYS=y +IX_TRUSTED_KEYS_DEVELOPMENT=y diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index 14b55bb94..ce8ac9901 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -100,6 +100,9 @@ All notable changes to the project are documented in this file. release feed on a schedule and install a newer release to the inactive partition on its own, then either reboot to activate it or leave it staged for the next reboot +- Add Novarq Tactical 1000 (Laguna) support: LAN9696 switch with 24 GbE + copper ports, four SFP+ cages, and a management port. Infix bootloader + in eMMC, the OS netboots; no eMMC image of the OS yet ### Fixes diff --git a/doc/img/bitsign-badge-dark-mode.png b/doc/img/bitsign-badge-dark-mode.png new file mode 100644 index 000000000..d16750c29 Binary files /dev/null and b/doc/img/bitsign-badge-dark-mode.png differ diff --git a/doc/img/bitsign-badge-light-mode.png b/doc/img/bitsign-badge-light-mode.png new file mode 100644 index 000000000..205c5351e Binary files /dev/null and b/doc/img/bitsign-badge-light-mode.png differ diff --git a/doc/netboot.md b/doc/netboot.md index c225119af..bcd017419 100644 --- a/doc/netboot.md +++ b/doc/netboot.md @@ -183,6 +183,93 @@ header with `sgdisk -e`, grows the last partition to fill the medium, and resizes the filesystem, in two stages with a reboot in between. +## Netboot with a Vendor U-Boot + +The [Novarq Tactical 1000][tactical] ships with a vendor U-Boot that +netboots but has neither `blkmap`, SquashFS support, nor `sysboot`, so it +cannot boot a `rootfs.itb`. Until the Infix bootloader is installed, +`IX_IMAGE_ITB_BOOT` builds `boot.itb` for it: kernel, rootfs, and every +device tree in the build, one configuration each. `#boot` is the board +the build was configured for. + +``` +setenv autoload no +dhcp +setenv serverip + +setenv fdt_high 0xffffffffffffffff +setenv initrd_high 0xffffffffffffffff + +tftp 0x70000000 boot.itb +fdt addr 0x70000000 +fdt get value rdsz /images/rootfs data-size +setexpr rdkb ${rdsz} / 0x400 +setenv bootargs "console=ttyAT0,115200 root=/dev/ram0 ro brd.rd_size=0x${rdkb} rauc.slot=net loglevel=4 usbcore.authorized_default=2" + +bootm 0x70000000#boot +``` + +`brd.rd_size` is the SquashFS size in KiB. `fdt_high` and `initrd_high` +need all 64 bits set, the shipped environment has a 32-bit `fdt_high`. + +### Unattended + +The `boot.scr` script runs the same steps. With the TFTP server on another +host than the DHCP server, name it in `bootcmd`: + +``` +setenv boot_net 'setenv autoload no; dhcp; setenv serverip ; setenv bootfile boot.scr; tftp ${loadaddr} ${bootfile}; source ${loadaddr}' +setenv bootcmd 'run boot_net' +saveenv +``` + +With the DHCP server also serving TFTP, `serverip` and `bootfile` come with +the lease and `dhcp` fetches the script by itself: + +``` +setenv bootcmd 'dhcp; source ${loadaddr}' +saveenv +``` + +Here with dnsmasq: + +``` +enable-tftp +tftp-root=/srv/ftp +dhcp-boot=boot.scr +``` + +The image name is `${bootfile}` with `.scr` replaced by `.itb`. If the fetch +fails the board resets after five seconds. + +### Separate Artifacts + +For trying a kernel or device tree without rebuilding the image: + +``` +setenv autoload no +dhcp +setenv serverip + +tftp 0x60000000 Image +tftp 0x6f000000 lan9696-tactical-1000.dtb +tftp 0x78000000 rootfs.itb + +setenv fdt_high 0xffffffffffffffff +setenv initrd_high 0xffffffffffffffff +setexpr rdkb ${filesize} / 0x400 +setenv bootargs "console=ttyAT0,115200 root=/dev/ram0 ro brd.rd_size=0x${rdkb} rauc.slot=net loglevel=4 usbcore.authorized_default=2" +booti 0x60000000 0x78000000#verity 0x6f000000 +``` + +- fetch `rootfs.itb` last, `${filesize}` is the last transfer +- name the `verity` configuration, `MULTI_DTB_FIT` ignores `default` +- pass `rootfs.itb`, not the bare SquashFS, there is no `SUPPORT_RAW_INITRD` + +DRAM starts at `0x60000000`. + +[tactical]: https://github.com/kernelkit/infix/blob/main/board/aarch64/novarq-tactical-1000/README.md + ## U-Boot Commands U-Boot is a maze of environment variables, some with values, some wrap diff --git a/patches/arm-trusted-firmware/0317e2ebb555d02ad694c5a7157b7db5b51a4ea4/0001-microchip-lan969x-add-Novarq-Tactical-1000-v3.patch b/patches/arm-trusted-firmware/0317e2ebb555d02ad694c5a7157b7db5b51a4ea4/0001-microchip-lan969x-add-Novarq-Tactical-1000-v3.patch new file mode 100644 index 000000000..4046162bd --- /dev/null +++ b/patches/arm-trusted-firmware/0317e2ebb555d02ad694c5a7157b7db5b51a4ea4/0001-microchip-lan969x-add-Novarq-Tactical-1000-v3.patch @@ -0,0 +1,183 @@ +From 7953b711bf2828a03f0f3a550cd15b9d8f62a1c6 Mon Sep 17 00:00:00 2001 +From: Robert Marko +Date: Sun, 2 Nov 2025 16:57:45 +0100 +Subject: [PATCH] microchip: lan969x: add Novarq Tactical 1000 v3 +Organization: Wires + +Add support for Novarq Tactical 1000 v3 board as a separate platform since +it uses 2GB of RAM and requires a different RAM configuration. + +Signed-off-by: Robert Marko +--- + .../fdts/lan969x-tactical-1000-v3-ddr.dtsi | 90 +++++++++++++++++++ + .../novarq_tactical_1000_v3_tb_fw_config.dts | 30 +++++++ + .../novarq_tactical_1000_v3/platform.mk | 12 +++ + scripts/fwu/fwu.js | 2 +- + 4 files changed, 133 insertions(+), 1 deletion(-) + create mode 100644 plat/microchip/lan969x/fdts/lan969x-tactical-1000-v3-ddr.dtsi + create mode 100644 plat/microchip/lan969x/novarq_tactical_1000_v3/fdts/novarq_tactical_1000_v3_tb_fw_config.dts + create mode 100644 plat/microchip/lan969x/novarq_tactical_1000_v3/platform.mk + +diff --git a/plat/microchip/lan969x/fdts/lan969x-tactical-1000-v3-ddr.dtsi b/plat/microchip/lan969x/fdts/lan969x-tactical-1000-v3-ddr.dtsi +new file mode 100644 +index 000000000..9f2c3d7dc +--- /dev/null ++++ b/plat/microchip/lan969x/fdts/lan969x-tactical-1000-v3-ddr.dtsi +@@ -0,0 +1,90 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries. ++ * ++ */ ++ ++&ddr { ++ microchip,mem-name = "lan969x_tactical_1000_2gb 2025-11-02-13:03:23 7391dfb-dirty"; ++ microchip,mem-speed = <2400>; ++ microchip,mem-size = <0x80000000>; ++ microchip,mem-bus-width = <16>; ++ ++ microchip,main-reg = < ++ 0x00001091 /* crcparctl1 */ ++ 0x00000001 /* dbictl */ ++ 0x00000040 /* dfimisc */ ++ 0x0391820f /* dfitmg0 */ ++ 0x00040201 /* dfitmg1 */ ++ 0x40400003 /* dfiupd0 */ ++ 0x004000ff /* dfiupd1 */ ++ 0x003f7f40 /* ecccfg0 */ ++ 0x00020248 /* init0 */ ++ 0x00e80000 /* init1 */ ++ 0x0c340101 /* init3 */ ++ 0x10180200 /* init4 */ ++ 0x00110000 /* init5 */ ++ 0x00000402 /* init6 */ ++ 0x00000c19 /* init7 */ ++ 0x81040010 /* mstr */ ++ 0x00000000 /* pccfg */ ++ 0x00000000 /* pwrctl */ ++ 0x00210020 /* rfshctl0 */ ++ 0x00000000 /* rfshctl3 */ ++ >; ++ ++ microchip,timing-reg = < ++ 0x17131413 /* dramtmg0 */ ++ 0x0007051b /* dramtmg1 */ ++ 0x1a000010 /* dramtmg12 */ ++ 0x090b0512 /* dramtmg2 */ ++ 0x0000400c /* dramtmg3 */ ++ 0x08040409 /* dramtmg4 */ ++ 0x07070404 /* dramtmg5 */ ++ 0x07060c0b /* dramtmg8 */ ++ 0x0003040d /* dramtmg9 */ ++ 0x07000610 /* odtcfg */ ++ 0x0049014b /* rfshtmg */ ++ >; ++ ++ microchip,mapping-reg = < ++ 0x0000001f /* addrmap0 */ ++ 0x003f0909 /* addrmap1 */ ++ 0x00000700 /* addrmap2 */ ++ 0x00000000 /* addrmap3 */ ++ 0x00001f1f /* addrmap4 */ ++ 0x07070707 /* addrmap5 */ ++ 0x07070707 /* addrmap6 */ ++ 0x00000f07 /* addrmap7 */ ++ 0x00003f01 /* addrmap8 */ ++ >; ++ ++ microchip,phy-reg = < ++ 0x0000040c /* dcr */ ++ 0x0064401b /* dsgcr */ ++ 0x8000b0cf /* dtcr0 */ ++ 0x00010a37 /* dtcr1 */ ++ 0x00c01884 /* dxccr */ ++ 0x000010ba /* pgcr2 */ ++ 0x00000000 /* schcr1 */ ++ 0x00079900 /* zq0pr */ ++ 0x10077900 /* zq1pr */ ++ 0x00000000 /* zq2pr */ ++ 0x00058f00 /* zqcr */ ++ >; ++ ++ microchip,phy_timing-reg = < ++ 0x0827100a /* dtpr0 */ ++ 0x28250018 /* dtpr1 */ ++ 0x000702a1 /* dtpr2 */ ++ 0x03000101 /* dtpr3 */ ++ 0x02950808 /* dtpr4 */ ++ 0x00361009 /* dtpr5 */ ++ 0x4ae25710 /* ptr0 */ ++ 0x74f4950e /* ptr1 */ ++ 0x00083def /* ptr2 */ ++ 0x2a192000 /* ptr3 */ ++ 0x1003a000 /* ptr4 */ ++ >; ++ ++}; +diff --git a/plat/microchip/lan969x/novarq_tactical_1000_v3/fdts/novarq_tactical_1000_v3_tb_fw_config.dts b/plat/microchip/lan969x/novarq_tactical_1000_v3/fdts/novarq_tactical_1000_v3_tb_fw_config.dts +new file mode 100644 +index 000000000..3a232166f +--- /dev/null ++++ b/plat/microchip/lan969x/novarq_tactical_1000_v3/fdts/novarq_tactical_1000_v3_tb_fw_config.dts +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2022, Microchip Technology Inc. and its subsidiaries. ++ * ++ * SPDX-License-Identifier: BSD-3-Clause ++ */ ++ ++/dts-v1/; ++ ++#include "lan969x.dtsi" ++#include "lan969x-tactical-1000-v3-ddr.dtsi" ++ ++&emmc_clk { ++ clock-frequency = <100000000>; ++}; ++ ++&sdmmc0 { ++ status = "okay"; ++ bus-width = <8>; ++}; ++ ++&qspi0 { ++ status = "okay"; ++ spi-flash@0 { ++ compatible = "jedec,spi-nor"; ++ reg = <0>; ++ spi-max-frequency = <100000000>; ++ spi-tx-bus-width = <4>; ++ spi-rx-bus-width = <4>; ++ }; ++}; +diff --git a/plat/microchip/lan969x/novarq_tactical_1000_v3/platform.mk b/plat/microchip/lan969x/novarq_tactical_1000_v3/platform.mk +new file mode 100644 +index 000000000..2f679816e +--- /dev/null ++++ b/plat/microchip/lan969x/novarq_tactical_1000_v3/platform.mk +@@ -0,0 +1,12 @@ ++# ++# Copyright (c) 2021, Microchip Technology Inc. and its subsidiaries. ++# ++# SPDX-License-Identifier: BSD-3-Clause ++# ++ ++include plat/microchip/lan969x/common/common.mk ++ ++# This is used in lan969x code ++$(eval $(call add_define,LAN969X_ASIC)) ++# This is used in common drivers ++$(eval $(call add_define,LAN966X_ASIC)) +diff --git a/scripts/fwu/fwu.js b/scripts/fwu/fwu.js +index ac0ba409e..0b9fda400 100644 +--- a/scripts/fwu/fwu.js ++++ b/scripts/fwu/fwu.js +@@ -91,7 +91,7 @@ const platforms = [ + "ddr_diag": ddr_diag_regs_lan969x, + "ddr_regs": ddr_regs_lan969x, + "ddr_speed": lan969x_speeds, +- "bl2u_compat": ["lan969x_a0", "lan969x_svb"], ++ "bl2u_compat": ["lan969x_a0", "lan969x_svb", "novarq_tactical_1000_v3"], + }, + ]; + diff --git a/src/confd/src/main.c b/src/confd/src/main.c index 1d0e9f137..fa390f770 100644 --- a/src/confd/src/main.c +++ b/src/confd/src/main.c @@ -59,9 +59,8 @@ static void set_finit_cond(const char *cond) { char path[128]; - snprintf(path, sizeof(path), "/run/finit/cond/usr/%s", cond); - + snprintf(path, sizeof(path), "/run/finit/cond/usr/%s", cond); if (symlink("/run/finit/cond/reconf", path) && errno != EEXIST) WARN("Failed to set finit condition %s: %m", path); } @@ -624,8 +623,11 @@ static int bootstrap_config(sr_conn_ctx_t *conn, sr_session_ctx_t *sess, } /* Export running → startup file */ - if (export_running(sess, startup_path, timeout_ms)) + if (export_running(sess, startup_path, timeout_ms)) { WARN("Failed to export running to %s", startup_path); + set_finit_cond("startup-config-error"); + } else + set_finit_cond("startup-config-ok"); return 0; } diff --git a/utils/mkimage.sh b/utils/mkimage.sh index 5ef7153c5..7738e4277 100755 --- a/utils/mkimage.sh +++ b/utils/mkimage.sh @@ -216,6 +216,9 @@ get_bootloader_name() echo "sama7g54_ek_sd_boot" fi ;; + novarq-tactical-1000) + echo "tactical_boot" + ;; *) err "Unknown bootloader for board: $board" return 1