diff --git a/board/aarch64/Config.in b/board/aarch64/Config.in
index 8e0974310..dc4fbce90 100644
--- a/board/aarch64/Config.in
+++ b/board/aarch64/Config.in
@@ -9,6 +9,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/freescale-imx8mp-evk/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/friendlyarm-nanopi-r2s/Config.in"
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/raspberrypi-rpi64/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/board/aarch64/styx-dcp-sc-28p/Config.in"
diff --git a/board/aarch64/microchip-ev23x71a/Config.in b/board/aarch64/microchip-ev23x71a/Config.in
new file mode 100644
index 000000000..dc3e8254d
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/Config.in
@@ -0,0 +1,7 @@
+config BR2_PACKAGE_MICROCHIP_EV23X71A
+ bool "Microchip EV23X71A (Laguna)"
+ depends on BR2_aarch64
+ help
+ Support for the Microchip EV23X71A evaluation board, 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/microchip-ev23x71a/EVB-LAN9696-24port.png b/board/aarch64/microchip-ev23x71a/EVB-LAN9696-24port.png
new file mode 100644
index 000000000..bb71baaa6
Binary files /dev/null and b/board/aarch64/microchip-ev23x71a/EVB-LAN9696-24port.png differ
diff --git a/board/aarch64/microchip-ev23x71a/LICENSE b/board/aarch64/microchip-ev23x71a/LICENSE
new file mode 100644
index 000000000..8cdb30a3a
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/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/microchip-ev23x71a/README.md b/board/aarch64/microchip-ev23x71a/README.md
new file mode 100644
index 000000000..195d5534c
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/README.md
@@ -0,0 +1,463 @@
+# Microchip EV23X71A (Laguna)
+
+
+
+Evaluation board for the Microchip LAN969x (Laguna) family, a TSN capable
+28-port switch with a Cortex-A53 CPU core.
+
+| **Property** | **Value** |
+|--------------|---------------------------------------------|
+| SoC | LAN969x, ARM Cortex-A53 single-core @ 1 GHz |
+| Memory | 1 GiB DDR4 x16 RAM |
+| Storage | 4 GiB eMMC on SDMMC0, 2 MiB QSPI NOR |
+| Switch | 24 x GbE copper, 4 x SFP+, 1 x RGMII NPI |
+| Console | `ttyAT0`, 115200 8N1 |
+
+## Status
+
+Supported:
+
+- switch core and SerDes, all ports
+- eMMC, I2C (including the SFP mux), SPI, USB host
+- watchdog, temperature sensor, SGPIO LEDs
+- our own boot chain, from BL2 to a slot booted out of the eMMC, with
+ the environment held in the authenticated control device tree
+
+Not yet done:
+
+- TSN queueing. PSFP and time aware shaping need `NET_SCH_TAPRIO`,
+ `NET_ACT_GATE`, `NET_SCH_ETS`, and `NET_SCH_CBS`, all currently off
+- HSR/PRP offload, see above
+- MAC addresses. With no environment in flash the board falls back to
+ `lan969x_otp_get_mac()`, which derives 30 addresses for this board
+ from OTP, but the OTP address block is blank on our sample, so
+ interfaces come up random. Provisioning it is a one way operation,
+ `boot-monitor.rb --otp-data :` in monitor mode
+
+## Boot Chain
+
+The board ships with Microchip's boot chain in the eMMC `fip` and `fip.bak`
+partitions. The Firmware Image Package (FIP) contains all the components of
+ARM Trusted Firmware (TF-A) required to boot the system: BL2, BL31, BL33
+(U-Boot), any certificates and the optional BL32 (OP-TEE).
+
+The first-stage bootloader (BL1) in mask ROM walks through the FIP sources in
+turn, `fip`, then `fip.bak`, then a raw offset, moving on whenever an image
+fails to load or authenticate. Leaving a working FIP in `fip.bak` is thus a
+way back from a bad one.
+
+When a valid FIP is found and loaded into SRAM, BL1 jumps to BL2 which brings
+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.
+
+## Boot Mode Strapping
+
+The DIP switch marked *VCore Configuration Strapping* tells BL1 where to
+look for the FIP:
+
+| **VCORE[3:0]** | **Mode** | **Description** |
+|----------------|--------------|------------------------------------------------|
+| 0000 | eMMC FC0 | Boot from eMMC, boot trace on Flexcom0, 115200 |
+| 0001 | QSPI0 FC0 | Boot from NOR, boot trace on Flexcom0, 115200 |
+| 0011 | eMMC | Boot from eMMC |
+| 0100 | QSPI0 | Boot from NOR |
+| 1000 | QSPI0 FC0 HS | Boot from NOR, boot trace on Flexcom0, 921600 |
+| 1010 | TF-A FC0 | TF-A monitor on Flexcom0, 115200 |
+| 1011 | TF-A FC0 HS | TF-A monitor on Flexcom0, 921600 |
+| 1111 | SPI client | QSPI0 as SPI client, internal CPU disabled |
+
+Only the "Flexcom0" modes give the firmware a console. For the rest
+`lan969x_console_init()` selects none, so BL1, BL2, and BL31 print nothing and
+the first line on the wire is U-Boot's banner, which brings up its own
+console.
+
+That is also the only way to quiet the firmware. Our `LOG_LEVEL` covers BL2
+and BL31, but BL1 lives in mask ROM and traces at the level it was built with
+in 2023, so its `INFO:` lines cannot be turned off from here. Use 0000 while
+working on the boot chain, when that trace is what you came for, and 0011 for
+a quiet boot.
+
+### Debricking
+
+> [!TIP]
+> Keep a released vendor FIP in the NOR flash while working with U-Boot or any
+> other part of the FIP, so that 0001 always reaches a prompt no matter what
+> the eMMC holds. From a running U-Boot:
+>
+> ```
+> setenv autoboot off
+> dhcp
+> tftpboot ${loadaddr} lan969x_a0-release.fip
+> run nor_fip_upd
+> ```
+>
+> Even with both flashes unusable the board is recoverable. Strap 1010 leaves
+> BL1 in TF-A monitor mode, which [`fwu-lan969x_a0-release.html`][4] drives
+> over USB, writing the GPT and FIP to either flash from blank.
+
+## Bootloader
+
+Infix keeps its own U-Boot from Microchip's tree, which carries the LAN969x
+support, together with Microchip's Trusted Firmware:
+
+```bash
+make laguna_boot_defconfig
+make
+```
+
+The build produces one `fip.bin`, with BL2, BL31, and U-Boot as BL33 in it.
+Microchip package BL2 inside the FIP, unlike MediaTek where it lives in a
+partition of its own, so there is a single artifact to place. BL1 in ROM
+authenticates BL2, so the FIP always carries certificates, which is why the
+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
+BL1 authenticates BL2: without it the FIP has no certificates and the ROM
+refuses to boot it.
+
+Trusted Firmware is pinned to a commit rather than a tag, since no tag carries
+the fix for `ERR-LAN969X-001`. The boot ROM's ECDSA verifier mishandles any
+P-256 value whose most significant byte is zero, which happens for about one
+in 256 random coordinates or signature scalars, so roughly one build in a
+hundred produced a FIP the ROM rejected:
+
+```
+INFO: Authenticating image id=6 (sign)
+INFO: Authenticated image id=6 (sign) = 12
+NOTICE: Image(6) load error: 12
+```
+
+`cert_create` now screens the values it generates and retries, for details,
+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:
+
+```bash
+make laguna_boot_defconfig O=x-boot-laguna && make O=x-boot-laguna
+make aarch64_defconfig && make
+utils/mkimage.sh -b x-boot-laguna -r output -t emmc microchip-ev23x71a
+```
+
+Install the FIP first, copy `x-boot-laguna/images/fip.bin` to your TFTP server
+directory. Strap board to 0001, stop autoboot, and write the FIP to the eMMC:
+
+```
+setenv fip_fw fip.bin
+run mmc_fip0_dlup
+```
+
+Strap back to 0000 and power cycle. With no `aux` partition to find, the new
+U-Boot reports `NO BOOTABLE MEDIA FOUND` and netboots, which is how the rest
+of the install happens: see [Installing to Onboard Storage][2] for addressing
+the netbooted system and streaming the image onto the eMMC.
+
+The first boot after installing grows `var` to fill the eMMC and reboots once
+by itself. The kernel complains that the backup GPT is not at the end of the
+disk until that has happened, which is expected.
+
+### Updating the FIP
+
+Once Infix runs from the eMMC the bootloader is just another partition,
+`fip` is `mmcblk0p1` and `fip.bak` is `mmcblk0p2`, and nothing mounts
+either of them:
+
+```bash
+scp x-boot-laguna/images/fip.bin admin@board:/tmp
+ssh admin@board.local 'sudo dd if=/tmp/fip.bin of=/dev/mmcblk0p1 conv=fsync'
+```
+
+Reboot and check the BL2 build date in the banner. Only then mirror it
+into `fip.bak`, so that BL1's fallback stays one known good step behind
+whatever is being tried in `fip`:
+
+```bash
+ssh admin@board.local 'sudo dd if=/tmp/fip.bin of=/dev/mmcblk0p2 conv=fsync'
+```
+
+The same from the U-Boot prompt, which resolves the partition by name:
+
+```
+setenv autoboot off
+dhcp
+tftpboot ${loadaddr} fip.bin
+setexpr blkcnt ${filesize} + 0x1ff
+setexpr blkcnt ${blkcnt} / 0x200
+part start mmc 0 fip fipstart
+mmc write ${loadaddr} ${fipstart} ${blkcnt}
+```
+
+The `mmc_fip0_dlup` helper used during bring-up belongs to the vendor
+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
+boots it, see the [netboot HowTo][1].
+
+The recipe below is for boards still running the vendor U-Boot, before our FIP
+has been written. Save it as `netboot.sh`, or paste the lines at the prompt
+one at a time:
+
+```
+# Run: mkimage -T script -d netboot.sh netboot.scr
+setenv fdt_addr_r 0x68000000
+setenv kernel_addr_r 0x62000000
+setenv ramdisk_addr_r 0x70000000
+
+setenv srvpath ix/ev23x71a
+tftp ${fdt_addr_r} ${srvpath}/lan9696-ev23x71a.dtb
+tftp ${kernel_addr_r} ${srvpath}/Image
+tftp ${ramdisk_addr_r} ${srvpath}/rootfs.itb
+
+setexpr rdkbsize ${filesize} / 0x400
+setenv bootargs "console=ttyAT0,115200 root=/dev/ram0 brd.rd_size=0x${rdkbsize} rauc.slot=net loglevel=4 usbcore.authorized_default=2"
+booti ${kernel_addr_r} ${ramdisk_addr_r}#verity ${fdt_addr_r}
+```
+
+The addresses keep kernel, device tree, and RAM disk clear of each other in
+the 896 MiB starting at 0x60000000. `setexpr` stores bare hex, hence the `0x`
+in front of `${rdkbsize}`. `rauc.slot=net` marks the system as network booted
+rather than running from a slot, the same variable `ixbootslot.sh` sets for a
+real one.
+
+Two details are peculiar to the U-Boot that ships with the board:
+
+- Pass `rootfs.itb`, not the bare `rootfs.squashfs`. It is built without
+ `SUPPORT_RAW_INITRD`, so the `addr:size` form of the ramdisk argument is
+ never parsed, and anything that is neither a FIT nor a legacy uImage is
+ rejected with `Wrong Ramdisk Image Format`.
+
+- Name the `verity` configuration. `mchp_lan969x_defconfig` sets
+ `MULTI_DTB_FIT`, since U-Boot carries a device tree for each LAN969x board,
+ and in 2023.04 that makes `fit_conf_get_node()` pick a configuration by
+ matching compatible strings, never falling back to the `default` property.
+ Our ITB carries a ramdisk and no device tree, so there is nothing to match,
+ and it fails with `Could not find configuration node`.
+
+The ITB is signed with the Infix development key, which that U-Boot knows
+nothing about, so it prints `-` for the signature and loads the ramdisk
+anyway; only keys marked required in the bootloader's control device tree can
+fail an image.
+
+To boot without typing anything, wrap the script and hand it out over DHCP as
+the boot file:
+
+```bash
+mkimage -T script -C none -n netboot -d netboot.sh netboot.scr
+```
+
+The vendor U-Boot will not source it by itself, its `bootcmd` runs `mmc_boot`,
+so point it at the script once:
+
+```
+setenv autoboot off
+setenv bootcmd 'dhcp; source ${loadaddr}'
+saveenv
+```
+
+`dhcp` fetches the boot file to `${loadaddr}`, 0x64000000 in the shipped
+environment and clear of the three addresses above. `saveenv` writes the
+`Env` partition in the eMMC; the original value is `run mmc_boot`. With
+a relay on the board's supply, a power cycle then becomes the whole
+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:
+
+```
+devmem 0xe2010000 32
+```
+
+Bits 27:12 hold the part, 31:28 the revision. Which part it is decides what
+the driver offers: `sparx5_init_features()` enables PTP and PSFP for the TSN,
+RED, and VAO variants only, and leaves a plain LAN9694, LAN9696, or LAN9698
+without either.
+
+| **ID** | **Part** | **Family** | **PTP, PSFP** |
+|----------|--------------|-------------|---------------|
+| `0x9694` | LAN9694 | lan969x-40 | no |
+| `0x9691` | LAN9691VAO | lan969x-40 | yes |
+| `0x9695` | LAN9694TSN | lan969x-40 | yes |
+| `0x969a` | LAN9694RED | lan969x-40 | yes |
+| `0x9696` | LAN9696 | lan969x-60 | no |
+| `0x9692` | LAN9692VAO | lan969x-65 | yes |
+| `0x9697` | LAN9696TSN | lan969x-60 | yes |
+| `0x969b` | LAN9696RED | lan969x-60 | yes |
+| `0x9698` | LAN9698 | lan969x-100 | no |
+| `0x9693` | LAN9693VAO | lan969x-100 | yes |
+| `0x9699` | LAN9698TSN | lan969x-100 | yes |
+| `0x969c` | LAN9698RED | lan969x-100 | yes |
+| `0x7546` | SparX-5-64 | Enterprise | no |
+| `0x7549` | SparX-5-90 | Enterprise | no |
+| `0x7552` | SparX-5-128 | Enterprise | no |
+| `0x7556` | SparX-5-160 | Enterprise | no |
+| `0x7558` | SparX-5-200 | Enterprise | no |
+| `0x0546` | SparX-5-64i | Industrial | yes |
+| `0x0549` | SparX-5-90i | Industrial | yes |
+| `0x0552` | SparX-5-128i | Industrial | yes |
+| `0x0556` | SparX-5-160i | Industrial | yes |
+| `0x0558` | SparX-5-200i | Industrial | yes |
+
+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
+```
+
+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:
+
+| **Device tree** | **Interface** | **Port** |
+|--------------------|----------------|---------------------|
+| `port@0..port@23` | `e1` .. `e24` | 1G copper, QSGMII |
+| `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.
+
+## LEDs
+
+The board has 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
+```
+
+The common `/etc/iitod.json` drives `green:boot` and `green:status` from
+inputs this board has no LEDs for, so the product ships its own. It blinks
+`green:status` at 1 Hz while booting, holds it on once `run/startup/success`
+is asserted, and flashes 5 Hz for a fail-safe boot or a panic. The green SFP
+LEDs get the kernel netdev trigger, bound to `e25` through `e28`, for link and
+activity.
+
+The yellow ones are left alone for now. `iitod` writes any key in a rule's
+`then` object straight to the LED's sysfs directory, so they can be given a
+trigger later without touching any code.
+
+## Debug and Analysis
+
+`DEBUG_FS` is on in the aarch64 configuration, and the driver puts its VCAP
+state there:
+
+```
+/sys/kernel/debug/sparx5/vcaps/
+├── is0_0, is0_1, is0_2 decoded rules, CLM-0 through CLM-2
+├── is2_0, is2_1, es0_0, es2_0 the remaining VCAP instances
+├── raw_is0_0, raw_is2_0, ... raw entry dump of each of the above
+└── eth0 .. eth28 per port key set selection
+```
+
+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.
+
+Every port netdev links to its device tree node, so they can be mapped back to
+switch ports whatever order they probed in:
+
+```bash
+for d in /sys/class/net/eth*; do
+ echo "$(basename $d) -> $(readlink $d/of_node)"
+done
+```
+
+Counters come from `ethtool`, which implements the structured groups as
+well as the flat set:
+
+```bash
+ethtool -S eth0 # flat, the full sparx5 counter set
+ethtool -S eth0 --all-groups # mac, phy, ctrl, and rmon groups
+ethtool -T eth0 # timestamping, empty unless the part has PTP
+ethtool -m eth24 # SFP module EEPROM, read through the i2c mux
+```
+
+There is no `ethtool -p`, the driver implements no `set_phys_id`, and no
+devlink support at all, so do not go looking for `devlink dev info`.
+
+PHY registers over the GCB MDIO controller, with `mdio` from mdio-tools
+(the `mdio-netlink` module is built for this kernel):
+
+```bash
+# mdio # list buses
+# mdio e20101a8.mdio-mii phy 0x03 # the management port PHY, a LAN8841
+BMCR(0x00): 0x1040
+ flags: -reset -loopback +aneg-enable -power-down -isolate -aneg-restart
+ -collision-test
+ speed: 1000-half
+
+BMSR(0x01): 0x796d
+ capabilities: -100-t4 +100-tx-f +100-tx-h +10-t-f +10-t-h -100-t2-f -100-t2-h
+ flags: +ext-status +aneg-complete -remote-fault +aneg-capable +link
+ -jabber +ext-register
+
+ID(0x02/0x03): 0x00221652
+
+ESTATUS(0x0F): 0x2000
+ capabilities: -1000-x-f -1000-x-h +1000-t-f -1000-t-h
+
+# mdio e20101a8.mdio-mii phy 0x04 raw 0x1
+0x7949
+```
+
+The bus name is the one dmesg prints for each port, `PHY
+[e20101a8.mdio-mii:0d]`, and the INDY quads answer at 0x04 through 0x1b.
+Scanning the whole bus, `mdio e20101a8.mdio-mii` with no object, instead
+fails with `Unable to read status (-5)`: `mscc_miim_read()` returns
+`-EIO` when the controller flags a read error, which is what an address
+with no PHY behind it does, and the scan gives up there. Address a
+specific PHY instead. Loading `mdio-netlink` needs root, so run the
+tool under `sudo`.
+
+Sensors and LEDs are plain class devices, `/sys/class/hwmon/*/temp1_input`
+for the die temperature and `/sys/class/leds/` for the status LED and the
+SGPIO driven port LEDs.
+
+For the eMMC, the mmc core exposes the negotiated bus parameters and the
+card's own health estimate:
+
+```bash
+cat /sys/kernel/debug/mmc0/ios # timing, bus width, clock
+cat /sys/class/mmc_host/mmc0/mmc0:0001/life_time # EXT_CSD wear estimate
+cat /sys/class/mmc_host/mmc0/mmc0:0001/pre_eol_info # 0x01 normal, 0x03 urgent
+```
+
+[0]: https://microchip-ung.github.io/bsp-doc/
+[1]: https://www.kernelkit.org/infix/latest/netboot/
+[2]: https://www.kernelkit.org/infix/latest/netboot/#installing-to-onboard-storage
+[4]: https://github.com/microchip-ung/arm-trusted-firmware/releases/latest
+[5]: https://github.com/microchip-ung/arm-trusted-firmware
diff --git a/board/aarch64/microchip-ev23x71a/dts/Makefile b/board/aarch64/microchip-ev23x71a/dts/Makefile
new file mode 100644
index 000000000..4190893a4
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/dts/Makefile
@@ -0,0 +1 @@
+dtb-y += microchip/lan9696-ev23x71a.dtb
diff --git a/board/aarch64/microchip-ev23x71a/dts/microchip/infix.dtsi b/board/aarch64/microchip-ev23x71a/dts/microchip/infix.dtsi
new file mode 100644
index 000000000..e39f876f8
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/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/microchip-ev23x71a/dts/microchip/lan9696-ev23x71a.dts b/board/aarch64/microchip-ev23x71a/dts/microchip/lan9696-ev23x71a.dts
new file mode 100644
index 000000000..105ad2317
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/dts/microchip/lan9696-ev23x71a.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Infix OS device tree for Microchip EV23X71A (Laguna)
+ */
+
+#include
+#include "infix.dtsi"
diff --git a/board/aarch64/microchip-ev23x71a/genimage.cfg.in b/board/aarch64/microchip-ev23x71a/genimage.cfg.in
new file mode 100644
index 000000000..b42557d42
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/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#-ev23x71a-#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/microchip-ev23x71a/microchip-ev23x71a.hash b/board/aarch64/microchip-ev23x71a/microchip-ev23x71a.hash
new file mode 100644
index 000000000..2b1e74432
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/microchip-ev23x71a.hash
@@ -0,0 +1,2 @@
+# Locally calculated
+sha256 d48246c717b505cc11df95171f2fd548b389e1a463f1af4c68d0b69fe0d1009b LICENSE
diff --git a/board/aarch64/microchip-ev23x71a/microchip-ev23x71a.mk b/board/aarch64/microchip-ev23x71a/microchip-ev23x71a.mk
new file mode 100644
index 000000000..9d2267b5d
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/microchip-ev23x71a.mk
@@ -0,0 +1,36 @@
+# Microchip EV23X71A (Laguna) kernel configuration fixups
+define MICROCHIP_EV23X71A_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, SPI, and DMA
+ $(call KCONFIG_ENABLE_OPT,CONFIG_I2C_AT91)
+ $(call KCONFIG_ENABLE_OPT,CONFIG_SPI_ATMEL)
+ $(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)
+endef
+
+$(eval $(ix-board))
+$(eval $(generic-package))
diff --git a/board/aarch64/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/etc/default/hw-wait b/board/aarch64/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/etc/default/hw-wait
new file mode 100644
index 000000000..490decc90
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/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/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/etc/iitod.json b/board/aarch64/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/etc/iitod.json
new file mode 100644
index 000000000..b80a3b8bd
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/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/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/etc/udev/rules.d/90-ev23x71a-rename-ifaces.rules b/board/aarch64/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/etc/udev/rules.d/90-ev23x71a-rename-ifaces.rules
new file mode 100644
index 000000000..db0d6c834
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/rootfs/usr/share/product/microchip,ev23x71a/etc/udev/rules.d/90-ev23x71a-rename-ifaces.rules
@@ -0,0 +1,41 @@
+# 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.
+#
+# EV23X71A port layout (switch@e00c0000, ethernet-ports):
+# port@0 .. port@23 1G copper over QSGMII, e1 .. e24
+# port@24 .. port@27 10G SFP+, e25 .. e28
+# port@29 1G RGMII management, e29, as in the Microchip docs
+
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@0", NAME="e1"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@1", NAME="e2"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@2", NAME="e3"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@3", NAME="e4"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@4", NAME="e5"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@5", NAME="e6"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@6", NAME="e7"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@7", NAME="e8"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@8", NAME="e9"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@9", NAME="e10"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@10", NAME="e11"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@11", NAME="e12"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@12", NAME="e13"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@13", NAME="e14"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@14", NAME="e15"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@15", NAME="e16"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@16", NAME="e17"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@17", NAME="e18"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@18", NAME="e19"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@19", NAME="e20"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@20", NAME="e21"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@21", NAME="e22"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@22", NAME="e23"
+ACTION=="add", SUBSYSTEM=="net", ENV{OF_FULLNAME}=="*/switch@e00c0000/ethernet-ports/port@23", NAME="e24"
+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="e29"
diff --git a/board/aarch64/microchip-ev23x71a/uboot/extras.config b/board/aarch64/microchip-ev23x71a/uboot/extras.config
new file mode 100644
index 000000000..db23bdc15
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/uboot/extras.config
@@ -0,0 +1,28 @@
+# 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.
+CONFIG_DEFAULT_DEVICE_TREE="lan969x_ev23x71a"
+CONFIG_OF_LIST="lan969x_ev23x71a"
+# CONFIG_MULTI_DTB_FIT is not set
+# CONFIG_DTB_RESELECT is not set
+
+# No persisted environment: everything comes from the control device
+# tree, which is authenticated as part of the FIP. A writable
+# environment would otherwise be enough to bypass secure boot, since
+# clearing env_fdt_path alone stops the device tree import.
+#
+# Needs the ENV_IS_NOWHERE patch for the board's env_get_location(),
+# see patches/uboot/, without which env_init() fails with -ENODEV.
+CONFIG_ENV_IS_NOWHERE=y
+# CONFIG_ENV_IS_IN_MMC is not set
+# CONFIG_ENV_IS_IN_SPI_FLASH is not set
+# CONFIG_ENV_IS_IN_FAT is not set
+# CONFIG_SYS_REDUNDAND_ENVIRONMENT is not set
+
+CONFIG_AUTOBOOT=y
+
+# Board environment, see lan969x-env.dtsi. Appended after the common
+# Infix ones, so it can extend them through the &env label.
+CONFIG_DEVICE_TREE_INCLUDES="infix-env.dtsi infix-key.dtsi lan969x-env.dtsi"
diff --git a/board/aarch64/microchip-ev23x71a/uboot/lan969x-env.dtsi b/board/aarch64/microchip-ev23x71a/uboot/lan969x-env.dtsi
new file mode 100644
index 000000000..e065757d3
--- /dev/null
+++ b/board/aarch64/microchip-ev23x71a/uboot/lan969x-env.dtsi
@@ -0,0 +1,37 @@
+/*
+ * 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/common/rootfs/usr/libexec/infix/hw-wait b/board/common/rootfs/usr/libexec/infix/hw-wait
index d06338fea..9e30dcfa0 100755
--- a/board/common/rootfs/usr/libexec/infix/hw-wait
+++ b/board/common/rootfs/usr/libexec/infix/hw-wait
@@ -4,6 +4,11 @@
ident=$(basename "$0")
+# Seconds to wait, boards with very slow switch cores raise this in
+# their product specific /etc/default/hw-wait
+HW_WAIT_TIMEOUT=10
+[ -r /etc/default/hw-wait ] && . /etc/default/hw-wait
+
report()
{
if [ -r "/tmp/$ident" ]; then
@@ -14,7 +19,7 @@ report()
rm -f "/tmp/$ident"
}
-for _ in $(seq 50); do
+for _ in $(seq $((HW_WAIT_TIMEOUT * 5))); do
again=
for dl in /sys/class/devlink/*; do
diff --git a/configs/aarch64_defconfig b/configs/aarch64_defconfig
index 3df284660..0398137b6 100644
--- a/configs/aarch64_defconfig
+++ b/configs/aarch64_defconfig
@@ -141,6 +141,7 @@ BR2_PACKAGE_BANANAPI_BPI_R64=y
BR2_PACKAGE_FRIENDLYARM_NANOPI_R2S=y
BR2_PACKAGE_MARVELL_CN9130_CRB=y
BR2_PACKAGE_MARVELL_ESPRESSOBIN=y
+BR2_PACKAGE_MICROCHIP_EV23X71A=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
new file mode 100644
index 000000000..1fcfb6640
--- /dev/null
+++ b/configs/laguna_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="lan969x_a0"
+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-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_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 d2f736a2c..dfcc1d54b 100644
--- a/doc/ChangeLog.md
+++ b/doc/ChangeLog.md
@@ -19,11 +19,17 @@ All notable changes to the project are documented in this file.
- Include .pkg files in release builds
- The `statd` service now logs at `notice` level by default, like other
services, and supports `-v ` to adjust verbosity at runtime
+- Hardware sensors are now children of the component they measure, so the
+ CPU temperature belongs to the CPU component, and VPD components are
+ named after the board they sit on, `vpd-cpu`, `vpd-product`
### Added
- Add NanoPi R2S Plus support (on-board 32 GB eMMC), including U-Boot
device tree selection so the eMMC is enabled when present
+- Add Microchip EV23X71A (Laguna) support: LAN969x switch with 24 GbE
+ copper ports, four SFP+ cages, and a management port, booting Infix
+ from eMMC with the usual A/B slots
### Fixes
@@ -35,6 +41,8 @@ All notable changes to the project are documented in this file.
or services keep the system busy, logged as:
statd[3558]: mdns: operational datastore busy, retrying ...
+- Fix missing CPU temperature in `show system` and the web interface on
+ SparX-5, LAN969x, and x86 boards
[ma13]: https://github.com/troglobit/mdns-alias/releases/tag/v1.3
diff --git a/doc/hardware.md b/doc/hardware.md
index f794e20eb..c54c22b5a 100644
--- a/doc/hardware.md
+++ b/doc/hardware.md
@@ -3,6 +3,34 @@
The hardware infomation and status is handled by the YANG model [IETF
hardware][1], with deviations and augmentations in _infix-hardware_.
+## Sensors
+
+Temperature, fan, voltage, current, and power readings are components of
+class `sensor`, one per reading. A sensor name is a list key and nothing
+more: what a sensor measures follows from the component it belongs to,
+named by its `parent`. Clients must select on class, never on names,
+which vary with the SoC, the driver, and the board.
+
+The SoC die temperature, for instance, is any `celsius` sensor whose
+parent has class `cpu`:
+
+```
+/ietf-hardware:hardware/component[class='iana-hardware:sensor']
+```
+
+with `parent` resolving to the component of class `iana-hardware:cpu`.
+An SoC reporting several dies or clusters yields several such sensors,
+and the hottest is the one to report. Over RESTCONF:
+
+```sh
+curl -su admin:admin \
+ https://example/restconf/data/ietf-hardware:hardware/component
+```
+
+Which hwmon device or thermal zone belongs to which component is decided
+when the data is collected, and is the only place platform specific names
+are recognized.
+
## GPS/GNSS Receivers
Infix supports GPS/GNSS receivers for hardware status monitoring and NTP
diff --git a/doc/netboot.md b/doc/netboot.md
index 202f0daa1..c225119af 100644
--- a/doc/netboot.md
+++ b/doc/netboot.md
@@ -114,6 +114,75 @@ The output is `netboot.scr` which we symlink to above in the dnsmasq
setup step.
+## Bootfile rootfs.itb
+
+By default, the U-Boot downloads whatever the DHCP server hands out as
+the boot file, so point that straight at a `rootfs.itb`:
+
+```
+cd /srv/ftp
+ln -sf ix/ev23x71a/rootfs.itb /srv/ftp/bootfile-enp17s0
+```
+
+U-Boot validates the image signature, finds the SquashFS inside it, and
+boots it as a RAM disk with `rauc.slot=net`, so the running system knows
+it came off the network rather than from a slot.
+
+This is also how a device with empty storage comes up on its own. With
+no `aux` partition there is no primary or secondary slot to try, so
+`ixpreboot` reports
+
+```
+NO BOOTABLE MEDIA FOUND, falling back to netboot
+```
+
+and goes straight to DHCP. A factory fresh board therefore reaches a
+running system with nobody at the console.
+
+
+## Installing to Onboard Storage
+
+A netbooted device is a complete system, so it can install itself.
+Build the bootloader and the Infix image separately, then combine them:
+
+```
+make _boot_defconfig O=x-boot && make O=x-boot
+make _defconfig && make
+utils/mkimage.sh -b x-boot -r output -t emmc
+```
+
+The netbooted system starts from the factory configuration, which does
+not necessarily bring up a management interface, so give it an address
+first:
+
+```
+admin@board:~$ sudo udhcpc -i e29
+```
+
+Then stream the image from the PC. Most of it is empty filesystem, so
+compressing it on the way saves a lot of wire time:
+
+```
+gzip -c x-boot/images/*-emmc.img \
+ | ssh admin@board.local 'gunzip | sudo dd of=/dev/mmcblk0 bs=1M conv=fsync'
+```
+
+Nothing on the target is mounted from the medium while netbooted, so the
+write is safe. When it completes the kernel re-reads the partition
+table and complains:
+
+```
+GPT:Primary header thinks Alt. header is not at the end of the disk.
+GPT:Alternate GPT header not at the end of the disk.
+GPT: Use GNU Parted to correct GPT errors.
+```
+
+That is expected. The table describes the image, not the medium it
+landed on. The first boot of the installed system moves the backup
+header with `sgdisk -e`, grows the last partition to fill the medium, and
+resizes the filesystem, in two stages with a reboot in between.
+
+
## U-Boot Commands
U-Boot is a maze of environment variables, some with values, some wrap
diff --git a/package/Config.in b/package/Config.in
index 6998f5804..3befdb365 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -29,6 +29,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-sysrepo/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/landing/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/libsrx/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/lowdown/Config.in"
+source "$BR2_EXTERNAL_INFIX_PATH/package/mbedtls-atf/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/mcd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/mdns-alias/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/netbrowse/Config.in"
diff --git a/package/mbedtls-atf/Config.in b/package/mbedtls-atf/Config.in
new file mode 100644
index 000000000..5ce135239
--- /dev/null
+++ b/package/mbedtls-atf/Config.in
@@ -0,0 +1,18 @@
+config BR2_PACKAGE_MBEDTLS_ATF
+ bool "mbedtls-atf"
+ depends on BR2_TARGET_ARM_TRUSTED_FIRMWARE
+ help
+ mbed TLS sources for Arm Trusted Firmware.
+
+ Platforms with Trusted Board Boot, e.g. Microchip LAN969x
+ (Laguna), authenticate each image in the FIP against a chain
+ of X.509 certificates. ATF parses those with mbed TLS, which
+ it compiles into BL1 and BL2 from source, pointed out by the
+ MBEDTLS_DIR build variable. Nothing is installed on target.
+
+ This is separate from the mbedtls package, which tracks the
+ 3.x series for use as a library. ATF 2.8 builds only against
+ the 2.28 LTS series, and expects sources, such as
+ library/rsa_internal.c, that 3.x no longer has.
+
+ https://www.trustedfirmware.org/projects/mbed-tls/
diff --git a/package/mbedtls-atf/mbedtls-atf.hash b/package/mbedtls-atf/mbedtls-atf.hash
new file mode 100644
index 000000000..4eb309b71
--- /dev/null
+++ b/package/mbedtls-atf/mbedtls-atf.hash
@@ -0,0 +1,3 @@
+# Locally calculated
+sha256 dbd42a11c26143aa8de1c07fd6ec6765395e86b06f583f051cfa60e8f0b23125 mbedtls-atf-2.28.5.tar.gz
+sha256 cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30 LICENSE
diff --git a/package/mbedtls-atf/mbedtls-atf.mk b/package/mbedtls-atf/mbedtls-atf.mk
new file mode 100644
index 000000000..6d498adef
--- /dev/null
+++ b/package/mbedtls-atf/mbedtls-atf.mk
@@ -0,0 +1,30 @@
+################################################################################
+#
+# mbedtls-atf
+#
+# mbed TLS sources for Arm Trusted Firmware, which needs them to parse
+# the X.509 certificates in a FIP when a platform has Trusted Board Boot,
+# as Microchip LAN969x (Laguna) does. ATF compiles them into BL1 and BL2
+# itself, so there is nothing to build or install here.
+#
+# The mbedtls package cannot be used for this: it tracks 3.x, while ATF
+# 2.8 builds only against the 2.28 LTS series.
+#
+################################################################################
+
+MBEDTLS_ATF_VERSION = 2.28.5
+MBEDTLS_ATF_SITE = $(call github,Mbed-TLS,mbedtls,mbedtls-$(MBEDTLS_ATF_VERSION))
+MBEDTLS_ATF_LICENSE = Apache-2.0
+MBEDTLS_ATF_LICENSE_FILES = LICENSE
+MBEDTLS_ATF_INSTALL_TARGET = NO
+
+$(eval $(generic-package))
+
+ifeq ($(BR2_PACKAGE_MBEDTLS_ATF),y)
+# MAKE_OPTS is expanded when the ATF build step runs, so appending to it
+# from here works even though Buildroot reads this file after the package
+# was defined. DEPENDENCIES is read at definition time and cannot be
+# appended to, hence the explicit ordering.
+ARM_TRUSTED_FIRMWARE_MAKE_OPTS += MBEDTLS_DIR=$(MBEDTLS_ATF_DIR)
+$(ARM_TRUSTED_FIRMWARE_TARGET_BUILD): $(MBEDTLS_ATF_TARGET_EXTRACT)
+endif
diff --git a/patches/linux/6.18.46/0001-net-phy-marvell10g-Support-firmware-loading-on-88X33.patch b/patches/linux/6.18.46/0001-net-phy-marvell10g-Support-firmware-loading-on-88X33.patch
index 41e6df0fe..46bef3501 100644
--- a/patches/linux/6.18.46/0001-net-phy-marvell10g-Support-firmware-loading-on-88X33.patch
+++ b/patches/linux/6.18.46/0001-net-phy-marvell10g-Support-firmware-loading-on-88X33.patch
@@ -1,8 +1,9 @@
From 7f49c30ee90aa0be9e9164a9948bfe8a1331fea6 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 19 Sep 2023 18:38:10 +0200
-Subject: [PATCH 01/51] net: phy: marvell10g: Support firmware loading on
+Subject: [PATCH 01/64] net: phy: marvell10g: Support firmware loading on
88X3310
+Organization: Wires
When probing, if a device is waiting for firmware to be loaded into
its RAM, ask userspace for the binary and load it over XMDIO.
diff --git a/patches/linux/6.18.46/0002-net-phy-marvell10g-Fix-power-up-when-strapped-to-sta.patch b/patches/linux/6.18.46/0002-net-phy-marvell10g-Fix-power-up-when-strapped-to-sta.patch
index bdd2bbe0a..4c15f122c 100644
--- a/patches/linux/6.18.46/0002-net-phy-marvell10g-Fix-power-up-when-strapped-to-sta.patch
+++ b/patches/linux/6.18.46/0002-net-phy-marvell10g-Fix-power-up-when-strapped-to-sta.patch
@@ -1,8 +1,9 @@
From b9ab146b15ea489f948f5a11980fe924ded4daae Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 21 Nov 2023 20:15:24 +0100
-Subject: [PATCH 02/51] net: phy: marvell10g: Fix power-up when strapped to
+Subject: [PATCH 02/64] net: phy: marvell10g: Fix power-up when strapped to
start powered down
+Organization: Wires
On devices which are hardware strapped to start powered down (PDSTATE
== 1), make sure that we clear the power-down bit on all units
diff --git a/patches/linux/6.18.46/0003-net-phy-marvell10g-Add-LED-support-for-88X3310.patch b/patches/linux/6.18.46/0003-net-phy-marvell10g-Add-LED-support-for-88X3310.patch
index 164abc4ad..7593ed5e9 100644
--- a/patches/linux/6.18.46/0003-net-phy-marvell10g-Add-LED-support-for-88X3310.patch
+++ b/patches/linux/6.18.46/0003-net-phy-marvell10g-Add-LED-support-for-88X3310.patch
@@ -1,7 +1,8 @@
From 48bf1d41a21cbe093ec241d8ee483abc70a1b8dc Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Wed, 15 Nov 2023 20:58:42 +0100
-Subject: [PATCH 03/51] net: phy: marvell10g: Add LED support for 88X3310
+Subject: [PATCH 03/64] net: phy: marvell10g: Add LED support for 88X3310
+Organization: Wires
Pickup the LEDs from the state in which the hardware reset or
bootloader left them, but also support further configuration via
diff --git a/patches/linux/6.18.46/0004-net-phy-marvell10g-Support-LEDs-tied-to-a-single-med.patch b/patches/linux/6.18.46/0004-net-phy-marvell10g-Support-LEDs-tied-to-a-single-med.patch
index 012173b7d..9cecc4a98 100644
--- a/patches/linux/6.18.46/0004-net-phy-marvell10g-Support-LEDs-tied-to-a-single-med.patch
+++ b/patches/linux/6.18.46/0004-net-phy-marvell10g-Support-LEDs-tied-to-a-single-med.patch
@@ -1,8 +1,9 @@
From 7f10824be067ddb40e89ccb66ebe9b0bda3a3f96 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 12 Dec 2023 09:51:05 +0100
-Subject: [PATCH 04/51] net: phy: marvell10g: Support LEDs tied to a single
+Subject: [PATCH 04/64] net: phy: marvell10g: Support LEDs tied to a single
media side
+Organization: Wires
In a combo-port setup, i.e. where both the copper and fiber interface
are available to the user, the LEDs may be physically located either
diff --git a/patches/linux/6.18.46/0005-net-phy-Do-not-resume-PHY-when-attaching.patch b/patches/linux/6.18.46/0005-net-phy-Do-not-resume-PHY-when-attaching.patch
index 74b9255db..b51781a3e 100644
--- a/patches/linux/6.18.46/0005-net-phy-Do-not-resume-PHY-when-attaching.patch
+++ b/patches/linux/6.18.46/0005-net-phy-Do-not-resume-PHY-when-attaching.patch
@@ -1,7 +1,8 @@
From 60c64feacdd6a2259d09545d45227f2c44c36e53 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Wed, 27 Mar 2024 10:10:19 +0100
-Subject: [PATCH 05/51] net: phy: Do not resume PHY when attaching
+Subject: [PATCH 05/64] net: phy: Do not resume PHY when attaching
+Organization: Wires
The PHY should not start negotiating with its link-partner until
explicitly instructed to do so.
diff --git a/patches/linux/6.18.46/0006-net-bridge-avoid-classifying-unknown-multicast-as-mr.patch b/patches/linux/6.18.46/0006-net-bridge-avoid-classifying-unknown-multicast-as-mr.patch
index cfd7d94b7..101739bf9 100644
--- a/patches/linux/6.18.46/0006-net-bridge-avoid-classifying-unknown-multicast-as-mr.patch
+++ b/patches/linux/6.18.46/0006-net-bridge-avoid-classifying-unknown-multicast-as-mr.patch
@@ -1,8 +1,9 @@
From 615860e3041a3837e09895425edd87aa16fa5965 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Mon, 4 Mar 2024 16:47:28 +0100
-Subject: [PATCH 06/51] net: bridge: avoid classifying unknown multicast as
+Subject: [PATCH 06/64] net: bridge: avoid classifying unknown multicast as
mrouters_only
+Organization: Wires
Unknown multicast, MAC/IPv4/IPv6, should always be flooded according to
the per-port mcast_flood setting, as well as to detected and configured
diff --git a/patches/linux/6.18.46/0007-net-bridge-Ignore-router-ports-when-forwarding-L2-mu.patch b/patches/linux/6.18.46/0007-net-bridge-Ignore-router-ports-when-forwarding-L2-mu.patch
index 5d605bbd2..a6e9e0459 100644
--- a/patches/linux/6.18.46/0007-net-bridge-Ignore-router-ports-when-forwarding-L2-mu.patch
+++ b/patches/linux/6.18.46/0007-net-bridge-Ignore-router-ports-when-forwarding-L2-mu.patch
@@ -1,8 +1,9 @@
From bf77eac4d9bc46717a5ce5cf30bd66e17d11b16e Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Tue, 5 Mar 2024 06:44:41 +0100
-Subject: [PATCH 07/51] net: bridge: Ignore router ports when forwarding L2
+Subject: [PATCH 07/64] net: bridge: Ignore router ports when forwarding L2
multicast
+Organization: Wires
Multicast router ports are either statically configured or learned from
control protocol traffic (IGMP/MLD/PIM). These protocols regulate IP
diff --git a/patches/linux/6.18.46/0008-net-bridge-drop-delay-for-applying-strict-multicast-.patch b/patches/linux/6.18.46/0008-net-bridge-drop-delay-for-applying-strict-multicast-.patch
index b4da0b6aa..bbd58fe38 100644
--- a/patches/linux/6.18.46/0008-net-bridge-drop-delay-for-applying-strict-multicast-.patch
+++ b/patches/linux/6.18.46/0008-net-bridge-drop-delay-for-applying-strict-multicast-.patch
@@ -1,8 +1,9 @@
From e0fb904d3050df4c7651d04fc823a6c1dd0ef459 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Thu, 4 Apr 2024 16:36:30 +0200
-Subject: [PATCH 08/51] net: bridge: drop delay for applying strict multicast
+Subject: [PATCH 08/64] net: bridge: drop delay for applying strict multicast
filtering
+Organization: Wires
This *local* patch drops the initial delay before applying strict multicast
filtering, introduced in [1] and recently updated in [2].
diff --git a/patches/linux/6.18.46/0009-net-bridge-Differentiate-MDB-additions-from-modifica.patch b/patches/linux/6.18.46/0009-net-bridge-Differentiate-MDB-additions-from-modifica.patch
index 907c5c7d5..bc80fa137 100644
--- a/patches/linux/6.18.46/0009-net-bridge-Differentiate-MDB-additions-from-modifica.patch
+++ b/patches/linux/6.18.46/0009-net-bridge-Differentiate-MDB-additions-from-modifica.patch
@@ -1,8 +1,9 @@
From 1bc840aa52d09ab5a3f51d75674f2ac517a9ff5a Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Thu, 16 May 2024 14:51:54 +0200
-Subject: [PATCH 09/51] net: bridge: Differentiate MDB additions from
+Subject: [PATCH 09/64] net: bridge: Differentiate MDB additions from
modifications
+Organization: Wires
Before this change, the reception of an IGMPv3 report (and analogously
for MLDv2) that adds a new group, would trigger two MDB RTM_NEWMDB
diff --git a/patches/linux/6.18.46/0010-nvmem-layouts-onie-tlv-Let-device-probe-even-when-TL.patch b/patches/linux/6.18.46/0010-nvmem-layouts-onie-tlv-Let-device-probe-even-when-TL.patch
index a495a04e3..c94ca34ee 100644
--- a/patches/linux/6.18.46/0010-nvmem-layouts-onie-tlv-Let-device-probe-even-when-TL.patch
+++ b/patches/linux/6.18.46/0010-nvmem-layouts-onie-tlv-Let-device-probe-even-when-TL.patch
@@ -1,8 +1,9 @@
From 31ec2dddbe45228f3ad3e4f850b65125cd2b9f06 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Fri, 24 Nov 2023 23:29:55 +0100
-Subject: [PATCH 10/51] nvmem: layouts: onie-tlv: Let device probe even when
+Subject: [PATCH 10/64] nvmem: layouts: onie-tlv: Let device probe even when
TLV is invalid
+Organization: Wires
Before this change, probing an NVMEM device, expected to contain a
valid TLV, would fail if it had not been provisioned yet. But an
diff --git a/patches/linux/6.18.46/0011-net-usb-r8152-add-r8153b-support-for-link-activity-L.patch b/patches/linux/6.18.46/0011-net-usb-r8152-add-r8153b-support-for-link-activity-L.patch
index b0bff94a6..0552cd4bc 100644
--- a/patches/linux/6.18.46/0011-net-usb-r8152-add-r8153b-support-for-link-activity-L.patch
+++ b/patches/linux/6.18.46/0011-net-usb-r8152-add-r8153b-support-for-link-activity-L.patch
@@ -1,8 +1,9 @@
From ed17421a32311c8bdd685b65e24f83e998449305 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Sun, 11 Aug 2024 11:27:35 +0200
-Subject: [PATCH 11/51] net: usb: r8152: add r8153b support for link/activity
+Subject: [PATCH 11/64] net: usb: r8152: add r8153b support for link/activity
LEDs
+Organization: Wires
This patch adds support for the link/activity LEDs on the NanoPi R2S
and OrangePi R1 Plus.
diff --git a/patches/linux/6.18.46/0012-arm64-dts-mediatek-mt7986a-rename-BPi-R3-ports-to-ma.patch b/patches/linux/6.18.46/0012-arm64-dts-mediatek-mt7986a-rename-BPi-R3-ports-to-ma.patch
index 49b51b3cf..406800e5b 100644
--- a/patches/linux/6.18.46/0012-arm64-dts-mediatek-mt7986a-rename-BPi-R3-ports-to-ma.patch
+++ b/patches/linux/6.18.46/0012-arm64-dts-mediatek-mt7986a-rename-BPi-R3-ports-to-ma.patch
@@ -1,8 +1,9 @@
From 72267d352c38207ddb1d84af6141de93db5d150a Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Sun, 10 Aug 2025 18:52:54 +0200
-Subject: [PATCH 12/51] arm64: dts: mediatek: mt7986a: rename BPi R3 ports to
+Subject: [PATCH 12/64] arm64: dts: mediatek: mt7986a: rename BPi R3 ports to
match case
+Organization: Wires
For ref. see: https://wiki.banana-pi.org/File:Bpi-r3_Metal_case.jpg
diff --git a/patches/linux/6.18.46/0013-drm-panel-simple-Add-a-timing-for-the-Raspberry-Pi-7.patch b/patches/linux/6.18.46/0013-drm-panel-simple-Add-a-timing-for-the-Raspberry-Pi-7.patch
index 373446783..68669080c 100644
--- a/patches/linux/6.18.46/0013-drm-panel-simple-Add-a-timing-for-the-Raspberry-Pi-7.patch
+++ b/patches/linux/6.18.46/0013-drm-panel-simple-Add-a-timing-for-the-Raspberry-Pi-7.patch
@@ -1,8 +1,9 @@
From 7106cd3a9e250c5e3974dd642d8cc19af5ef2ac7 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Wed, 20 Aug 2025 21:38:24 +0200
-Subject: [PATCH 13/51] drm/panel-simple: Add a timing for the Raspberry Pi 7"
+Subject: [PATCH 13/64] drm/panel-simple: Add a timing for the Raspberry Pi 7"
panel
+Organization: Wires
The Raspberry Pi 7" 800x480 panel uses a Toshiba TC358762 DSI
to DPI bridge chip, so there is a requirement for the timings
diff --git a/patches/linux/6.18.46/0014-input-touchscreen-edt-ft5x06-Add-polled-mode.patch b/patches/linux/6.18.46/0014-input-touchscreen-edt-ft5x06-Add-polled-mode.patch
index bb7844b87..cda7b5435 100644
--- a/patches/linux/6.18.46/0014-input-touchscreen-edt-ft5x06-Add-polled-mode.patch
+++ b/patches/linux/6.18.46/0014-input-touchscreen-edt-ft5x06-Add-polled-mode.patch
@@ -1,7 +1,8 @@
From 3bc1d86fcd0e24960152f4d758aa250057b63fcb Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Thu, 21 Aug 2025 11:20:23 +0200
-Subject: [PATCH 14/51] input:touchscreen:edt-ft5x06: Add polled mode
+Subject: [PATCH 14/64] input:touchscreen:edt-ft5x06: Add polled mode
+Organization: Wires
Not all hardware has interrupts therefore we need
to poll the touchscreen.
diff --git a/patches/linux/6.18.46/0015-FIX-net-dsa-mv88e6xxx-Fix-timeout-on-waiting-for-PPU.patch b/patches/linux/6.18.46/0015-FIX-net-dsa-mv88e6xxx-Fix-timeout-on-waiting-for-PPU.patch
index 39bcba81e..eb441a09e 100644
--- a/patches/linux/6.18.46/0015-FIX-net-dsa-mv88e6xxx-Fix-timeout-on-waiting-for-PPU.patch
+++ b/patches/linux/6.18.46/0015-FIX-net-dsa-mv88e6xxx-Fix-timeout-on-waiting-for-PPU.patch
@@ -1,8 +1,9 @@
From b0a42be0c80c3d44305f80e6e867a911aa00d35c Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 12 Mar 2024 10:27:24 +0100
-Subject: [PATCH 15/51] [FIX] net: dsa: mv88e6xxx: Fix timeout on waiting for
+Subject: [PATCH 15/64] [FIX] net: dsa: mv88e6xxx: Fix timeout on waiting for
PPU on 6393X
+Organization: Wires
In a multi-chip setup, delays of up to 750ms are observed before the
device (6393X) signals completion of PPU initialization (Global 1,
diff --git a/patches/linux/6.18.46/0016-net-dsa-mv88e6xxx-Improve-indirect-register-access-p.patch b/patches/linux/6.18.46/0016-net-dsa-mv88e6xxx-Improve-indirect-register-access-p.patch
index 03aa9b563..fdb0fd3a5 100644
--- a/patches/linux/6.18.46/0016-net-dsa-mv88e6xxx-Improve-indirect-register-access-p.patch
+++ b/patches/linux/6.18.46/0016-net-dsa-mv88e6xxx-Improve-indirect-register-access-p.patch
@@ -1,8 +1,9 @@
From 5810a287ae29b817a4294ebed04358f730f65065 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Wed, 27 Mar 2024 15:52:43 +0100
-Subject: [PATCH 16/51] net: dsa: mv88e6xxx: Improve indirect register access
+Subject: [PATCH 16/64] net: dsa: mv88e6xxx: Improve indirect register access
perf on 6393
+Organization: Wires
When operating in multi-chip mode, the 6393 family maps a subset of
commonly used global registers to the outermost address space (in
diff --git a/patches/linux/6.18.46/0017-net-dsa-mv88e6xxx-Honor-ports-being-managed-via-in-b.patch b/patches/linux/6.18.46/0017-net-dsa-mv88e6xxx-Honor-ports-being-managed-via-in-b.patch
index 17fcd3c28..1c72832c7 100644
--- a/patches/linux/6.18.46/0017-net-dsa-mv88e6xxx-Honor-ports-being-managed-via-in-b.patch
+++ b/patches/linux/6.18.46/0017-net-dsa-mv88e6xxx-Honor-ports-being-managed-via-in-b.patch
@@ -1,8 +1,9 @@
From 38a0d0b99db217d86d8b2b2b832858df24b235a0 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Mon, 22 Apr 2024 23:18:01 +0200
-Subject: [PATCH 17/51] net: dsa: mv88e6xxx: Honor ports being managed via
+Subject: [PATCH 17/64] net: dsa: mv88e6xxx: Honor ports being managed via
in-band-status
+Organization: Wires
Keep all link parameters in their unforced states when the port is
declared as being managed via in-band-status, and let the MAC
diff --git a/patches/linux/6.18.46/0018-net-dsa-mv88e6xxx-Limit-rsvd2cpu-policy-to-user-port.patch b/patches/linux/6.18.46/0018-net-dsa-mv88e6xxx-Limit-rsvd2cpu-policy-to-user-port.patch
index ec2be34ca..0dcb06322 100644
--- a/patches/linux/6.18.46/0018-net-dsa-mv88e6xxx-Limit-rsvd2cpu-policy-to-user-port.patch
+++ b/patches/linux/6.18.46/0018-net-dsa-mv88e6xxx-Limit-rsvd2cpu-policy-to-user-port.patch
@@ -1,8 +1,9 @@
From c4fffd95d964d7a911b6039cc8e7e5d736a47e4d Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Wed, 24 Apr 2024 22:41:04 +0200
-Subject: [PATCH 18/51] net: dsa: mv88e6xxx: Limit rsvd2cpu policy to user
+Subject: [PATCH 18/64] net: dsa: mv88e6xxx: Limit rsvd2cpu policy to user
ports on 6393X
+Organization: Wires
For packets with a DA in the IEEE reserved L2 group range, originating
from a CPU, forward it as normal, rather than classifying it as
diff --git a/patches/linux/6.18.46/0019-net-dsa-tag_dsa-Use-tag-priority-as-initial-skb-prio.patch b/patches/linux/6.18.46/0019-net-dsa-tag_dsa-Use-tag-priority-as-initial-skb-prio.patch
index 60a0743e6..78bb597b8 100644
--- a/patches/linux/6.18.46/0019-net-dsa-tag_dsa-Use-tag-priority-as-initial-skb-prio.patch
+++ b/patches/linux/6.18.46/0019-net-dsa-tag_dsa-Use-tag-priority-as-initial-skb-prio.patch
@@ -1,8 +1,9 @@
From 5027f6ffd52d93916153bce5bbea45e510cdde00 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 28 May 2024 10:38:42 +0200
-Subject: [PATCH 19/51] net: dsa: tag_dsa: Use tag priority as initial
+Subject: [PATCH 19/64] net: dsa: tag_dsa: Use tag priority as initial
skb->priority
+Organization: Wires
Use the 3-bit priority field from the DSA tag as the initial packet
priority on ingress to the CPU.
diff --git a/patches/linux/6.18.46/0020-net-dsa-Support-MDB-memberships-whose-L2-addresses-o.patch b/patches/linux/6.18.46/0020-net-dsa-Support-MDB-memberships-whose-L2-addresses-o.patch
index d19eee19d..dbf4bd741 100644
--- a/patches/linux/6.18.46/0020-net-dsa-Support-MDB-memberships-whose-L2-addresses-o.patch
+++ b/patches/linux/6.18.46/0020-net-dsa-Support-MDB-memberships-whose-L2-addresses-o.patch
@@ -1,8 +1,9 @@
From ac1320e82a14564a734664a0a8f7a0c116aaccdd Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 16 Jan 2024 16:00:55 +0100
-Subject: [PATCH 20/51] net: dsa: Support MDB memberships whose L2 addresses
+Subject: [PATCH 20/64] net: dsa: Support MDB memberships whose L2 addresses
overlap
+Organization: Wires
Multiple IP multicast groups (32 for v4, 2^80 for v6) map to the same
L2 address. This means that switchdev drivers may receive multiple MDB
diff --git a/patches/linux/6.18.46/0021-net-dsa-Support-EtherType-based-priority-overrides.patch b/patches/linux/6.18.46/0021-net-dsa-Support-EtherType-based-priority-overrides.patch
index 1518ba71d..c6525ff82 100644
--- a/patches/linux/6.18.46/0021-net-dsa-Support-EtherType-based-priority-overrides.patch
+++ b/patches/linux/6.18.46/0021-net-dsa-Support-EtherType-based-priority-overrides.patch
@@ -1,7 +1,8 @@
From 8e49aca4ae513ea525bdf82b5f05045c11448f6a Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Thu, 21 Mar 2024 19:12:15 +0100
-Subject: [PATCH 21/51] net: dsa: Support EtherType based priority overrides
+Subject: [PATCH 21/64] net: dsa: Support EtherType based priority overrides
+Organization: Wires
---
include/net/dsa.h | 4 ++++
diff --git a/patches/linux/6.18.46/0022-net-dsa-mv88e6xxx-Support-EtherType-based-priority-o.patch b/patches/linux/6.18.46/0022-net-dsa-mv88e6xxx-Support-EtherType-based-priority-o.patch
index ff5f14bc3..851ece142 100644
--- a/patches/linux/6.18.46/0022-net-dsa-mv88e6xxx-Support-EtherType-based-priority-o.patch
+++ b/patches/linux/6.18.46/0022-net-dsa-mv88e6xxx-Support-EtherType-based-priority-o.patch
@@ -1,8 +1,9 @@
From e474fdde8c8131bbf996112e274f9842c659aa42 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Fri, 22 Mar 2024 16:15:43 +0100
-Subject: [PATCH 22/51] net: dsa: mv88e6xxx: Support EtherType based priority
+Subject: [PATCH 22/64] net: dsa: mv88e6xxx: Support EtherType based priority
overrides
+Organization: Wires
---
drivers/net/dsa/mv88e6xxx/chip.c | 64 +++++++++++++++++++++++++++++
diff --git a/patches/linux/6.18.46/0023-net-dsa-mv88e6xxx-Add-mqprio-qdisc-support.patch b/patches/linux/6.18.46/0023-net-dsa-mv88e6xxx-Add-mqprio-qdisc-support.patch
index 538b03592..09d2a5480 100644
--- a/patches/linux/6.18.46/0023-net-dsa-mv88e6xxx-Add-mqprio-qdisc-support.patch
+++ b/patches/linux/6.18.46/0023-net-dsa-mv88e6xxx-Add-mqprio-qdisc-support.patch
@@ -1,7 +1,8 @@
From fd4efe5794c4abc5e1d0f06f70466d6e2eccd37d Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 28 May 2024 11:04:22 +0200
-Subject: [PATCH 23/51] net: dsa: mv88e6xxx: Add mqprio qdisc support
+Subject: [PATCH 23/64] net: dsa: mv88e6xxx: Add mqprio qdisc support
+Organization: Wires
Add support for attaching mqprio qdisc's to mv88e6xxx ports and use
the packet's traffic class as the outgoing priority when no PCP bits
diff --git a/patches/linux/6.18.46/0024-net-dsa-mv88e6xxx-Use-VLAN-prio-over-IP-when-both-ar.patch b/patches/linux/6.18.46/0024-net-dsa-mv88e6xxx-Use-VLAN-prio-over-IP-when-both-ar.patch
index b47582ec5..9706f7444 100644
--- a/patches/linux/6.18.46/0024-net-dsa-mv88e6xxx-Use-VLAN-prio-over-IP-when-both-ar.patch
+++ b/patches/linux/6.18.46/0024-net-dsa-mv88e6xxx-Use-VLAN-prio-over-IP-when-both-ar.patch
@@ -1,8 +1,9 @@
From e9dc3d87cc9812e1b81f19ea1ad15b0492e35b91 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Wed, 29 May 2024 13:20:41 +0200
-Subject: [PATCH 24/51] net: dsa: mv88e6xxx: Use VLAN prio over IP when both
+Subject: [PATCH 24/64] net: dsa: mv88e6xxx: Use VLAN prio over IP when both
are available
+Organization: Wires
Switch the priority sourcing precdence to prefer VLAN PCP over IP
DSCP, when both are available.
diff --git a/patches/linux/6.18.46/0025-FIX-net-dsa-mv88e6xxx-Trap-locally-terminated-VLANs.patch b/patches/linux/6.18.46/0025-FIX-net-dsa-mv88e6xxx-Trap-locally-terminated-VLANs.patch
index 5b6afab28..6038626e4 100644
--- a/patches/linux/6.18.46/0025-FIX-net-dsa-mv88e6xxx-Trap-locally-terminated-VLANs.patch
+++ b/patches/linux/6.18.46/0025-FIX-net-dsa-mv88e6xxx-Trap-locally-terminated-VLANs.patch
@@ -1,8 +1,9 @@
From 365989e8bc430a722c62fae7a54aa76d95403d44 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Tue, 26 Nov 2024 19:45:59 +0100
-Subject: [PATCH 25/51] [FIX] net: dsa: mv88e6xxx: Trap locally terminated
+Subject: [PATCH 25/64] [FIX] net: dsa: mv88e6xxx: Trap locally terminated
VLANs
+Organization: Wires
Before this change, in a setup like the following, packets assigned to
VLAN 10 were forwarded between the switch ports, even though the
diff --git a/patches/linux/6.18.46/0026-net-dsa-mv88e6xxx-collapse-disabled-state-into-block.patch b/patches/linux/6.18.46/0026-net-dsa-mv88e6xxx-collapse-disabled-state-into-block.patch
index 7f64a66e1..4981c6a5e 100644
--- a/patches/linux/6.18.46/0026-net-dsa-mv88e6xxx-collapse-disabled-state-into-block.patch
+++ b/patches/linux/6.18.46/0026-net-dsa-mv88e6xxx-collapse-disabled-state-into-block.patch
@@ -1,8 +1,9 @@
From cc07a927ce3d66cbb5507b97d71f2e4289e3932a Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Thu, 16 Jan 2025 12:35:12 +0100
-Subject: [PATCH 26/51] net: dsa: mv88e6xxx: collapse disabled state into
+Subject: [PATCH 26/64] net: dsa: mv88e6xxx: collapse disabled state into
blocking
+Organization: Wires
This patch changes the behavior of switchcore ports wrt. the port state.
Instead of disabling the port, the driver now treats the disabled state
diff --git a/patches/linux/6.18.46/0027-net-dsa-mv88e6xxx-Only-activate-LAG-offloading-when-.patch b/patches/linux/6.18.46/0027-net-dsa-mv88e6xxx-Only-activate-LAG-offloading-when-.patch
index 25713888b..fdc08b297 100644
--- a/patches/linux/6.18.46/0027-net-dsa-mv88e6xxx-Only-activate-LAG-offloading-when-.patch
+++ b/patches/linux/6.18.46/0027-net-dsa-mv88e6xxx-Only-activate-LAG-offloading-when-.patch
@@ -1,8 +1,9 @@
From 293bd6b0ff1a613e7a2f864039517881f1dd7191 Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Wed, 12 Feb 2025 22:03:14 +0100
-Subject: [PATCH 27/51] net: dsa: mv88e6xxx: Only activate LAG offloading when
+Subject: [PATCH 27/64] net: dsa: mv88e6xxx: Only activate LAG offloading when
bridged
+Organization: Wires
The current port isolation scheme for mv88e6xxx is detailed here:
https://lore.kernel.org/netdev/20220203101657.990241-1-tobias@waldekranz.com/
diff --git a/patches/linux/6.18.46/0028-net-dsa-mv88e6xxx-Add-LED-support-for-6393X.patch b/patches/linux/6.18.46/0028-net-dsa-mv88e6xxx-Add-LED-support-for-6393X.patch
index b86aebd16..0ed4cfd6c 100644
--- a/patches/linux/6.18.46/0028-net-dsa-mv88e6xxx-Add-LED-support-for-6393X.patch
+++ b/patches/linux/6.18.46/0028-net-dsa-mv88e6xxx-Add-LED-support-for-6393X.patch
@@ -1,7 +1,8 @@
From cbdcda769e36b4c2c4870b01a02efd4223f327e1 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Wed, 14 Jan 2026 18:22:41 +0100
-Subject: [PATCH 28/51] net: dsa: mv88e6xxx: Add LED support for 6393X
+Subject: [PATCH 28/64] net: dsa: mv88e6xxx: Add LED support for 6393X
+Organization: Wires
Original commit:
commit 462277b926140ee2d231317e92afb6cabf640268
diff --git a/patches/linux/6.18.46/0029-wifi-brcmfmac-support-deletion-and-recreation-of-pri.patch b/patches/linux/6.18.46/0029-wifi-brcmfmac-support-deletion-and-recreation-of-pri.patch
index a10c95d75..bcf38abee 100644
--- a/patches/linux/6.18.46/0029-wifi-brcmfmac-support-deletion-and-recreation-of-pri.patch
+++ b/patches/linux/6.18.46/0029-wifi-brcmfmac-support-deletion-and-recreation-of-pri.patch
@@ -1,11 +1,12 @@
From 38ed86d1c1b291c40e6a15681acc09234014a271 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Thu, 15 Jan 2026 22:47:37 +0100
-Subject: [PATCH 29/51] wifi: brcmfmac: support deletion and recreation of
+Subject: [PATCH 29/64] wifi: brcmfmac: support deletion and recreation of
primary interface
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
The Broadcom FullMAC firmware does not allow the primary interface
(bsscfgidx 0) to be deleted - it always exists in firmware. However,
diff --git a/patches/linux/6.18.46/0030-wifi-brcmfmac-check-connection-state-before-querying.patch b/patches/linux/6.18.46/0030-wifi-brcmfmac-check-connection-state-before-querying.patch
index 4294e225e..aaa994bc4 100644
--- a/patches/linux/6.18.46/0030-wifi-brcmfmac-check-connection-state-before-querying.patch
+++ b/patches/linux/6.18.46/0030-wifi-brcmfmac-check-connection-state-before-querying.patch
@@ -1,11 +1,12 @@
From 854fa7b14fd0e6612884a3020279f613daeaf07f Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Mon, 19 Jan 2026 13:06:53 +0100
-Subject: [PATCH 30/51] wifi: brcmfmac: check connection state before querying
+Subject: [PATCH 30/64] wifi: brcmfmac: check connection state before querying
station info
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
In station mode, brcmf_cfg80211_get_station() queries the firmware for
station info even when not connected to an AP. This results in error
diff --git a/patches/linux/6.18.46/0031-wifi-brcmfmac-suppress-log-spam-for-regulatory-restr.patch b/patches/linux/6.18.46/0031-wifi-brcmfmac-suppress-log-spam-for-regulatory-restr.patch
index 3a18cac59..ff45e6c01 100644
--- a/patches/linux/6.18.46/0031-wifi-brcmfmac-suppress-log-spam-for-regulatory-restr.patch
+++ b/patches/linux/6.18.46/0031-wifi-brcmfmac-suppress-log-spam-for-regulatory-restr.patch
@@ -1,11 +1,12 @@
From 93c0d322dc996a4cb3b1fbe7de5b4d103c4ff936 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Tue, 20 Jan 2026 20:12:10 +0100
-Subject: [PATCH 31/51] wifi: brcmfmac: suppress log spam for
+Subject: [PATCH 31/64] wifi: brcmfmac: suppress log spam for
regulatory-restricted channels
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
When scanning, the driver attempts to set each channel and logs an
error if the firmware rejects it. For regulatory-restricted channels,
diff --git a/patches/linux/6.18.46/0032-wifi-brcmfmac-reduce-log-noise-during-AP-to-station-.patch b/patches/linux/6.18.46/0032-wifi-brcmfmac-reduce-log-noise-during-AP-to-station-.patch
index 06f6b2cda..cbc5c15be 100644
--- a/patches/linux/6.18.46/0032-wifi-brcmfmac-reduce-log-noise-during-AP-to-station-.patch
+++ b/patches/linux/6.18.46/0032-wifi-brcmfmac-reduce-log-noise-during-AP-to-station-.patch
@@ -1,11 +1,12 @@
From 974f5187c4e1e618b7a4912b0fe8f7f02d8f2102 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Tue, 20 Jan 2026 20:18:45 +0100
-Subject: [PATCH 32/51] wifi: brcmfmac: reduce log noise during AP to station
+Subject: [PATCH 32/64] wifi: brcmfmac: reduce log noise during AP to station
transition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
When transitioning from AP mode to station mode (e.g., hostapd stopping
and wpa_supplicant starting), several non-fatal errors can occur:
diff --git a/patches/linux/6.18.46/0033-net-phy-air_en8811h-add-OF-device-table-for-auto-loa.patch b/patches/linux/6.18.46/0033-net-phy-air_en8811h-add-OF-device-table-for-auto-loa.patch
index dc703ba12..60f48320e 100644
--- a/patches/linux/6.18.46/0033-net-phy-air_en8811h-add-OF-device-table-for-auto-loa.patch
+++ b/patches/linux/6.18.46/0033-net-phy-air_en8811h-add-OF-device-table-for-auto-loa.patch
@@ -1,8 +1,9 @@
From ea6dd4989c7bb939e925f4c9173966e1c314ffa6 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Tue, 17 Feb 2026 21:59:59 +0100
-Subject: [PATCH 33/51] net: phy: air_en8811h: add OF device table for
+Subject: [PATCH 33/64] net: phy: air_en8811h: add OF device table for
auto-loading
+Organization: Wires
mdio_uevent() only emits an OF-style MODALIAS via
of_device_uevent_modalias(), never the mdio: binary format that
diff --git a/patches/linux/6.18.46/0034-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch b/patches/linux/6.18.46/0034-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch
index 92046f485..033f2d322 100644
--- a/patches/linux/6.18.46/0034-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch
+++ b/patches/linux/6.18.46/0034-drm-vc4-dsi-enable-video-and-then-retry-failed-trans.patch
@@ -1,8 +1,9 @@
From be81d065db8772a936a8aa82a58cbb64e04e9c20 Mon Sep 17 00:00:00 2001
From: Dave Stevenson
Date: Fri, 20 Sep 2024 12:05:18 +0100
-Subject: [PATCH 34/51] drm: vc4: dsi: enable video and then retry failed
+Subject: [PATCH 34/64] drm: vc4: dsi: enable video and then retry failed
transfers
+Organization: Wires
The DSI block appears to be able to come up stuck in a condition where
it leaves the lanes in HS mode or just jabbering. This stops LP
diff --git a/patches/linux/6.18.46/0035-drm-vc4-dsi-Clocks-should-be-running-before-reset.patch b/patches/linux/6.18.46/0035-drm-vc4-dsi-Clocks-should-be-running-before-reset.patch
index 23554b0e4..2a2364a45 100644
--- a/patches/linux/6.18.46/0035-drm-vc4-dsi-Clocks-should-be-running-before-reset.patch
+++ b/patches/linux/6.18.46/0035-drm-vc4-dsi-Clocks-should-be-running-before-reset.patch
@@ -1,7 +1,8 @@
From 68d70ad3bf8403c46abbb915082ecd62f22b67f0 Mon Sep 17 00:00:00 2001
From: Dave Stevenson
Date: Wed, 8 Jun 2022 17:23:47 +0100
-Subject: [PATCH 35/51] drm: vc4: dsi: Clocks should be running before reset
+Subject: [PATCH 35/64] drm: vc4: dsi: Clocks should be running before reset
+Organization: Wires
The initialisation sequence differs slightly from the documentation
in that the clocks are meant to be running before resets and
diff --git a/patches/linux/6.18.46/0036-drm-vc4-Ensure-DSI-is-enabled-for-FIFO-resets.patch b/patches/linux/6.18.46/0036-drm-vc4-Ensure-DSI-is-enabled-for-FIFO-resets.patch
index 1dbcadf53..ce2c4917c 100644
--- a/patches/linux/6.18.46/0036-drm-vc4-Ensure-DSI-is-enabled-for-FIFO-resets.patch
+++ b/patches/linux/6.18.46/0036-drm-vc4-Ensure-DSI-is-enabled-for-FIFO-resets.patch
@@ -1,7 +1,8 @@
From 1c76f7dc3d027966639b7d5ca6f65129547c6a2d Mon Sep 17 00:00:00 2001
From: Dave Stevenson
Date: Fri, 5 Apr 2024 17:51:55 +0100
-Subject: [PATCH 36/51] drm/vc4: Ensure DSI is enabled for FIFO resets
+Subject: [PATCH 36/64] drm/vc4: Ensure DSI is enabled for FIFO resets
+Organization: Wires
The block must be enabled for the FIFO resets to be actioned,
so ensure this is the case.
diff --git a/patches/linux/6.18.46/0037-drm-vc4-Reset-DSI-AFE-on-disable.patch b/patches/linux/6.18.46/0037-drm-vc4-Reset-DSI-AFE-on-disable.patch
index 5b6b875f2..3d408454a 100644
--- a/patches/linux/6.18.46/0037-drm-vc4-Reset-DSI-AFE-on-disable.patch
+++ b/patches/linux/6.18.46/0037-drm-vc4-Reset-DSI-AFE-on-disable.patch
@@ -1,7 +1,8 @@
From 10c7894512493d96255f5b04c173e3c221d02ecc Mon Sep 17 00:00:00 2001
From: Dave Stevenson
Date: Thu, 26 May 2022 18:56:19 +0100
-Subject: [PATCH 37/51] drm: vc4: Reset DSI AFE on disable
+Subject: [PATCH 37/64] drm: vc4: Reset DSI AFE on disable
+Organization: Wires
vc4_dsi_bridge_disable wasn't resetting things during shutdown,
so add that in.
diff --git a/patches/linux/6.18.46/0038-drm-vc4-dsi-Handle-the-different-command-FIFO-widths.patch b/patches/linux/6.18.46/0038-drm-vc4-dsi-Handle-the-different-command-FIFO-widths.patch
index 75009fdfd..a20f3a1c0 100644
--- a/patches/linux/6.18.46/0038-drm-vc4-dsi-Handle-the-different-command-FIFO-widths.patch
+++ b/patches/linux/6.18.46/0038-drm-vc4-dsi-Handle-the-different-command-FIFO-widths.patch
@@ -1,7 +1,8 @@
From 29c6177a89963064bee65d75e8c3eb627b59eef3 Mon Sep 17 00:00:00 2001
From: Dave Stevenson
Date: Wed, 20 Nov 2024 13:58:08 +0000
-Subject: [PATCH 38/51] drm: vc4: dsi: Handle the different command FIFO widths
+Subject: [PATCH 38/64] drm: vc4: dsi: Handle the different command FIFO widths
+Organization: Wires
DSI0 and DSI1 have different widths for the command FIFO (24bit
vs 32bit), but the driver was assuming the 32bit width of DSI1
diff --git a/patches/linux/6.18.46/0039-drm-bridge-tc358762-Program-the-DPI-mode-into-the-ch.patch b/patches/linux/6.18.46/0039-drm-bridge-tc358762-Program-the-DPI-mode-into-the-ch.patch
index a92d19516..1f395a4c4 100644
--- a/patches/linux/6.18.46/0039-drm-bridge-tc358762-Program-the-DPI-mode-into-the-ch.patch
+++ b/patches/linux/6.18.46/0039-drm-bridge-tc358762-Program-the-DPI-mode-into-the-ch.patch
@@ -1,8 +1,9 @@
From 28567ab2d86656eb251237c2e724ca3adb7bd990 Mon Sep 17 00:00:00 2001
From: Dave Stevenson
Date: Tue, 9 Jan 2024 17:37:00 +0000
-Subject: [PATCH 39/51] drm/bridge: tc358762: Program the DPI mode into the
+Subject: [PATCH 39/64] drm/bridge: tc358762: Program the DPI mode into the
chip
+Organization: Wires
The autodetection of resolution/timing by the TC358762 can lead
to the display being shifted by a pixel or two.
diff --git a/patches/linux/6.18.46/0040-drm-bridge-tc358762-revert-move-ops-to-enable.patch b/patches/linux/6.18.46/0040-drm-bridge-tc358762-revert-move-ops-to-enable.patch
index a709ffa4a..35b2e4569 100644
--- a/patches/linux/6.18.46/0040-drm-bridge-tc358762-revert-move-ops-to-enable.patch
+++ b/patches/linux/6.18.46/0040-drm-bridge-tc358762-revert-move-ops-to-enable.patch
@@ -1,7 +1,8 @@
From 98cae179b9f4aa535686fb10031183b0d7b98294 Mon Sep 17 00:00:00 2001
From: Dave Stevenson
Date: Tue, 9 Jan 2024 18:44:49 +0000
-Subject: [PATCH 40/51] drm/bridge: tc358762: revert move ops to enable
+Subject: [PATCH 40/64] drm/bridge: tc358762: revert move ops to enable
+Organization: Wires
Reverts 8a4b2fc9c91a ("drm/bridge: tc358762: Split register programming from pre-enable to enable")
as we want the config commands sent before video starts.
diff --git a/patches/linux/6.18.46/0041-drm-bridge-tc358762-Set-pre_enabled-on-pre_enable-to.patch b/patches/linux/6.18.46/0041-drm-bridge-tc358762-Set-pre_enabled-on-pre_enable-to.patch
index 4796b421e..b6d8f01c6 100644
--- a/patches/linux/6.18.46/0041-drm-bridge-tc358762-Set-pre_enabled-on-pre_enable-to.patch
+++ b/patches/linux/6.18.46/0041-drm-bridge-tc358762-Set-pre_enabled-on-pre_enable-to.patch
@@ -1,11 +1,12 @@
From df1dd24ec79a6b653484d44a47c2e4856284ca01 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Sat, 4 Apr 2026 18:04:19 +0200
-Subject: [PATCH 41/51] drm/bridge: tc358762: Set pre_enabled on pre_enable to
+Subject: [PATCH 41/64] drm/bridge: tc358762: Set pre_enabled on pre_enable to
prevent regulator imbalance
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
The RPi cherry-pick moved tc358762_init() to pre_enable but dropped the pre_enabled = true assignment.
Without it, post_disable always bails out early and never disables the regulator.
diff --git a/patches/linux/6.18.46/0042-net-pcs-add-standalone-PCS-registration-infrastructu.patch b/patches/linux/6.18.46/0042-net-pcs-add-standalone-PCS-registration-infrastructu.patch
index 9152e8633..b7ae733b6 100644
--- a/patches/linux/6.18.46/0042-net-pcs-add-standalone-PCS-registration-infrastructu.patch
+++ b/patches/linux/6.18.46/0042-net-pcs-add-standalone-PCS-registration-infrastructu.patch
@@ -1,7 +1,8 @@
From ba4bf183b4951aef883d3211f20b957367a6870e Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Sun, 5 Apr 2026 11:33:00 +0200
-Subject: [PATCH 42/51] net/pcs: add standalone PCS registration infrastructure
+Subject: [PATCH 42/64] net/pcs: add standalone PCS registration infrastructure
+Organization: Wires
Add a simple registration mechanism that allows platform PCS drivers to
register their phylink_pcs instances, and consumers (e.g. Ethernet MAC
diff --git a/patches/linux/6.18.46/0043-net-pcs-add-MediaTek-MT7988-USXGMII-PCS-driver.patch b/patches/linux/6.18.46/0043-net-pcs-add-MediaTek-MT7988-USXGMII-PCS-driver.patch
index 2d84d49f0..a8e541c6e 100644
--- a/patches/linux/6.18.46/0043-net-pcs-add-MediaTek-MT7988-USXGMII-PCS-driver.patch
+++ b/patches/linux/6.18.46/0043-net-pcs-add-MediaTek-MT7988-USXGMII-PCS-driver.patch
@@ -1,7 +1,8 @@
From 98943e6e990fae82fbfc635daa223ca528173ceb Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Mon, 6 Apr 2026 14:14:23 +0200
-Subject: [PATCH 43/51] net/pcs: add MediaTek MT7988 USXGMII PCS driver
+Subject: [PATCH 43/64] net/pcs: add MediaTek MT7988 USXGMII PCS driver
+Organization: Wires
Add a PCS driver for the USXGMII subsystem found in the MediaTek MT7988
SoC (usxgmiisys0 at 0x10080000, usxgmiisys1 at 0x10081000). The hardware
diff --git a/patches/linux/6.18.46/0044-net-ethernet-mediatek-add-USXGMII-support-for-MT7988.patch b/patches/linux/6.18.46/0044-net-ethernet-mediatek-add-USXGMII-support-for-MT7988.patch
index f8ff16f44..67a3546dc 100644
--- a/patches/linux/6.18.46/0044-net-ethernet-mediatek-add-USXGMII-support-for-MT7988.patch
+++ b/patches/linux/6.18.46/0044-net-ethernet-mediatek-add-USXGMII-support-for-MT7988.patch
@@ -1,10 +1,11 @@
From 198e2e4dd0c98e9b97c372503c6a6fd2253d166b Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Mon, 6 Apr 2026 14:15:43 +0200
-Subject: [PATCH 44/51] net: ethernet: mediatek: add USXGMII support for MT7988
+Subject: [PATCH 44/64] net: ethernet: mediatek: add USXGMII support for MT7988
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
Add support for the USXGMII path used by gmac1 and gmac2 on the MT7988
SoC (BananaPi BPI-R4). Changes:
diff --git a/patches/linux/6.18.46/0045-arm64-dts-mediatek-mt7988a-add-USXGMII-PCS-nodes.patch b/patches/linux/6.18.46/0045-arm64-dts-mediatek-mt7988a-add-USXGMII-PCS-nodes.patch
index a5d4affe0..df86aece6 100644
--- a/patches/linux/6.18.46/0045-arm64-dts-mediatek-mt7988a-add-USXGMII-PCS-nodes.patch
+++ b/patches/linux/6.18.46/0045-arm64-dts-mediatek-mt7988a-add-USXGMII-PCS-nodes.patch
@@ -1,7 +1,8 @@
From c3a1c9134ffd977fde5029ade219b2264be78b6e Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Mon, 6 Apr 2026 14:15:56 +0200
-Subject: [PATCH 45/51] arm64: dts: mediatek: mt7988a: add USXGMII PCS nodes
+Subject: [PATCH 45/64] arm64: dts: mediatek: mt7988a: add USXGMII PCS nodes
+Organization: Wires
Add device nodes for the two USXGMII subsystem blocks (usxgmiisys0 at
0x10080000 and usxgmiisys1 at 0x10081000), each referencing its clock,
diff --git a/patches/linux/6.18.46/0046-arm64-dts-mediatek-bananapi-bpi-r4-enable-SFP-ports-.patch b/patches/linux/6.18.46/0046-arm64-dts-mediatek-bananapi-bpi-r4-enable-SFP-ports-.patch
index c195e2a6d..7059cdf6a 100644
--- a/patches/linux/6.18.46/0046-arm64-dts-mediatek-bananapi-bpi-r4-enable-SFP-ports-.patch
+++ b/patches/linux/6.18.46/0046-arm64-dts-mediatek-bananapi-bpi-r4-enable-SFP-ports-.patch
@@ -1,8 +1,9 @@
From 7e489d0c99259d17b6dd92d892afde4193d54efe Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Mon, 6 Apr 2026 14:16:11 +0200
-Subject: [PATCH 46/51] arm64: dts: mediatek: bananapi-bpi-r4: enable SFP+
+Subject: [PATCH 46/64] arm64: dts: mediatek: bananapi-bpi-r4: enable SFP+
ports and WPS button
+Organization: Wires
Enable the SFP+ cages wired to gmac1 and gmac2. The USXGMII PCS nodes
and xfi_tphy SerDes are wired up in mt7988a.dtsi; only status = "okay"
diff --git a/patches/linux/6.18.46/0047-net-phy-sfp-add-OEM-SFP-10G-T-I-quirk.patch b/patches/linux/6.18.46/0047-net-phy-sfp-add-OEM-SFP-10G-T-I-quirk.patch
index 042ed6da2..a4501dc83 100644
--- a/patches/linux/6.18.46/0047-net-phy-sfp-add-OEM-SFP-10G-T-I-quirk.patch
+++ b/patches/linux/6.18.46/0047-net-phy-sfp-add-OEM-SFP-10G-T-I-quirk.patch
@@ -1,10 +1,11 @@
From 2c62214c6d20bd98ebb4096f65e4c6dbff4796d0 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Tue, 7 Apr 2026 07:34:52 +0200
-Subject: [PATCH 47/51] net: phy: sfp: add OEM SFP-10G-T-I quirk
+Subject: [PATCH 47/64] net: phy: sfp: add OEM SFP-10G-T-I quirk
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
The industrial-temperature variant of the OEM SFP-10G-T copper module
reports vendor PN "SFP-10G-T-I". Unlike the base "SFP-10G-T" which is a
diff --git a/patches/linux/6.18.46/0048-net-dsa-mv88e6xxx-Trap-PTP-frames-on-timestamping-po.patch b/patches/linux/6.18.46/0048-net-dsa-mv88e6xxx-Trap-PTP-frames-on-timestamping-po.patch
index 5f35c1377..2bd5a1f41 100644
--- a/patches/linux/6.18.46/0048-net-dsa-mv88e6xxx-Trap-PTP-frames-on-timestamping-po.patch
+++ b/patches/linux/6.18.46/0048-net-dsa-mv88e6xxx-Trap-PTP-frames-on-timestamping-po.patch
@@ -1,8 +1,9 @@
From 4519c34f0aa0fac92c47f13523c11134d4dbf83f Mon Sep 17 00:00:00 2001
From: Tobias Waldekranz
Date: Fri, 17 Apr 2026 09:13:04 +0000
-Subject: [PATCH 48/51] net: dsa: mv88e6xxx: Trap PTP frames on timestamping
+Subject: [PATCH 48/64] net: dsa: mv88e6xxx: Trap PTP frames on timestamping
ports, on 6393X
+Organization: Wires
Similar to the Peridot (6390), the designation of PTP frames as
management (and the destination port) must be explicitly
diff --git a/patches/linux/6.18.46/0049-wifi-mt76-mt7615-add-MODULE_DEVICE_TABLE-for-mt7622-.patch b/patches/linux/6.18.46/0049-wifi-mt76-mt7615-add-MODULE_DEVICE_TABLE-for-mt7622-.patch
index 4dc921e55..e3b836475 100644
--- a/patches/linux/6.18.46/0049-wifi-mt76-mt7615-add-MODULE_DEVICE_TABLE-for-mt7622-.patch
+++ b/patches/linux/6.18.46/0049-wifi-mt76-mt7615-add-MODULE_DEVICE_TABLE-for-mt7622-.patch
@@ -1,8 +1,9 @@
From bd2d7c32a849c3aae185d6480b8331a53523bd52 Mon Sep 17 00:00:00 2001
From: Joachim Wiberg
Date: Tue, 28 Apr 2026 15:30:01 +0200
-Subject: [PATCH 49/51] wifi: mt76: mt7615: add MODULE_DEVICE_TABLE for mt7622
+Subject: [PATCH 49/64] wifi: mt76: mt7615: add MODULE_DEVICE_TABLE for mt7622
wmac
+Organization: Wires
Without MODULE_DEVICE_TABLE(of, ...) the OF compatible alias is never
exported to modules.alias, so udev cannot autoload mt7615e when the
diff --git a/patches/linux/6.18.46/0050-PCI-mediatek-gen3-Fix-PERST-control-timing-during-sy.patch b/patches/linux/6.18.46/0050-PCI-mediatek-gen3-Fix-PERST-control-timing-during-sy.patch
index 71a516ade..6e9013492 100644
--- a/patches/linux/6.18.46/0050-PCI-mediatek-gen3-Fix-PERST-control-timing-during-sy.patch
+++ b/patches/linux/6.18.46/0050-PCI-mediatek-gen3-Fix-PERST-control-timing-during-sy.patch
@@ -1,11 +1,12 @@
From cfe3cae54505d0b52f2bd314ed3c6492f4a8e0a7 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Wed, 22 Apr 2026 10:24:43 +0200
-Subject: [PATCH 50/51] PCI: mediatek-gen3: Fix PERST# control timing during
+Subject: [PATCH 50/64] PCI: mediatek-gen3: Fix PERST# control timing during
system startup
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
Some of MediaTek's chips (mt7986 amongst them) stop generating REFCLK
if the PCIE_PHY_RSTB signal of the PCIe controller is asserted.
diff --git a/patches/linux/6.18.46/0051-net-dsa-mv88e6xxx-Derive-LED-names-from-device-name.patch b/patches/linux/6.18.46/0051-net-dsa-mv88e6xxx-Derive-LED-names-from-device-name.patch
index 554e79366..e918b35c1 100644
--- a/patches/linux/6.18.46/0051-net-dsa-mv88e6xxx-Derive-LED-names-from-device-name.patch
+++ b/patches/linux/6.18.46/0051-net-dsa-mv88e6xxx-Derive-LED-names-from-device-name.patch
@@ -1,10 +1,11 @@
From cbc7109adb79cf7e1f20e1e93421511a93ab9e05 Mon Sep 17 00:00:00 2001
From: Mattias Walström
Date: Wed, 12 Aug 2026 10:08:53 +0200
-Subject: [PATCH 51/51] net: dsa: mv88e6xxx: Derive LED names from device name
+Subject: [PATCH 51/64] net: dsa: mv88e6xxx: Derive LED names from device name
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
+Organization: Wires
LED devices were named ":0:0", e.g.
"mv88e6390:01:00:port:lednum". Since chip->info->name is the model name, two
diff --git a/patches/linux/6.18.46/0052-phy-sparx5-serdes-make-it-selectable-for-ARCH_LAN969.patch b/patches/linux/6.18.46/0052-phy-sparx5-serdes-make-it-selectable-for-ARCH_LAN969.patch
new file mode 100644
index 000000000..fecb3e8db
--- /dev/null
+++ b/patches/linux/6.18.46/0052-phy-sparx5-serdes-make-it-selectable-for-ARCH_LAN969.patch
@@ -0,0 +1,33 @@
+From 65ba23bcd8ecebee5cf2a52f09aa617362554b78 Mon Sep 17 00:00:00 2001
+From: Robert Marko
+Date: Fri, 31 Oct 2025 13:18:12 +0100
+Subject: [PATCH 52/64] phy: sparx5-serdes: make it selectable for ARCH_LAN969X
+Organization: Wires
+
+LAN969x uses the SparX-5 SERDES driver, so make it selectable for
+ARCH_LAN969X.
+
+Reviewed-by: Daniel Machon
+Signed-off-by: Robert Marko
+Tested-by: Gabor Juhos
+Tested-by: Vladimir Oltean
+Link: https://patch.msgid.link/20251031121834.665987-1-robert.marko@sartura.hr
+Signed-off-by: Vinod Koul
+(cherry picked from commit d543d3eb06873f0ab8edb0d1f8364e9af93544a0)
+---
+ drivers/phy/microchip/Kconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/phy/microchip/Kconfig b/drivers/phy/microchip/Kconfig
+index 2f0045e874ac..2e6d1224711e 100644
+--- a/drivers/phy/microchip/Kconfig
++++ b/drivers/phy/microchip/Kconfig
+@@ -6,7 +6,7 @@
+ config PHY_SPARX5_SERDES
+ tristate "Microchip Sparx5 SerDes PHY driver"
+ select GENERIC_PHY
+- depends on ARCH_SPARX5 || COMPILE_TEST
++ depends on ARCH_SPARX5 || ARCH_LAN969X || COMPILE_TEST
+ depends on OF
+ depends on HAS_IOMEM
+ help
diff --git a/patches/linux/6.18.46/0053-net-sparx5-fix-wrong-chip-ids-for-TSN-SKUs.patch b/patches/linux/6.18.46/0053-net-sparx5-fix-wrong-chip-ids-for-TSN-SKUs.patch
new file mode 100644
index 000000000..43bb11a5b
--- /dev/null
+++ b/patches/linux/6.18.46/0053-net-sparx5-fix-wrong-chip-ids-for-TSN-SKUs.patch
@@ -0,0 +1,53 @@
+From 37170ce9154fe02f4b7c32dc598a8588a863723d Mon Sep 17 00:00:00 2001
+From: Daniel Machon
+Date: Wed, 6 May 2026 09:25:38 +0200
+Subject: [PATCH 53/64] net: sparx5: fix wrong chip ids for TSN SKUs
+Organization: Wires
+
+The TSN SKUs in enum spx5_target_chiptype have incorrect IDs:
+
+ SPX5_TARGET_CT_7546TSN = 0x47546,
+ SPX5_TARGET_CT_7549TSN = 0x47549,
+ SPX5_TARGET_CT_7552TSN = 0x47552,
+ SPX5_TARGET_CT_7556TSN = 0x47556,
+ SPX5_TARGET_CT_7558TSN = 0x47558,
+
+The value read back from the chip is GCB_CHIP_ID_PART_ID, which is a
+GENMASK(27, 12) field, i.e. at most 16 bits wide. It can never match
+these IDs, so probing a TSN part fails with a "Target not supported"
+error.
+
+Fix the enum to use the actual 16-bit part IDs returned by the
+hardware: 0x0546, 0x0549, 0x0552, 0x0556 and 0x0558.
+
+Reported-by: Andrew Lunn
+Fixes: 3cfa11bac9bb ("net: sparx5: add the basic sparx5 driver")
+Signed-off-by: Daniel Machon
+Link: https://patch.msgid.link/20260506-misc-fixes-sparx5-lan969x-v2-3-fb236aa96908@microchip.com
+Signed-off-by: Jakub Kicinski
+(cherry picked from commit b131dc93f7bf1b1461f5bde0c06c4c2384aa5b58)
+---
+ drivers/net/ethernet/microchip/sparx5/sparx5_main.h | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+index fe7d8bcc0cd9..2f1b50ba8ad3 100644
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+@@ -31,11 +31,11 @@ enum spx5_target_chiptype {
+ SPX5_TARGET_CT_7552 = 0x7552, /* SparX-5-128 Enterprise */
+ SPX5_TARGET_CT_7556 = 0x7556, /* SparX-5-160 Enterprise */
+ SPX5_TARGET_CT_7558 = 0x7558, /* SparX-5-200 Enterprise */
+- SPX5_TARGET_CT_7546TSN = 0x47546, /* SparX-5-64i Industrial */
+- SPX5_TARGET_CT_7549TSN = 0x47549, /* SparX-5-90i Industrial */
+- SPX5_TARGET_CT_7552TSN = 0x47552, /* SparX-5-128i Industrial */
+- SPX5_TARGET_CT_7556TSN = 0x47556, /* SparX-5-160i Industrial */
+- SPX5_TARGET_CT_7558TSN = 0x47558, /* SparX-5-200i Industrial */
++ SPX5_TARGET_CT_7546TSN = 0x0546, /* SparX-5-64i Industrial */
++ SPX5_TARGET_CT_7549TSN = 0x0549, /* SparX-5-90i Industrial */
++ SPX5_TARGET_CT_7552TSN = 0x0552, /* SparX-5-128i Industrial */
++ SPX5_TARGET_CT_7556TSN = 0x0556, /* SparX-5-160i Industrial */
++ SPX5_TARGET_CT_7558TSN = 0x0558, /* SparX-5-200i Industrial */
+ SPX5_TARGET_CT_LAN9694 = 0x9694, /* lan969x-40 */
+ SPX5_TARGET_CT_LAN9691VAO = 0x9691, /* lan969x-40-VAO */
+ SPX5_TARGET_CT_LAN9694TSN = 0x9695, /* lan969x-40-TSN */
diff --git a/patches/linux/6.18.46/0054-net-sparx5-configure-serdes-for-1000BASE-X-in-sparx5.patch b/patches/linux/6.18.46/0054-net-sparx5-configure-serdes-for-1000BASE-X-in-sparx5.patch
new file mode 100644
index 000000000..dc4c10bb7
--- /dev/null
+++ b/patches/linux/6.18.46/0054-net-sparx5-configure-serdes-for-1000BASE-X-in-sparx5.patch
@@ -0,0 +1,44 @@
+From a1a9f763c4760918d035ead954de9a768681e8df Mon Sep 17 00:00:00 2001
+From: Daniel Machon
+Date: Wed, 6 May 2026 09:25:39 +0200
+Subject: [PATCH 54/64] net: sparx5: configure serdes for 1000BASE-X in
+ sparx5_port_init()
+Organization: Wires
+
+sparx5_port_init() only invokes sparx5_serdes_set() and the associated
+shadow-device enable and low-speed device switch for SGMII and QSGMII.
+On any port with a high-speed primary device (DEV5G/DEV10G/DEV25G)
+configured for 1000BASE-X the serdes is therefore left uninitialized,
+the DEV2G5 shadow is never enabled, and the port stays pointed at its
+high-speed device rather than the DEV2G5. The PCS1G block looks
+healthy in isolation, but no frames reach the link partner.
+
+Add 1000BASE-X to the check so the same three steps run.
+
+Note: the same issue might apply to 2500BASE-X, but that will,
+eventually, be addressed in a separate commit.
+
+Reported-by: Andrew Lunn
+Fixes: 946e7fd5053a ("net: sparx5: add port module support")
+Signed-off-by: Daniel Machon
+Link: https://patch.msgid.link/20260506-misc-fixes-sparx5-lan969x-v2-4-fb236aa96908@microchip.com
+Signed-off-by: Jakub Kicinski
+(cherry picked from commit 41ae14071cd7f6a7770e2fe1f8a0859d4c2c6ba4)
+---
+ drivers/net/ethernet/microchip/sparx5/sparx5_port.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
+index 04bc8fffaf96..62c49893de3c 100644
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_port.c
+@@ -1128,7 +1128,8 @@ int sparx5_port_init(struct sparx5 *sparx5,
+ DEV2G5_PCS1G_SD_CFG(port->portno));
+
+ if (conf->portmode == PHY_INTERFACE_MODE_QSGMII ||
+- conf->portmode == PHY_INTERFACE_MODE_SGMII) {
++ conf->portmode == PHY_INTERFACE_MODE_SGMII ||
++ conf->portmode == PHY_INTERFACE_MODE_1000BASEX) {
+ err = sparx5_serdes_set(sparx5, port, conf);
+ if (err)
+ return err;
diff --git a/patches/linux/6.18.46/0055-dt-bindings-mmc-atmel-sama5d2-sdhci-add-microchip-la.patch b/patches/linux/6.18.46/0055-dt-bindings-mmc-atmel-sama5d2-sdhci-add-microchip-la.patch
new file mode 100644
index 000000000..0e759348e
--- /dev/null
+++ b/patches/linux/6.18.46/0055-dt-bindings-mmc-atmel-sama5d2-sdhci-add-microchip-la.patch
@@ -0,0 +1,29 @@
+From 34c5de04a922e37c9caecebf73437c929f5b513b Mon Sep 17 00:00:00 2001
+From: Joachim Wiberg
+Date: Wed, 19 Aug 2026 11:35:29 +0200
+Subject: [PATCH 55/64] dt-bindings: mmc: atmel,sama5d2-sdhci: add
+ microchip,lan969x-sdhci
+Organization: Wires
+
+The LAN969x SDMMC controller has its own base clock divider and, unlike
+the SAMA5D2 and SAM9X60 variants, supports HS200 and caps SDR104 at
+100 MHz. It therefore needs a compatible of its own rather than a
+fallback to microchip,sam9x60-sdhci.
+
+Signed-off-by: Joachim Wiberg
+---
+ Documentation/devicetree/bindings/mmc/atmel,sama5d2-sdhci.yaml | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Documentation/devicetree/bindings/mmc/atmel,sama5d2-sdhci.yaml b/Documentation/devicetree/bindings/mmc/atmel,sama5d2-sdhci.yaml
+index ba75623b7778..860e6736e2eb 100644
+--- a/Documentation/devicetree/bindings/mmc/atmel,sama5d2-sdhci.yaml
++++ b/Documentation/devicetree/bindings/mmc/atmel,sama5d2-sdhci.yaml
+@@ -18,6 +18,7 @@ properties:
+ oneOf:
+ - enum:
+ - atmel,sama5d2-sdhci
++ - microchip,lan969x-sdhci
+ - microchip,sam9x60-sdhci
+ - items:
+ - enum:
diff --git a/patches/linux/6.18.46/0056-mmc-sdhci-of-at91-add-LAN969x-support.patch b/patches/linux/6.18.46/0056-mmc-sdhci-of-at91-add-LAN969x-support.patch
new file mode 100644
index 000000000..4510e8820
--- /dev/null
+++ b/patches/linux/6.18.46/0056-mmc-sdhci-of-at91-add-LAN969x-support.patch
@@ -0,0 +1,111 @@
+From 54a84169810b3650c67f51c9b71a4eeb54e9085b Mon Sep 17 00:00:00 2001
+From: Joachim Wiberg
+Date: Wed, 19 Aug 2026 11:35:44 +0200
+Subject: [PATCH 56/64] mmc: sdhci-of-at91: add LAN969x support
+Organization: Wires
+
+The LAN969x SDMMC controller is an Atmel SDMMC IP block, but the driver
+has no compatible for it, so the eMMC on LAN969x boards never probes.
+
+Three of the driver's assumptions do not hold on LAN969x: SDR104 is
+capped at 100 MHz rather than 120 MHz, HS200 works, and the hclock,
+multclk and baseclk must stay enabled across runtime suspend. Move all
+three to the SoC data so each variant states its own behaviour, and add
+LAN969x.
+
+Signed-off-by: Joachim Wiberg
+---
+ drivers/mmc/host/sdhci-of-at91.c | 34 ++++++++++++++++++++++++++------
+ 1 file changed, 28 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
+index 7c4ac65f247d..5dcb88cba0d9 100644
+--- a/drivers/mmc/host/sdhci-of-at91.c
++++ b/drivers/mmc/host/sdhci-of-at91.c
+@@ -39,6 +39,9 @@ struct sdhci_at91_soc_data {
+ const struct sdhci_pltfm_data *pdata;
+ bool baseclk_is_generated_internally;
+ unsigned int divider_for_baseclk;
++ unsigned int max_sdr104_clk;
++ bool hs200_broken;
++ bool pm_runtime_disable_clks;
+ };
+
+ struct sdhci_at91_priv {
+@@ -149,17 +152,31 @@ static const struct sdhci_pltfm_data sdhci_sama5d2_pdata = {
+ static const struct sdhci_at91_soc_data soc_data_sama5d2 = {
+ .pdata = &sdhci_sama5d2_pdata,
+ .baseclk_is_generated_internally = false,
++ .max_sdr104_clk = 120000000,
++ .hs200_broken = true,
++ .pm_runtime_disable_clks = true,
+ };
+
+ static const struct sdhci_at91_soc_data soc_data_sam9x60 = {
+ .pdata = &sdhci_sama5d2_pdata,
+ .baseclk_is_generated_internally = true,
+ .divider_for_baseclk = 2,
++ .max_sdr104_clk = 120000000,
++ .hs200_broken = true,
++ .pm_runtime_disable_clks = true,
++};
++
++static const struct sdhci_at91_soc_data soc_data_lan969x = {
++ .pdata = &sdhci_sama5d2_pdata,
++ .baseclk_is_generated_internally = true,
++ .divider_for_baseclk = 2,
++ .max_sdr104_clk = 100000000,
+ };
+
+ static const struct of_device_id sdhci_at91_dt_match[] = {
+ { .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 },
+ { .compatible = "microchip,sam9x60-sdhci", .data = &soc_data_sam9x60 },
++ { .compatible = "microchip,lan969x-sdhci", .data = &soc_data_lan969x },
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, sdhci_at91_dt_match);
+@@ -216,7 +233,7 @@ static int sdhci_at91_set_clks_presets(struct device *dev)
+ preset_div = DIV_ROUND_UP(gck_rate, 100000000) - 1;
+ writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
+ host->ioaddr + SDHCI_PRESET_FOR_SDR50);
+- preset_div = DIV_ROUND_UP(gck_rate, 120000000) - 1;
++ preset_div = DIV_ROUND_UP(gck_rate, priv->soc_data->max_sdr104_clk) - 1;
+ writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div,
+ host->ioaddr + SDHCI_PRESET_FOR_SDR104);
+ preset_div = DIV_ROUND_UP(gck_rate, 50000000) - 1;
+@@ -254,9 +271,11 @@ static int sdhci_at91_runtime_suspend(struct device *dev)
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
+- clk_disable_unprepare(priv->gck);
+- clk_disable_unprepare(priv->hclock);
+- clk_disable_unprepare(priv->mainck);
++ if (priv->soc_data->pm_runtime_disable_clks) {
++ clk_disable_unprepare(priv->gck);
++ clk_disable_unprepare(priv->hclock);
++ clk_disable_unprepare(priv->mainck);
++ }
+
+ return 0;
+ }
+@@ -277,6 +296,9 @@ static int sdhci_at91_runtime_resume(struct device *dev)
+ goto out;
+ }
+
++ if (!priv->soc_data->pm_runtime_disable_clks)
++ goto out;
++
+ ret = clk_prepare_enable(priv->mainck);
+ if (ret) {
+ dev_err(dev, "can't enable mainck\n");
+@@ -370,8 +392,8 @@ static int sdhci_at91_probe(struct platform_device *pdev)
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+
+- /* HS200 is broken at this moment */
+- host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
++ if (priv->soc_data->hs200_broken)
++ host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
+
+ ret = sdhci_add_host(host);
+ if (ret)
diff --git a/patches/linux/6.18.46/0057-mmc-sdhci-of-at91-stop-SDCLK-on-reset-and-add-eMMC-h.patch b/patches/linux/6.18.46/0057-mmc-sdhci-of-at91-stop-SDCLK-on-reset-and-add-eMMC-h.patch
new file mode 100644
index 000000000..2171881ec
--- /dev/null
+++ b/patches/linux/6.18.46/0057-mmc-sdhci-of-at91-stop-SDCLK-on-reset-and-add-eMMC-h.patch
@@ -0,0 +1,142 @@
+From e3137466bb1335efc719dba3841319438f4bba26 Mon Sep 17 00:00:00 2001
+From: Joachim Wiberg
+Date: Wed, 19 Aug 2026 11:37:48 +0200
+Subject: [PATCH 57/64] mmc: sdhci-of-at91: stop SDCLK on reset and add eMMC
+ hardware reset
+Organization: Wires
+
+The controller is reset, and its signaling mode changed, with SDCLK
+still running. Both require the clock to be stopped, otherwise the
+block can be left in a state where transfers time out.
+
+Stop SDCLK around both operations and restore it afterwards. Also wire
+up .hw_reset so the MMC core can pulse the eMMC reset line through
+MC1R.RSTN, and reset the block on probe for LAN969x, where the
+bootloader loads the kernel from eMMC and hands over a running
+controller.
+
+Signed-off-by: Joachim Wiberg
+---
+ drivers/mmc/host/sdhci-of-at91.c | 50 ++++++++++++++++++++++++++++++++
+ 1 file changed, 50 insertions(+)
+
+diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
+index 5dcb88cba0d9..6a9e4a7fa705 100644
+--- a/drivers/mmc/host/sdhci-of-at91.c
++++ b/drivers/mmc/host/sdhci-of-at91.c
+@@ -25,6 +25,7 @@
+
+ #define SDMMC_MC1R 0x204
+ #define SDMMC_MC1R_DDR BIT(3)
++#define SDMMC_MC1R_RSTN BIT(6)
+ #define SDMMC_MC1R_FCD BIT(7)
+ #define SDMMC_CACR 0x230
+ #define SDMMC_CACR_CAPWREN BIT(0)
+@@ -42,6 +43,7 @@ struct sdhci_at91_soc_data {
+ unsigned int max_sdr104_clk;
+ bool hs200_broken;
+ bool pm_runtime_disable_clks;
++ bool reset_on_probe;
+ };
+
+ struct sdhci_at91_priv {
+@@ -103,24 +105,48 @@ static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
+ static void sdhci_at91_set_uhs_signaling(struct sdhci_host *host,
+ unsigned int timing)
+ {
++ u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ u8 mc1r;
+
++ /* SDCLK must be disabled while changing the mode */
++ if (clk & SDHCI_CLOCK_CARD_EN)
++ sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN,
++ SDHCI_CLOCK_CONTROL);
++
+ if (timing == MMC_TIMING_MMC_DDR52) {
+ mc1r = sdhci_readb(host, SDMMC_MC1R);
+ mc1r |= SDMMC_MC1R_DDR;
+ sdhci_writeb(host, mc1r, SDMMC_MC1R);
+ }
+ sdhci_set_uhs_signaling(host, timing);
++
++ if (clk & SDHCI_CLOCK_CARD_EN) {
++ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
++ sdhci_writew(host, clk | SDHCI_CLOCK_CARD_EN,
++ SDHCI_CLOCK_CONTROL);
++ }
+ }
+
+ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
+ {
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host);
++ u16 clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ unsigned int tmp;
+
++ /* SDCLK must be disabled while resetting the HW block */
++ if (clk & SDHCI_CLOCK_CARD_EN)
++ sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN,
++ SDHCI_CLOCK_CONTROL);
++
+ sdhci_reset(host, mask);
+
++ if (clk & SDHCI_CLOCK_CARD_EN) {
++ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
++ sdhci_writew(host, clk | SDHCI_CLOCK_CARD_EN,
++ SDHCI_CLOCK_CONTROL);
++ }
++
+ if ((host->mmc->caps & MMC_CAP_NONREMOVABLE)
+ || mmc_gpio_get_cd(host->mmc) >= 0)
+ sdhci_at91_set_force_card_detect(host);
+@@ -137,12 +163,30 @@ static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
+ }
+ }
+
++static void sdhci_at91_hw_reset(struct sdhci_host *host)
++{
++ u8 mc1r;
++
++ mc1r = readb(host->ioaddr + SDMMC_MC1R);
++ mc1r |= SDMMC_MC1R_RSTN;
++ writeb(mc1r, host->ioaddr + SDMMC_MC1R);
++
++ udelay(10);
++
++ mc1r &= ~SDMMC_MC1R_RSTN;
++ writeb(mc1r, host->ioaddr + SDMMC_MC1R);
++
++ /* JEDEC specifies a minimum of 200us for tRSCA (reset to command) */
++ usleep_range(200, 500);
++}
++
+ static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
+ .set_clock = sdhci_at91_set_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = sdhci_at91_reset,
+ .set_uhs_signaling = sdhci_at91_set_uhs_signaling,
+ .set_power = sdhci_set_power_and_bus_voltage,
++ .hw_reset = sdhci_at91_hw_reset,
+ };
+
+ static const struct sdhci_pltfm_data sdhci_sama5d2_pdata = {
+@@ -171,6 +215,7 @@ static const struct sdhci_at91_soc_data soc_data_lan969x = {
+ .baseclk_is_generated_internally = true,
+ .divider_for_baseclk = 2,
+ .max_sdr104_clk = 100000000,
++ .reset_on_probe = true,
+ };
+
+ static const struct of_device_id sdhci_at91_dt_match[] = {
+@@ -347,6 +392,11 @@ static int sdhci_at91_probe(struct platform_device *pdev)
+ priv = sdhci_pltfm_priv(pltfm_host);
+ priv->soc_data = soc_data;
+
++ if (soc_data->reset_on_probe) {
++ sdhci_at91_reset(host, SDHCI_RESET_ALL);
++ sdhci_at91_hw_reset(host);
++ }
++
+ priv->mainck = devm_clk_get(&pdev->dev, "baseclk");
+ if (IS_ERR(priv->mainck)) {
+ if (soc_data->baseclk_is_generated_internally)
diff --git a/patches/linux/6.18.46/0058-net-sparx5-lan969x-populate-netdev-of_node.patch b/patches/linux/6.18.46/0058-net-sparx5-lan969x-populate-netdev-of_node.patch
new file mode 100644
index 000000000..6dedcea3d
--- /dev/null
+++ b/patches/linux/6.18.46/0058-net-sparx5-lan969x-populate-netdev-of_node.patch
@@ -0,0 +1,30 @@
+From 6d2e708d45f1f1a8a187eef079b1247cf7f60a49 Mon Sep 17 00:00:00 2001
+From: Robert Marko
+Date: Mon, 10 Nov 2025 13:42:53 +0100
+Subject: [PATCH 58/64] net: sparx5/lan969x: populate netdev of_node
+Organization: Wires
+
+Populate of_node for the port netdevs, to make the individual ports
+of_nodes available in sysfs.
+
+Signed-off-by: Robert Marko
+Link: https://patch.msgid.link/20251110124342.199216-1-robert.marko@sartura.hr
+Signed-off-by: Jakub Kicinski
+(cherry picked from commit fc6aa0e470e092873eddb213d996a8beee86bf4d)
+---
+ drivers/net/ethernet/microchip/sparx5/sparx5_main.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+index 40b1bfc600a7..582145713cfd 100644
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+@@ -395,6 +395,8 @@ static int sparx5_create_port(struct sparx5 *sparx5,
+
+ spx5_port->phylink = phylink;
+
++ spx5_port->ndev->dev.of_node = spx5_port->of_node;
++
+ return 0;
+ }
+
diff --git a/patches/linux/6.18.46/0059-arm64-dts-microchip-add-LAN969x-clock-header-file.patch b/patches/linux/6.18.46/0059-arm64-dts-microchip-add-LAN969x-clock-header-file.patch
new file mode 100644
index 000000000..e9f70bb75
--- /dev/null
+++ b/patches/linux/6.18.46/0059-arm64-dts-microchip-add-LAN969x-clock-header-file.patch
@@ -0,0 +1,49 @@
+From e222fb4b440eaea1eef4522a440f965e674066fa Mon Sep 17 00:00:00 2001
+From: Robert Marko
+Date: Mon, 2 Mar 2026 12:20:11 +0100
+Subject: [PATCH 59/64] arm64: dts: microchip: add LAN969x clock header file
+Organization: Wires
+
+LAN969x uses hardware clock indexes, so document theses in a header to make
+them humanly readable.
+
+Signed-off-by: Robert Marko
+Reviewed-by: Claudiu Beznea
+Link: https://lore.kernel.org/r/20260302112153.464422-4-robert.marko@sartura.hr
+Signed-off-by: Claudiu Beznea
+(cherry picked from commit 229eeb0ad913c1bb2dd6027e5983d1e4c409abd0)
+---
+ arch/arm64/boot/dts/microchip/clk-lan9691.h | 24 +++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/microchip/clk-lan9691.h
+
+diff --git a/arch/arm64/boot/dts/microchip/clk-lan9691.h b/arch/arm64/boot/dts/microchip/clk-lan9691.h
+new file mode 100644
+index 000000000000..0f2d7a0f881e
+--- /dev/null
++++ b/arch/arm64/boot/dts/microchip/clk-lan9691.h
+@@ -0,0 +1,24 @@
++/* SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) */
++
++#ifndef _DTS_CLK_LAN9691_H
++#define _DTS_CLK_LAN9691_H
++
++#define GCK_ID_QSPI0 0
++#define GCK_ID_QSPI2 1
++#define GCK_ID_SDMMC0 2
++#define GCK_ID_SDMMC1 3
++#define GCK_ID_MCAN0 4
++#define GCK_ID_MCAN1 5
++#define GCK_ID_FLEXCOM0 6
++#define GCK_ID_FLEXCOM1 7
++#define GCK_ID_FLEXCOM2 8
++#define GCK_ID_FLEXCOM3 9
++#define GCK_ID_TIMER 10
++#define GCK_ID_USB_REFCLK 11
++
++/* Gate clocks */
++#define GCK_GATE_USB_DRD 12
++#define GCK_GATE_MCRAMC 13
++#define GCK_GATE_HMATRIX 14
++
++#endif
diff --git a/patches/linux/6.18.46/0060-arm64-dts-microchip-add-LAN969x-support.patch b/patches/linux/6.18.46/0060-arm64-dts-microchip-add-LAN969x-support.patch
new file mode 100644
index 000000000..c7fd4ba66
--- /dev/null
+++ b/patches/linux/6.18.46/0060-arm64-dts-microchip-add-LAN969x-support.patch
@@ -0,0 +1,513 @@
+From d72697a81242685f8913222a2769a183f7d8c5bb Mon Sep 17 00:00:00 2001
+From: Robert Marko
+Date: Mon, 2 Mar 2026 12:20:12 +0100
+Subject: [PATCH 60/64] arm64: dts: microchip: add LAN969x support
+Organization: Wires
+
+Add support for Microchip LAN969x switch SoC series by adding the SoC DTSI.
+
+Signed-off-by: Robert Marko
+Reviewed-by: Claudiu Beznea
+Acked-by: Daniel Machon
+Link: https://lore.kernel.org/r/20260302112153.464422-5-robert.marko@sartura.hr
+Signed-off-by: Claudiu Beznea
+(cherry picked from commit 1effec9834710ec417861634c32208edcd2fcb2a)
+---
+ arch/arm64/boot/dts/microchip/lan9691.dtsi | 488 +++++++++++++++++++++
+ 1 file changed, 488 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/microchip/lan9691.dtsi
+
+diff --git a/arch/arm64/boot/dts/microchip/lan9691.dtsi b/arch/arm64/boot/dts/microchip/lan9691.dtsi
+new file mode 100644
+index 000000000000..235e56bebbdb
+--- /dev/null
++++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
+@@ -0,0 +1,488 @@
++// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
++/*
++ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
++ */
++
++#include
++#include
++#include
++#include
++
++#include "clk-lan9691.h"
++
++/ {
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ model = "Microchip LAN969x";
++ compatible = "microchip,lan9691";
++ interrupt-parent = <&gic>;
++
++ clocks {
++ fx100_clk: fx100-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <320000000>;
++ };
++
++ cpu_clk: cpu-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <1000000000>;
++ };
++
++ ddr_clk: ddr-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <600000000>;
++ };
++
++ fabric_clk: fabric-clk {
++ compatible = "fixed-clock";
++ #clock-cells = <0>;
++ clock-frequency = <250000000>;
++ };
++ };
++
++ cpus {
++ #address-cells = <2>;
++ #size-cells = <0>;
++
++ cpu0: cpu@0 {
++ compatible = "arm,cortex-a53";
++ device_type = "cpu";
++ reg = <0x0 0x0>;
++ next-level-cache = <&l2_0>;
++ };
++
++ l2_0: l2-cache {
++ compatible = "cache";
++ cache-level = <2>;
++ cache-unified;
++ };
++ };
++
++ psci {
++ compatible = "arm,psci-1.0";
++ method = "smc";
++ };
++
++ pmu {
++ compatible = "arm,cortex-a53-pmu";
++ interrupts = ;
++ };
++
++ timer {
++ compatible = "arm,armv8-timer";
++ interrupts = , /* Secure Phys IRQ */
++ , /* Non-secure Phys IRQ */
++ , /* Virt IRQ */
++ ; /* Hyp IRQ */
++ };
++
++ axi: axi {
++ compatible = "simple-bus";
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges;
++
++ usb: usb@300000 {
++ compatible = "microchip,lan9691-dwc3", "snps,dwc3";
++ reg = <0x300000 0x80000>;
++ interrupts = ;
++ clocks = <&clks GCK_GATE_USB_DRD>,
++ <&clks GCK_ID_USB_REFCLK>;
++ clock-names = "bus_early", "ref";
++ assigned-clocks = <&clks GCK_ID_USB_REFCLK>;
++ assigned-clock-rates = <60000000>;
++ maximum-speed = "high-speed";
++ dr_mode = "host";
++ status = "disabled";
++ };
++
++ flx0: flexcom@e0040000 {
++ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
++ reg = <0xe0040000 0x100>;
++ ranges = <0x0 0xe0040000 0x800>;
++ clocks = <&clks GCK_ID_FLEXCOM0>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ status = "disabled";
++
++ usart0: serial@200 {
++ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
++ reg = <0x200 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
++ <&dma AT91_XDMAC_DT_PERID(2)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "usart";
++ atmel,fifo-size = <32>;
++ atmel,usart-mode = ;
++ status = "disabled";
++ };
++
++ spi0: spi@400 {
++ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
++ reg = <0x400 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
++ <&dma AT91_XDMAC_DT_PERID(2)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "spi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ atmel,fifo-size = <32>;
++ status = "disabled";
++ };
++
++ i2c0: i2c@600 {
++ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
++ reg = <0x600 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
++ <&dma AT91_XDMAC_DT_PERID(2)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ };
++
++ flx1: flexcom@e0044000 {
++ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
++ reg = <0xe0044000 0x100>;
++ ranges = <0x0 0xe0044000 0x800>;
++ clocks = <&clks GCK_ID_FLEXCOM1>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ status = "disabled";
++
++ usart1: serial@200 {
++ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
++ reg = <0x200 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
++ <&dma AT91_XDMAC_DT_PERID(2)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "usart";
++ atmel,fifo-size = <32>;
++ atmel,usart-mode = ;
++ status = "disabled";
++ };
++
++ spi1: spi@400 {
++ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
++ reg = <0x400 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
++ <&dma AT91_XDMAC_DT_PERID(2)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "spi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ atmel,fifo-size = <32>;
++ status = "disabled";
++ };
++
++ i2c1: i2c@600 {
++ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
++ reg = <0x600 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(3)>,
++ <&dma AT91_XDMAC_DT_PERID(2)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ };
++
++ trng: rng@e0048000 {
++ compatible = "microchip,lan9691-trng", "atmel,at91sam9g45-trng";
++ reg = <0xe0048000 0x100>;
++ clocks = <&fabric_clk>;
++ status = "disabled";
++ };
++
++ aes: crypto@e004c000 {
++ compatible = "microchip,lan9691-aes", "atmel,at91sam9g46-aes";
++ reg = <0xe004c000 0x100>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(12)>,
++ <&dma AT91_XDMAC_DT_PERID(13)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "aes_clk";
++ status = "disabled";
++ };
++
++ flx2: flexcom@e0060000 {
++ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
++ reg = <0xe0060000 0x100>;
++ ranges = <0x0 0xe0060000 0x800>;
++ clocks = <&clks GCK_ID_FLEXCOM2>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ status = "disabled";
++
++ usart2: serial@200 {
++ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
++ reg = <0x200 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
++ <&dma AT91_XDMAC_DT_PERID(6)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "usart";
++ atmel,fifo-size = <32>;
++ atmel,usart-mode = ;
++ status = "disabled";
++ };
++
++ spi2: spi@400 {
++ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
++ reg = <0x400 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
++ <&dma AT91_XDMAC_DT_PERID(6)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "spi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ atmel,fifo-size = <32>;
++ status = "disabled";
++ };
++
++ i2c2: i2c@600 {
++ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
++ reg = <0x600 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(7)>,
++ <&dma AT91_XDMAC_DT_PERID(6)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ };
++
++ flx3: flexcom@e0064000 {
++ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
++ reg = <0xe0064000 0x100>;
++ ranges = <0x0 0xe0064000 0x800>;
++ clocks = <&clks GCK_ID_FLEXCOM3>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ status = "disabled";
++
++ usart3: serial@200 {
++ compatible = "microchip,lan9691-usart", "atmel,at91sam9260-usart";
++ reg = <0x200 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
++ <&dma AT91_XDMAC_DT_PERID(8)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "usart";
++ atmel,fifo-size = <32>;
++ atmel,usart-mode = ;
++ status = "disabled";
++ };
++
++ spi3: spi@400 {
++ compatible = "microchip,lan9691-spi", "atmel,at91rm9200-spi";
++ reg = <0x400 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
++ <&dma AT91_XDMAC_DT_PERID(8)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ clock-names = "spi_clk";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ atmel,fifo-size = <32>;
++ status = "disabled";
++ };
++
++ i2c3: i2c@600 {
++ compatible = "microchip,lan9691-i2c", "microchip,sam9x60-i2c";
++ reg = <0x600 0x200>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(9)>,
++ <&dma AT91_XDMAC_DT_PERID(8)>;
++ dma-names = "tx", "rx";
++ clocks = <&fabric_clk>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++ };
++ };
++
++ dma: dma-controller@e0068000 {
++ compatible = "microchip,lan9691-dma", "microchip,sama7g5-dma";
++ reg = <0xe0068000 0x1000>;
++ interrupts = ;
++ dma-channels = <16>;
++ #dma-cells = <1>;
++ clocks = <&fabric_clk>;
++ clock-names = "dma_clk";
++ };
++
++ sha: crypto@e006c000 {
++ compatible = "microchip,lan9691-sha", "atmel,at91sam9g46-sha";
++ reg = <0xe006c000 0xec>;
++ interrupts = ;
++ dmas = <&dma AT91_XDMAC_DT_PERID(14)>;
++ dma-names = "tx";
++ clocks = <&fabric_clk>;
++ clock-names = "sha_clk";
++ status = "disabled";
++ };
++
++ timer: timer@e008c000 {
++ compatible = "snps,dw-apb-timer";
++ reg = <0xe008c000 0x400>;
++ clocks = <&fabric_clk>;
++ clock-names = "timer";
++ interrupts = ;
++ status = "disabled";
++ };
++
++ watchdog: watchdog@e0090000 {
++ compatible = "snps,dw-wdt";
++ reg = <0xe0090000 0x1000>;
++ interrupts = ;
++ clocks = <&fabric_clk>;
++ };
++
++ cpu_ctrl: syscon@e00c0000 {
++ compatible = "microchip,lan966x-cpu-syscon", "syscon";
++ reg = <0xe00c0000 0x350>;
++ };
++
++ switch: switch@e00c0000 {
++ compatible = "microchip,lan9691-switch";
++ reg = <0xe00c0000 0x0010000>,
++ <0xe2010000 0x1410000>;
++ reg-names = "cpu", "devices";
++ interrupt-names = "xtr", "fdma", "ptp";
++ interrupts = ,
++ ,
++ ;
++ resets = <&reset 0>;
++ reset-names = "switch";
++ status = "disabled";
++ };
++
++ clks: clock-controller@e00c00b4 {
++ compatible = "microchip,lan9691-gck";
++ reg = <0xe00c00b4 0x30>, <0xe00c0308 0x4>;
++ #clock-cells = <1>;
++ clocks = <&cpu_clk>, <&ddr_clk>, <&fx100_clk>;
++ clock-names = "cpu", "ddr", "sys";
++ };
++
++ reset: reset-controller@e201000c {
++ compatible = "microchip,lan9691-switch-reset",
++ "microchip,lan966x-switch-reset";
++ reg = <0xe201000c 0x4>;
++ reg-names = "gcb";
++ #reset-cells = <1>;
++ cpu-syscon = <&cpu_ctrl>;
++ };
++
++ gpio: pinctrl@e20100d4 {
++ compatible = "microchip,lan9691-pinctrl";
++ reg = <0xe20100d4 0xd4>,
++ <0xe2010370 0xa8>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ gpio-ranges = <&gpio 0 0 66>;
++ interrupt-controller;
++ interrupts = ;
++ #interrupt-cells = <2>;
++ };
++
++ mdio0: mdio@e20101a8 {
++ compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
++ reg = <0xe20101a8 0x24>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clocks = <&fx100_clk>;
++ status = "disabled";
++ };
++
++ mdio1: mdio@e20101cc {
++ compatible = "microchip,lan9691-miim", "mscc,ocelot-miim";
++ reg = <0xe20101cc 0x24>;
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clocks = <&fx100_clk>;
++ status = "disabled";
++ };
++
++ sgpio: gpio@e2010230 {
++ compatible = "microchip,lan9691-sgpio", "microchip,sparx5-sgpio";
++ reg = <0xe2010230 0x118>;
++ clocks = <&fx100_clk>;
++ resets = <&reset 0>;
++ reset-names = "switch";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "disabled";
++
++ sgpio_in: gpio@0 {
++ compatible = "microchip,lan9691-sgpio-bank",
++ "microchip,sparx5-sgpio-bank";
++ reg = <0>;
++ gpio-controller;
++ #gpio-cells = <3>;
++ interrupts = ;
++ interrupt-controller;
++ #interrupt-cells = <3>;
++ };
++
++ sgpio_out: gpio@1 {
++ compatible = "microchip,lan9691-sgpio-bank",
++ "microchip,sparx5-sgpio-bank";
++ reg = <1>;
++ gpio-controller;
++ #gpio-cells = <3>;
++ };
++ };
++
++ tmon: hwmon@e2020100 {
++ compatible = "microchip,lan9691-temp", "microchip,sparx5-temp";
++ reg = <0xe2020100 0xc>;
++ clocks = <&fx100_clk>;
++ #thermal-sensor-cells = <0>;
++ };
++
++ serdes: serdes@e3410000 {
++ compatible = "microchip,lan9691-serdes";
++ reg = <0xe3410000 0x150000>;
++ #phy-cells = <1>;
++ clocks = <&fabric_clk>;
++ };
++
++ gic: interrupt-controller@e8c11000 {
++ compatible = "arm,gic-400";
++ reg = <0xe8c11000 0x1000>, /* Distributor GICD_ */
++ <0xe8c12000 0x2000>, /* CPU interface GICC_ */
++ <0xe8c14000 0x2000>, /* Virt interface control */
++ <0xe8c16000 0x2000>; /* Virt CPU interface */
++ #interrupt-cells = <3>;
++ interrupt-controller;
++ interrupts = ;
++ };
++ };
++};
diff --git a/patches/linux/6.18.46/0061-arm64-dts-microchip-add-EV23X71A-board.patch b/patches/linux/6.18.46/0061-arm64-dts-microchip-add-EV23X71A-board.patch
new file mode 100644
index 000000000..47231911e
--- /dev/null
+++ b/patches/linux/6.18.46/0061-arm64-dts-microchip-add-EV23X71A-board.patch
@@ -0,0 +1,793 @@
+From 8f86e07b4ced078e3785534b2da159bd79765c22 Mon Sep 17 00:00:00 2001
+From: Robert Marko
+Date: Mon, 2 Mar 2026 12:20:14 +0100
+Subject: [PATCH 61/64] arm64: dts: microchip: add EV23X71A board
+Organization: Wires
+
+Microchip EV23X71A is an LAN9696 based evaluation board.
+
+Signed-off-by: Robert Marko
+Reviewed-by: Claudiu Beznea
+Acked-by: Daniel Machon
+Tested-by: Daniel Machon
+Link: https://lore.kernel.org/r/20260302112153.464422-7-robert.marko@sartura.hr
+Signed-off-by: Claudiu Beznea
+(cherry picked from commit 711cca0f1cfef57018654b969da4041c2bab68d3)
+---
+ arch/arm64/boot/dts/microchip/Makefile | 1 +
+ .../boot/dts/microchip/lan9696-ev23x71a.dts | 756 ++++++++++++++++++
+ 2 files changed, 757 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
+
+diff --git a/arch/arm64/boot/dts/microchip/Makefile b/arch/arm64/boot/dts/microchip/Makefile
+index c6e0313eea0f..09d16fc1ce9a 100644
+--- a/arch/arm64/boot/dts/microchip/Makefile
++++ b/arch/arm64/boot/dts/microchip/Makefile
+@@ -1,4 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
++dtb-$(CONFIG_ARCH_LAN969X) += lan9696-ev23x71a.dtb
+ dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb125.dtb
+ dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb134.dtb sparx5_pcb134_emmc.dtb
+ dtb-$(CONFIG_ARCH_SPARX5) += sparx5_pcb135.dtb sparx5_pcb135_emmc.dtb
+diff --git a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
+new file mode 100644
+index 000000000000..4012ea7d07bb
+--- /dev/null
++++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
+@@ -0,0 +1,756 @@
++// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
++/*
++ * Copyright (c) 2025 Microchip Technology Inc. and its subsidiaries.
++ */
++
++/dts-v1/;
++
++#include
++#include
++#include "lan9691.dtsi"
++
++/ {
++ model = "Microchip EV23X71A";
++ compatible = "microchip,ev23x71a", "microchip,lan9696", "microchip,lan9691";
++
++ aliases {
++ serial0 = &usart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ gpio-restart {
++ compatible = "gpio-restart";
++ gpios = <&gpio 60 GPIO_ACTIVE_LOW>;
++ open-source;
++ priority = <200>;
++ };
++
++ i2c-mux {
++ compatible = "i2c-mux-gpio";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ i2c-parent = <&i2c3>;
++ idle-state = <0x8>;
++ mux-gpios = <&sgpio_out 0 1 GPIO_ACTIVE_HIGH>,
++ <&sgpio_out 0 2 GPIO_ACTIVE_HIGH>,
++ <&sgpio_out 0 3 GPIO_ACTIVE_HIGH>;
++ settle-time-us = <100>;
++
++ i2c_sfp0: i2c@0 {
++ reg = <0x0>;
++ };
++
++ i2c_sfp1: i2c@1 {
++ reg = <0x1>;
++ };
++
++ i2c_sfp2: i2c@2 {
++ reg = <0x2>;
++ };
++
++ i2c_sfp3: i2c@3 {
++ reg = <0x3>;
++ };
++
++ i2c_poe: i2c@7 {
++ reg = <0x7>;
++ };
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led-status {
++ color = ;
++ function = LED_FUNCTION_STATUS;
++ gpios = <&gpio 61 GPIO_ACTIVE_LOW>;
++ };
++
++ led-sfp1-green {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <0>;
++ gpios = <&sgpio_out 6 0 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++
++ led-sfp1-yellow {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <0>;
++ gpios = <&sgpio_out 6 1 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++
++ led-sfp2-green {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <1>;
++ gpios = <&sgpio_out 7 0 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++
++ led-sfp2-yellow {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <1>;
++ gpios = <&sgpio_out 7 1 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++
++ led-sfp3-green {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <2>;
++ gpios = <&sgpio_out 8 0 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++
++ led-sfp3-yellow {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <2>;
++ gpios = <&sgpio_out 8 1 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++
++ led-sfp4-green {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <3>;
++ gpios = <&sgpio_out 9 0 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++
++ led-sfp4-yellow {
++ color = ;
++ function = LED_FUNCTION_LAN;
++ function-enumerator = <3>;
++ gpios = <&sgpio_out 9 1 GPIO_ACTIVE_LOW>;
++ default-state = "off";
++ };
++ };
++
++ mux-controller {
++ compatible = "gpio-mux";
++ #mux-control-cells = <0>;
++ mux-gpios = <&sgpio_out 1 2 GPIO_ACTIVE_LOW>,
++ <&sgpio_out 1 3 GPIO_ACTIVE_LOW>;
++ };
++
++ sfp0: sfp0 {
++ compatible = "sff,sfp";
++ i2c-bus = <&i2c_sfp0>;
++ tx-disable-gpios = <&sgpio_out 6 2 GPIO_ACTIVE_HIGH>;
++ los-gpios = <&sgpio_in 6 0 GPIO_ACTIVE_HIGH>;
++ mod-def0-gpios = <&sgpio_in 6 1 GPIO_ACTIVE_LOW>;
++ tx-fault-gpios = <&sgpio_in 6 2 GPIO_ACTIVE_HIGH>;
++ };
++
++ sfp1: sfp1 {
++ compatible = "sff,sfp";
++ i2c-bus = <&i2c_sfp1>;
++ tx-disable-gpios = <&sgpio_out 7 2 GPIO_ACTIVE_HIGH>;
++ los-gpios = <&sgpio_in 7 0 GPIO_ACTIVE_HIGH>;
++ mod-def0-gpios = <&sgpio_in 7 1 GPIO_ACTIVE_LOW>;
++ tx-fault-gpios = <&sgpio_in 7 2 GPIO_ACTIVE_HIGH>;
++ };
++
++ sfp2: sfp2 {
++ compatible = "sff,sfp";
++ i2c-bus = <&i2c_sfp2>;
++ tx-disable-gpios = <&sgpio_out 8 2 GPIO_ACTIVE_HIGH>;
++ los-gpios = <&sgpio_in 8 0 GPIO_ACTIVE_HIGH>;
++ mod-def0-gpios = <&sgpio_in 8 1 GPIO_ACTIVE_LOW>;
++ tx-fault-gpios = <&sgpio_in 8 2 GPIO_ACTIVE_HIGH>;
++ };
++
++ sfp3: sfp3 {
++ compatible = "sff,sfp";
++ i2c-bus = <&i2c_sfp3>;
++ tx-disable-gpios = <&sgpio_out 9 2 GPIO_ACTIVE_HIGH>;
++ los-gpios = <&sgpio_in 9 0 GPIO_ACTIVE_HIGH>;
++ mod-def0-gpios = <&sgpio_in 9 1 GPIO_ACTIVE_LOW>;
++ tx-fault-gpios = <&sgpio_in 9 2 GPIO_ACTIVE_HIGH>;
++ };
++};
++
++&gpio {
++ emmc_sd_pins: emmc-sd-pins {
++ /* eMMC_SD - CMD, CLK, D0, D1, D2, D3, D4, D5, D6, D7, RSTN */
++ pins = "GPIO_14", "GPIO_15", "GPIO_16", "GPIO_17",
++ "GPIO_18", "GPIO_19", "GPIO_20", "GPIO_21",
++ "GPIO_22", "GPIO_23", "GPIO_24";
++ function = "emmc_sd";
++ };
++
++ fan_pins: fan-pins {
++ pins = "GPIO_25", "GPIO_26";
++ function = "fan";
++ };
++
++ fc0_pins: fc0-pins {
++ pins = "GPIO_3", "GPIO_4";
++ function = "fc";
++ };
++
++ fc2_pins: fc2-pins {
++ pins = "GPIO_64", "GPIO_65", "GPIO_66";
++ function = "fc";
++ };
++
++ fc3_pins: fc3-pins {
++ pins = "GPIO_55", "GPIO_56";
++ function = "fc";
++ };
++
++ mdio_irq_pins: mdio-irq-pins {
++ pins = "GPIO_11";
++ function = "miim_irq";
++ };
++
++ mdio_pins: mdio-pins {
++ pins = "GPIO_9", "GPIO_10";
++ function = "miim";
++ };
++
++ ptp_ext_pins: ptp-ext-pins {
++ pins = "GPIO_59";
++ function = "ptpsync_5";
++ };
++
++ ptp_out_pins: ptp-out-pins {
++ pins = "GPIO_58";
++ function = "ptpsync_4";
++ };
++
++ sgpio_pins: sgpio-pins {
++ /* SCK, D0, D1, LD */
++ pins = "GPIO_5", "GPIO_6", "GPIO_7", "GPIO_8";
++ function = "sgpio_a";
++ };
++
++ usb_over_pins: usb-over-pins {
++ pins = "GPIO_13";
++ function = "usb_over_detect";
++ };
++
++ usb_power_pins: usb-power-pins {
++ pins = "GPIO_1";
++ function = "usb_power";
++ };
++
++ usb_rst_pins: usb-rst-pins {
++ pins = "GPIO_12";
++ function = "usb2phy_rst";
++ };
++
++ usb_ulpi_pins: usb-ulpi-pins {
++ pins = "GPIO_30", "GPIO_31", "GPIO_32", "GPIO_33",
++ "GPIO_34", "GPIO_35", "GPIO_36", "GPIO_37",
++ "GPIO_38", "GPIO_39", "GPIO_40", "GPIO_41";
++ function = "usb_ulpi";
++ };
++};
++
++&flx0 {
++ atmel,flexcom-mode = ;
++ status = "okay";
++};
++
++&flx2 {
++ atmel,flexcom-mode = ;
++ status = "okay";
++};
++
++&flx3 {
++ atmel,flexcom-mode = ;
++ status = "okay";
++};
++
++&i2c3 {
++ pinctrl-0 = <&fc3_pins>;
++ pinctrl-names = "default";
++ i2c-analog-filter;
++ i2c-digital-filter;
++ i2c-digital-filter-width-ns = <35>;
++ i2c-sda-hold-time-ns = <1500>;
++ status = "okay";
++};
++
++&mdio0 {
++ pinctrl-0 = <&mdio_pins>, <&mdio_irq_pins>;
++ pinctrl-names = "default";
++ reset-gpios = <&gpio 62 GPIO_ACTIVE_LOW>;
++ status = "okay";
++
++ phy3: phy@3 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <3>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy4: phy@4 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <4>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy5: phy@5 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <5>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy6: phy@6 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <6>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy7: phy@7 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <7>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy8: phy@8 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <8>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy9: phy@9 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <9>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy10: phy@10 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <10>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy11: phy@11 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <11>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy12: phy@12 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <12>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy13: phy@13 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <13>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy14: phy@14 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <14>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy15: phy@15 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <15>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy16: phy@16 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <16>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy17: phy@17 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <17>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy18: phy@18 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <18>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy19: phy@19 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <19>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy20: phy@20 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <20>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy21: phy@21 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <21>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy22: phy@22 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <22>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy23: phy@23 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <23>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy24: phy@24 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <24>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy25: phy@25 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <25>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy26: phy@26 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <26>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++
++ phy27: phy@27 {
++ compatible = "ethernet-phy-ieee802.3-c22";
++ reg = <27>;
++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
++ interrupt-parent = <&gpio>;
++ };
++};
++
++&serdes {
++ status = "okay";
++};
++
++&sgpio {
++ pinctrl-0 = <&sgpio_pins>;
++ pinctrl-names = "default";
++ microchip,sgpio-port-ranges = <0 1>, <6 9>;
++ status = "okay";
++
++ gpio@0 {
++ ngpios = <128>;
++ };
++ gpio@1 {
++ ngpios = <128>;
++ };
++};
++
++&spi2 {
++ pinctrl-0 = <&fc2_pins>;
++ pinctrl-names = "default";
++ cs-gpios = <&gpio 63 GPIO_ACTIVE_LOW>;
++ status = "okay";
++};
++
++&switch {
++ pinctrl-0 = <&ptp_out_pins>, <&ptp_ext_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++
++ ethernet-ports {
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ port0: port@0 {
++ reg = <0>;
++ phy-handle = <&phy4>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 0>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port1: port@1 {
++ reg = <1>;
++ phy-handle = <&phy5>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 0>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port2: port@2 {
++ reg = <2>;
++ phy-handle = <&phy6>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 0>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port3: port@3 {
++ reg = <3>;
++ phy-handle = <&phy7>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 0>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port4: port@4 {
++ reg = <4>;
++ phy-handle = <&phy8>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 1>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port5: port@5 {
++ reg = <5>;
++ phy-handle = <&phy9>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 1>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port6: port@6 {
++ reg = <6>;
++ phy-handle = <&phy10>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 1>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port7: port@7 {
++ reg = <7>;
++ phy-handle = <&phy11>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 1>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port8: port@8 {
++ reg = <8>;
++ phy-handle = <&phy12>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 2>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port9: port@9 {
++ reg = <9>;
++ phy-handle = <&phy13>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 2>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port10: port@10 {
++ reg = <10>;
++ phy-handle = <&phy14>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 2>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port11: port@11 {
++ reg = <11>;
++ phy-handle = <&phy15>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 2>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port12: port@12 {
++ reg = <12>;
++ phy-handle = <&phy16>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 3>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port13: port@13 {
++ reg = <13>;
++ phy-handle = <&phy17>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 3>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port14: port@14 {
++ reg = <14>;
++ phy-handle = <&phy18>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 3>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port15: port@15 {
++ reg = <15>;
++ phy-handle = <&phy19>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 3>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port16: port@16 {
++ reg = <16>;
++ phy-handle = <&phy20>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 4>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port17: port@17 {
++ reg = <17>;
++ phy-handle = <&phy21>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 4>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port18: port@18 {
++ reg = <18>;
++ phy-handle = <&phy22>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 4>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port19: port@19 {
++ reg = <19>;
++ phy-handle = <&phy23>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 4>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port20: port@20 {
++ reg = <20>;
++ phy-handle = <&phy24>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 5>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port21: port@21 {
++ reg = <21>;
++ phy-handle = <&phy25>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 5>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port22: port@22 {
++ reg = <22>;
++ phy-handle = <&phy26>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 5>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port23: port@23 {
++ reg = <23>;
++ phy-handle = <&phy27>;
++ phy-mode = "qsgmii";
++ phys = <&serdes 5>;
++ microchip,bandwidth = <1000>;
++ };
++
++ port24: port@24 {
++ reg = <24>;
++ phys = <&serdes 6>;
++ phy-mode = "10gbase-r";
++ sfp = <&sfp0>;
++ managed = "in-band-status";
++ microchip,bandwidth = <10000>;
++ microchip,sd-sgpio = <24>;
++ };
++
++ port25: port@25 {
++ reg = <25>;
++ phys = <&serdes 7>;
++ phy-mode = "10gbase-r";
++ sfp = <&sfp1>;
++ managed = "in-band-status";
++ microchip,bandwidth = <10000>;
++ microchip,sd-sgpio = <28>;
++ };
++
++ port26: port@26 {
++ reg = <26>;
++ phys = <&serdes 8>;
++ phy-mode = "10gbase-r";
++ sfp = <&sfp2>;
++ managed = "in-band-status";
++ microchip,bandwidth = <10000>;
++ microchip,sd-sgpio = <32>;
++ };
++
++ port27: port@27 {
++ reg = <27>;
++ phys = <&serdes 9>;
++ phy-mode = "10gbase-r";
++ sfp = <&sfp3>;
++ managed = "in-band-status";
++ microchip,bandwidth = <10000>;
++ microchip,sd-sgpio = <36>;
++ };
++
++ port29: port@29 {
++ reg = <29>;
++ phy-handle = <&phy3>;
++ phy-mode = "rgmii-id";
++ microchip,bandwidth = <1000>;
++ };
++ };
++};
++
++&tmon {
++ pinctrl-0 = <&fan_pins>;
++ pinctrl-names = "default";
++};
++
++&usart0 {
++ pinctrl-0 = <&fc0_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
++
++&usb {
++ pinctrl-0 = <&usb_ulpi_pins>, <&usb_rst_pins>, <&usb_over_pins>, <&usb_power_pins>;
++ pinctrl-names = "default";
++ status = "okay";
++};
diff --git a/patches/linux/6.18.46/0062-arm64-dts-microchip-lan969x-add-OTP-node.patch b/patches/linux/6.18.46/0062-arm64-dts-microchip-lan969x-add-OTP-node.patch
new file mode 100644
index 000000000..0a9dd3787
--- /dev/null
+++ b/patches/linux/6.18.46/0062-arm64-dts-microchip-lan969x-add-OTP-node.patch
@@ -0,0 +1,33 @@
+From 09f9fca6457b9967a340d21625727112df82ee2b Mon Sep 17 00:00:00 2001
+From: Robert Marko
+Date: Fri, 15 May 2026 13:59:09 +0200
+Subject: [PATCH 62/64] arm64: dts: microchip: lan969x: add OTP node
+Organization: Wires
+
+Add the required OTP on LAN969x.
+
+Signed-off-by: Robert Marko
+Reviewed-by: Claudiu Beznea
+Link: https://lore.kernel.org/r/20260515115954.701155-3-robimarko@gmail.com
+Signed-off-by: Claudiu Beznea
+(cherry picked from commit 8071815790141d3f05e32b972a6c79fdbbb88cfa)
+---
+ arch/arm64/boot/dts/microchip/lan9691.dtsi | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/microchip/lan9691.dtsi b/arch/arm64/boot/dts/microchip/lan9691.dtsi
+index 235e56bebbdb..ed997d87dd09 100644
+--- a/arch/arm64/boot/dts/microchip/lan9691.dtsi
++++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
+@@ -100,6 +100,11 @@ usb: usb@300000 {
+ status = "disabled";
+ };
+
++ otp: otp@e0021000 {
++ compatible = "microchip,lan9691-otpc";
++ reg = <0xe0021000 0x1000>;
++ };
++
+ flx0: flexcom@e0040000 {
+ compatible = "microchip,lan9691-flexcom", "atmel,sama5d2-flexcom";
+ reg = <0xe0040000 0x100>;
diff --git a/patches/linux/6.18.46/0063-arm64-dts-microchip-lan969x-add-SDMMC-nodes.patch b/patches/linux/6.18.46/0063-arm64-dts-microchip-lan969x-add-SDMMC-nodes.patch
new file mode 100644
index 000000000..27aa978a6
--- /dev/null
+++ b/patches/linux/6.18.46/0063-arm64-dts-microchip-lan969x-add-SDMMC-nodes.patch
@@ -0,0 +1,48 @@
+From 4ea283cd3f17bcd1ac8bdc1cbcf5f5751fc0a334 Mon Sep 17 00:00:00 2001
+From: Joachim Wiberg
+Date: Wed, 19 Aug 2026 11:38:37 +0200
+Subject: [PATCH 63/64] arm64: dts: microchip: lan969x: add SDMMC nodes
+Organization: Wires
+
+The SoC has two SDMMC controllers, neither of which is described, so
+boards with eMMC have no way to enable it. Add both, disabled by
+default.
+
+Signed-off-by: Joachim Wiberg
+---
+ arch/arm64/boot/dts/microchip/lan9691.dtsi | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/microchip/lan9691.dtsi b/arch/arm64/boot/dts/microchip/lan9691.dtsi
+index ed997d87dd09..59a19462a5db 100644
+--- a/arch/arm64/boot/dts/microchip/lan9691.dtsi
++++ b/arch/arm64/boot/dts/microchip/lan9691.dtsi
+@@ -396,6 +396,28 @@ clks: clock-controller@e00c00b4 {
+ clock-names = "cpu", "ddr", "sys";
+ };
+
++ sdmmc0: mmc@e0830000 {
++ compatible = "microchip,lan969x-sdhci";
++ reg = <0xe0830000 0x300>;
++ interrupts = ;
++ clocks = <&clks GCK_ID_SDMMC0>, <&clks GCK_ID_SDMMC0>;
++ clock-names = "hclock", "multclk";
++ assigned-clocks = <&clks GCK_ID_SDMMC0>;
++ assigned-clock-rates = <100000000>;
++ status = "disabled";
++ };
++
++ sdmmc1: mmc@e0838000 {
++ compatible = "microchip,lan969x-sdhci";
++ reg = <0xe0838000 0x300>;
++ interrupts = ;
++ clocks = <&clks GCK_ID_SDMMC1>, <&clks GCK_ID_SDMMC1>;
++ clock-names = "hclock", "multclk";
++ assigned-clocks = <&clks GCK_ID_SDMMC1>;
++ assigned-clock-rates = <45000000>;
++ status = "disabled";
++ };
++
+ reset: reset-controller@e201000c {
+ compatible = "microchip,lan9691-switch-reset",
+ "microchip,lan966x-switch-reset";
diff --git a/patches/linux/6.18.46/0064-arm64-dts-microchip-ev23x71a-enable-eMMC.patch b/patches/linux/6.18.46/0064-arm64-dts-microchip-ev23x71a-enable-eMMC.patch
new file mode 100644
index 000000000..b684e647b
--- /dev/null
+++ b/patches/linux/6.18.46/0064-arm64-dts-microchip-ev23x71a-enable-eMMC.patch
@@ -0,0 +1,36 @@
+From c7c0989192e8f3a5be11a3a9f4c230bc28b430f9 Mon Sep 17 00:00:00 2001
+From: Joachim Wiberg
+Date: Wed, 19 Aug 2026 11:38:37 +0200
+Subject: [PATCH 64/64] arm64: dts: microchip: ev23x71a: enable eMMC
+Organization: Wires
+
+The board has an 8-bit eMMC on SDMMC0, and defines the emmc_sd pinctrl
+group for it, but nothing enables the controller.
+
+Signed-off-by: Joachim Wiberg
+---
+ arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
+index 4012ea7d07bb..7f12fc5c321f 100644
+--- a/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
++++ b/arch/arm64/boot/dts/microchip/lan9696-ev23x71a.dts
+@@ -463,6 +463,17 @@ phy27: phy@27 {
+ };
+ };
+
++&sdmmc0 {
++ pinctrl-0 = <&emmc_sd_pins>;
++ pinctrl-names = "default";
++ max-frequency = <100000000>;
++ bus-width = <8>;
++ mmc-ddr-1_8v;
++ mmc-hs200-1_8v;
++ non-removable;
++ status = "okay";
++};
++
+ &serdes {
+ status = "okay";
+ };
diff --git a/patches/uboot/bsp-v2024.04-2026.06/0001-cmd-sleep-Consume-Ctrl-C-when-exiting-early.patch b/patches/uboot/bsp-v2024.04-2026.06/0001-cmd-sleep-Consume-Ctrl-C-when-exiting-early.patch
new file mode 100644
index 000000000..18744cc25
--- /dev/null
+++ b/patches/uboot/bsp-v2024.04-2026.06/0001-cmd-sleep-Consume-Ctrl-C-when-exiting-early.patch
@@ -0,0 +1,52 @@
+From 5a62870ed29983d5286c42733acd26b05ee6cfdb Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz
+Date: Mon, 10 Jun 2024 12:59:21 +0200
+Subject: [PATCH 1/3] cmd/sleep: Consume Ctrl-C when exiting early
+Organization: Wires
+
+When sleep aborts early due to Ctrl-C input from the user, that state
+is transferred to the exit status of the program and should therefore
+be cleared from the global state.
+
+Before this change, the lingering global state would lead to very
+unintuitive execution flows in scripts due to the U-Boot specific
+modification to the hush interpreter which checks for Ctrl-C in all
+loop constructs.
+
+This script, for example...
+
+ if sleep 3; then
+ echo "Had a good night's sleep"
+ else
+ echo "That was a rude awakening! I refuse to go on..."
+ while true; do
+ true
+ done
+
+ echo "...or maybe I will"
+ fi
+
+...would just skip over the infinite loop (indeed, all following
+loops) when prematurely interrupting the sleep.
+
+(cherry picked from commit ed733077b87b1f3da6ac956840c927406c268a3d)
+---
+ cmd/sleep.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/cmd/sleep.c b/cmd/sleep.c
+index c741b4aa029..b3511e13b83 100644
+--- a/cmd/sleep.c
++++ b/cmd/sleep.c
+@@ -39,8 +39,10 @@ static int do_sleep(struct cmd_tbl *cmdtp, int flag, int argc,
+ delay += mdelay;
+
+ while (get_timer(start) < delay) {
+- if (ctrlc())
++ if (ctrlc()) {
++ clear_ctrlc();
+ return CMD_RET_FAILURE;
++ }
+
+ udelay(100);
+ }
diff --git a/patches/uboot/bsp-v2024.04-2026.06/0002-hush-Remove-Ctrl-C-detection-in-loops.patch b/patches/uboot/bsp-v2024.04-2026.06/0002-hush-Remove-Ctrl-C-detection-in-loops.patch
new file mode 100644
index 000000000..c481aed59
--- /dev/null
+++ b/patches/uboot/bsp-v2024.04-2026.06/0002-hush-Remove-Ctrl-C-detection-in-loops.patch
@@ -0,0 +1,39 @@
+From 0c7f46cb147199ecc649838105ce49f9131a7b2e Mon Sep 17 00:00:00 2001
+From: Tobias Waldekranz
+Date: Mon, 10 Jun 2024 13:25:31 +0200
+Subject: [PATCH 2/3] hush: Remove Ctrl-C detection in loops
+Organization: Wires
+
+Assume that the original intent was to emulate SIGINT to a shell. This
+only works as expected if the loop in question is the ouermost, and
+last, statement. In all other cases, it completely breaks the expected
+execution flow. It more or less resurrects Visual Basic's "On Error
+Resume Next".
+
+Disable this behavior and delegate the problem of loop termination to
+the writer of the script instead.
+
+Signed-off-by: Tobias Waldekranz
+(cherry picked from commit cde9fed496833b88094ed6e9fea11969a1be8e25)
+---
+ common/cli_hush.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/common/cli_hush.c b/common/cli_hush.c
+index 9cda97f30e3..45293d8d482 100644
+--- a/common/cli_hush.c
++++ b/common/cli_hush.c
+@@ -1796,13 +1796,6 @@ static int run_list_real(struct pipe *pi)
+ for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
+ if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
+ pi->r_mode == RES_FOR) {
+-#ifdef __U_BOOT__
+- /* check Ctrl-C */
+- ctrlc();
+- if ((had_ctrlc())) {
+- return 1;
+- }
+-#endif
+ flag_restore = 0;
+ if (!rpipe) {
+ flag_rep = 0;
diff --git a/patches/uboot/bsp-v2024.04-2026.06/0003-board-microchip-lan969x-honor-ENV_IS_NOWHERE.patch b/patches/uboot/bsp-v2024.04-2026.06/0003-board-microchip-lan969x-honor-ENV_IS_NOWHERE.patch
new file mode 100644
index 000000000..fb62e5f25
--- /dev/null
+++ b/patches/uboot/bsp-v2024.04-2026.06/0003-board-microchip-lan969x-honor-ENV_IS_NOWHERE.patch
@@ -0,0 +1,43 @@
+From 6b81edd0d7bd3231106757846a8ad0442b0ed3ea Mon Sep 17 00:00:00 2001
+From: Joachim Wiberg
+Date: Fri, 21 Aug 2026 14:37:27 +0200
+Subject: [PATCH 3/3] board: microchip: lan969x: honor ENV_IS_NOWHERE
+Organization: Wires
+
+env_get_location() returns the environment location matching the medium
+Trusted Firmware booted from, and never ENVL_NOWHERE. A system that
+keeps its environment in the control device tree, and therefore builds
+no environment driver at all, fails to boot: env_driver_lookup() finds
+nothing at prio 0, so env_init() returns -ENODEV. This happens before
+the console is up, and the initcall list reports the failure one entry
+late, at init_baud_rate, which makes it needlessly hard to place.
+
+Return ENVL_NOWHERE when no location driver is built, as
+board/kontron/sl28/sl28.c already does.
+
+Signed-off-by: Joachim Wiberg
+---
+ board/microchip/lan969x/lan969x.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/board/microchip/lan969x/lan969x.c b/board/microchip/lan969x/lan969x.c
+index bc357159ecd..2694604ef6d 100644
+--- a/board/microchip/lan969x/lan969x.c
++++ b/board/microchip/lan969x/lan969x.c
+@@ -77,6 +77,16 @@ enum env_location env_get_location(enum env_operation op, int prio)
+ {
+ boot_source_type_t boot_source = tfa_get_boot_source();
+
++ /*
++ * Systems keeping the environment in the control device tree
++ * build no location driver at all. Asking for one that was
++ * never built fails env_init() with -ENODEV.
++ */
++ if (!CONFIG_IS_ENABLED(ENV_IS_IN_MMC) &&
++ !CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH) &&
++ !CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
++ return prio == 0 ? ENVL_NOWHERE : ENVL_UNKNOWN;
++
+ switch(boot_source) {
+ case BOOT_SOURCE_EMMC:
+ return prio == 0 ? ENVL_MMC : ENVL_UNKNOWN;
diff --git a/src/bin/show/__init__.py b/src/bin/show/__init__.py
index 0b3471bd7..4d240c4a9 100755
--- a/src/bin/show/__init__.py
+++ b/src/bin/show/__init__.py
@@ -544,15 +544,8 @@ def mdns(args: List[str]) -> None:
cli_pretty(data, "show-mdns")
-# Sensor names that represent the SoC/CPU temperature (not per-port PHYs).
-# Matches "cpu"/"soc"/"core", and Marvell CN913x "ap-*" / "cp-*" zones.
-# Note the hyphen after "cp" so mangled PHY names like "cp0busbus…" never
-# match.
-SOC_TEMP_RE = re.compile(r'^(cpu|soc|core|ap-|cp\d+-)')
-
-
def system(args: List[str]) -> None:
- # Get system state from sysrepo
+ """Get system state from sysrepo"""
data = get_json("/ietf-system:system-state")
if not data:
print("No system data retrieved.")
@@ -569,21 +562,20 @@ def system(args: List[str]) -> None:
fan_rpm = None
if hardware_data and "ietf-hardware:hardware" in hardware_data:
components = hardware_data.get("ietf-hardware:hardware", {}).get("component", [])
+ # A sensor says nothing in its name, what it measures follows from
+ # the component it belongs to, see doc/hardware.md
+ classes = {c.get("name"): c.get("class") for c in components}
soc_temps = []
for component in components:
sensor_data = component.get("sensor-data", {})
if not sensor_data:
continue
- name = component.get("name", "")
+ parent = classes.get(component.get("parent"))
value_type = sensor_data.get("value-type")
- # Capture SoC/CPU temperature, ignoring per-port phy, sfp, etc.
- # Platforms name the zone differently: a plain "cpu"/"soc"/"core",
- # or, on Marvell CN913x, an "ap-*" (application processor) or
- # "cp-*" (communication processor) cluster. Collect them all
- # and report the hottest as the representative SoC temperature.
- if value_type == "celsius" and SOC_TEMP_RE.match(name):
+ # An SoC may report several dies or clusters, take the hottest
+ if value_type == "celsius" and parent == "iana-hardware:cpu":
soc_temps.append(sensor_data.get("value", 0) / 1000.0)
# Capture fan speed if available
diff --git a/src/statd/python/cli_pretty/cli_pretty.py b/src/statd/python/cli_pretty/cli_pretty.py
index b9eb05157..f098c2734 100755
--- a/src/statd/python/cli_pretty/cli_pretty.py
+++ b/src/statd/python/cli_pretty/cli_pretty.py
@@ -2253,13 +2253,17 @@ def show_services(json):
service_table.print()
-def sensor_sort_key(component):
- """Natural sort key for sensor names: digit runs compare numerically so
- e2 sorts before e10, while keeping ap-cpu/cp0-ic/sfp groups together."""
- name = component.get("name", "")
+def natural_key(name):
+ """Natural sort key: digit runs compare numerically so e2 sorts before
+ e10, while keeping ap-cpu/cp0-ic/sfp groups together."""
return [int(t) if t.isdigit() else t for t in re.split(r'(\d+)', name)]
+def sensor_sort_key(component):
+ """Natural sort key for a sensor component."""
+ return natural_key(component.get("name", ""))
+
+
def show_hardware(json):
if not json.get("ietf-hardware:hardware"):
print("Error, top level \"ietf-hardware:component\" missing")
@@ -2424,23 +2428,19 @@ def show_hardware(json):
else:
standalone.append(component)
- # Get all parent modules (non-sensor components)
- modules = [c for c in components if c.get("class") == "iana-hardware:module"]
-
- # Display modules with their child sensors (indented)
- for module in sorted(modules, key=lambda m: m.get("name", "")):
- module_name = module.get("name", "unknown")
- print(f"\n{module_name}:")
+ # Anything with sensors of its own heads a group, an SFP module,
+ # the CPU, a WiFi radio, ...
+ for parent_name in sorted(children, key=natural_key):
+ print(f"\n{parent_name}:")
- if module_name in children:
- for child in sorted(children[module_name], key=sensor_sort_key):
- sensor = Sensor(child)
- sensor.print(indent=1)
+ for child in sorted(children[parent_name], key=sensor_sort_key):
+ sensor = Sensor(child)
+ sensor.print(indent=1)
# Display standalone sensors (no parent), naturally sorted so port
# temperatures read e1, e2, ... e28 rather than e1, e10, e11, ...
if standalone:
- if modules:
+ if children:
print() # Add blank line between modules and standalone
for component in sorted(standalone, key=sensor_sort_key):
sensor = Sensor(component)
diff --git a/src/statd/python/yanger/ietf_hardware.py b/src/statd/python/yanger/ietf_hardware.py
index e29f53e37..385e9cf3c 100644
--- a/src/statd/python/yanger/ietf_hardware.py
+++ b/src/statd/python/yanger/ietf_hardware.py
@@ -3,7 +3,7 @@
import re
import sys
-from .common import insert, YangDate
+from .common import insert, LOG, YangDate
from .host import HOST
@@ -19,7 +19,10 @@ def vpd_vendor_extensions(data):
def vpd_component(vpd):
component = {}
- component["name"] = vpd.get("board")
+ # Board authors name these in the device tree, as "cpu", "power",
+ # "product", short words that collide with everything else sharing
+ # the component namespace. Say what they are.
+ component["name"] = f"vpd-{vpd.get('board')}"
component["infix-hardware:vpd-data"] = {}
if vpd.get("data"):
@@ -122,31 +125,69 @@ def normalize_sensor_name(name):
sfp_2 -> sfp2
mt7915_phy0 -> phy0
marvell_alaska_tomte_phy7 -> phy7
- cpu_thermal -> cpu
+ cpu_thermal -> cpu-thermal
+ s5_temp -> s5-temp
pwmfan -> pwmfan
Strategy:
- 1. Strip common suffixes like -thermal/_thermal
- 2. Extract well-known sensor type names (phy, sfp, fan, etc.) from
- the end of the name, stripping any vendor/chipset prefix
- 3. Remove underscores before trailing numbers (sfp_2 -> sfp2)
+ 1. Drop the vendor/chipset prefix of a per-port device, where the
+ type and index are what identify it (mt7915_phy0 -> phy0)
+ 2. Remove underscores before trailing numbers (sfp_2 -> sfp2)
+ 3. Keep the rest as one name (s5_temp -> s5-temp)
+
+ A thermal zone and the hwmon device the kernel mirrors it as differ
+ only in their separators, so this also makes the two spellings of
+ one sensor come out identical, which is how the mirror is spotted.
+
+ Names are list keys, nothing more. What a sensor measures is
+ conveyed by the class of the component it belongs to, see
+ doc/hardware.md, so a name must stay unique rather than descriptive.
"""
- import re
-
- # Strip common suffixes
- name = name.replace("-thermal", "").replace("_thermal", "")
-
- # Extract well-known sensor types from end of name, stripping any prefix
- # This handles: mt7915_phy0 -> phy0, marvell_alaska_phy7 -> phy7, etc.
- sensor_types = r'(phy|sfp|fan|temp|sensor|psu|cpu|gpu|memory|disk)'
- match = re.search(rf'.*_({sensor_types}\d*)$', name)
+ # Per-port devices: mt7915_phy0 -> phy0, marvell_alaska_phy7 -> phy7
+ match = re.search(r'.*_((phy|sfp)\d*)$', name)
if match:
name = match.group(1)
# Remove underscores before trailing numbers (sfp_2 -> sfp2)
name = re.sub(r'_(\d+)$', r'\1', name)
- return name
+ return name.replace("_", "-")
+
+
+CPU_COMPONENT = "cpu"
+
+# hwmon device names and thermal zone types that report an SoC die
+# temperature, after normalization: a plain cpu/soc/core, Intel and AMD
+# (coretemp, k10temp), Microchip SparX-5 and LAN969x (s5-temp), or a
+# Marvell CN913x application (ap) or communication (cp) processor
+# cluster.
+#
+# Recognizing vendor names cannot be avoided, but this is the only place
+# it happens. Northbound, the sensors are found through the class of
+# their parent component, see doc/hardware.md.
+SOC_TEMP_SOURCE = re.compile(
+ r'^(cpu\d*|soc\d*|core\d*|coretemp|k10temp|s5-temp|ap|cp\d+)(-.*)?$')
+
+
+def cpu_component(sensors):
+ """
+ Create the SoC component that die temperature sensors belong to.
+
+ Only created when something references it, boards without a die
+ sensor have nothing to say about their SoC.
+ """
+ if not any(sensor.get("parent") == CPU_COMPONENT for sensor in sensors):
+ return []
+
+ return [{
+ "name": CPU_COMPONENT,
+ "class": "iana-hardware:cpu",
+ "parent": "mainboard",
+ "state": {
+ "admin-state": "unknown",
+ "oper-state": "enabled"
+ }
+ }]
def _dt_phandle(path):
@@ -234,9 +275,11 @@ def get_wifi_phy_info():
return phy_info
-def hwmon_sensor_components():
+def hwmon_sensor_components(mirrored):
"""
Discover hwmon sensors and create sensor components with parent/child relationships.
+
+ Devices named in "mirrored" are skipped, see the thermal zones.
Returns a list of hardware components with sensor-data for temperature,
fan, voltage, current, and power sensors.
@@ -268,6 +311,13 @@ def add_sensor(base_name, sensor_component):
device_name = HOST.read(name_path).strip()
+ # With THERMAL_HWMON the kernel mirrors every thermal
+ # zone as an hwmon device, named after the zone with the
+ # separators changed. Both spell the same sensor, and
+ # the zone is already accounted for.
+ if normalize_sensor_name(device_name) in mirrored:
+ continue
+
# Check if device/name exists (e.g., for WiFi radios) and use that instead
device_name_path = os.path.join(hwmon_path, "device", "name")
if HOST.exists(device_name_path):
@@ -447,21 +497,24 @@ def create_sensor(sensor_name, value, value_type, value_scale, label=None):
# Now create parent/child relationships
for base_name, sensors in device_sensors.items():
- if len(sensors) > 1:
- # Multiple sensors: create parent component
- parent = {
+ if SOC_TEMP_SOURCE.match(base_name):
+ # SoC die sensors belong to the CPU, whatever the vendor
+ # called the hwmon device
+ parent = CPU_COMPONENT
+ elif len(sensors) > 1:
+ # Multi-sensor devices, like SFP modules, head their own
+ parent = base_name
+ components.append({
"name": base_name,
- "class": "iana-hardware:module", # Use "module" for multi-sensor devices like SFP
- }
- components.append(parent)
-
- # Add parent reference to all child sensors
- for sensor in sensors:
- sensor["parent"] = base_name
- components.append(sensor)
+ "class": "iana-hardware:module",
+ })
else:
- # Single sensor: add without parent
- components.extend(sensors)
+ parent = None
+
+ for sensor in sensors:
+ if parent:
+ sensor["parent"] = parent
+ components.extend(sensors)
# Enrich WiFi PHY sensors with descriptive information
wifi_info = get_wifi_phy_info()
@@ -495,22 +548,13 @@ def thermal_sensor_components():
for zone_path in thermal_zones:
try:
# Read zone type (e.g., "cpu-thermal", "gpu-thermal")
- type_path = os.path.join(zone_path, "type")
- if not HOST.exists(type_path):
+ zone_type = HOST.read(os.path.join(zone_path, "type"))
+ temp = HOST.read(os.path.join(zone_path, "temp"))
+ if not zone_type or not temp:
continue
- zone_type = HOST.read(type_path).strip()
-
- # Read temperature in millidegrees Celsius
- temp_path = os.path.join(zone_path, "temp")
- if not HOST.exists(temp_path):
- continue
-
- temp_millidegrees = int(HOST.read(temp_path).strip())
-
- # Create component with sensor-data
- # Component name: strip "-thermal" suffix for cleaner display
- component_name = normalize_sensor_name(zone_type)
+ temp_millidegrees = int(temp.strip())
+ component_name = normalize_sensor_name(zone_type.strip())
component = {
"name": component_name,
@@ -525,6 +569,9 @@ def thermal_sensor_components():
}
}
+ if SOC_TEMP_SOURCE.match(component_name):
+ component["parent"] = CPU_COMPONENT
+
components.append(component)
except (FileNotFoundError, ValueError, IOError):
@@ -871,19 +918,56 @@ def gps_receiver_components():
return components
+def unique_names(components):
+ """
+ Components are keyed by name, so a duplicate is not a cosmetic
+ problem: it fails every client parsing the tree. Producers avoid
+ collisions by construction, this is the net under them.
+
+ Note that a renamed component keeps any children pointing at the
+ original name, so this really is a last resort, not a mechanism to
+ rely on.
+ """
+ taken = set()
+
+ for component in components:
+ name = component.get("name")
+ if name not in taken:
+ taken.add(name)
+ continue
+
+ unique = name
+ seq = 1
+ while unique in taken:
+ unique = f"{name}-{seq}"
+ seq += 1
+
+ LOG.warning(f"Duplicate hardware component \"{name}\", renaming "
+ f"one of them \"{unique}\"")
+ component["name"] = unique
+ taken.add(unique)
+
+ return components
+
+
def operational():
systemjson = HOST.read_json("/run/system.json", {})
+ # Thermal zones first: the kernel mirrors each one as an hwmon
+ # device, which carries nothing the zone does not.
+ thermal = thermal_sensor_components()
+ sensors = thermal + hwmon_sensor_components({c["name"] for c in thermal})
+ inventory = (motherboard_component(systemjson) +
+ vpd_components(systemjson) +
+ usb_port_components(systemjson))
return {
"ietf-hardware:hardware": {
- "component":
- motherboard_component(systemjson) +
- vpd_components(systemjson) +
- usb_port_components(systemjson) +
- hwmon_sensor_components() +
- thermal_sensor_components() +
- wifi_radio_components() +
- gps_receiver_components() +
- [],
+ "component": unique_names(
+ inventory +
+ cpu_component(sensors) +
+ sensors +
+ wifi_radio_components() +
+ gps_receiver_components()
+ ),
},
}
diff --git a/src/webui/internal/handlers/dashboard.go b/src/webui/internal/handlers/dashboard.go
index e51dfc11b..7e5351e22 100644
--- a/src/webui/internal/handlers/dashboard.go
+++ b/src/webui/internal/handlers/dashboard.go
@@ -178,6 +178,7 @@ type filesystemFS struct {
// Short forms of hardware-class identities — see shortClass(). Kept here so
// the dashboard and Status > Hardware handlers route the same way.
const (
+ classCPU = "cpu" // ietf-hardware:cpu
classChassis = "chassis" // ietf-hardware:chassis
classUSB = "usb" // infix-hardware:usb
classWiFi = "wifi" // infix-hardware:wifi
@@ -707,8 +708,9 @@ func keyVital(c hwComponentJSON, classByName map[string]string) (sensorEntry, bo
switch c.SensorData.ValueType {
case "celsius":
switch {
- case c.Name == "cpu", c.Name == "soc", c.Name == "core":
- // CPU / SoC / core temperatures.
+ case classByName[c.Parent] == classCPU:
+ // SoC die temperatures, however the platform names the
+ // hwmon device or thermal zone underneath.
case classByName[c.Parent] == classWiFi:
// WiFi radio temperatures whose sensor-data lives under
// the radio component as a child.
diff --git a/test/case/statd/all.yaml b/test/case/statd/all.yaml
index ee1d006bb..69abe2789 100644
--- a/test/case/statd/all.yaml
+++ b/test/case/statd/all.yaml
@@ -7,5 +7,7 @@
name: "interfaces-all"
- case: journal-retention/test.py
name: "journal-retention"
+- case: sensors/test
+ name: "sensors"
- case: system/test
name: "system"
diff --git a/test/case/statd/sensors/cli/show-hardware b/test/case/statd/sensors/cli/show-hardware
new file mode 100644
index 000000000..fb22cbb1e
--- /dev/null
+++ b/test/case/statd/sensors/cli/show-hardware
@@ -0,0 +1,15 @@
+[7mHARDWARE COMPONENTS [0m
+──────────────────────────────────────────────────────────────
+[1mBoard Information[0m
+Model : EV23X71A
+Manufacturer : Microchip
+Base MAC Address : 00:a0:85:00:03:00
+──────────────────────────────────────────────────────────────
+[1mSensors[0m
+[7mNAME VALUE STATUS [0m
+
+cpu:
+ Thermal [32m48.0 °C[39m ok
+ S5 Temp [32m59.5 °C[39m ok
+
+pwmfan 3200 RPM ok
diff --git a/test/case/statd/sensors/ietf-hardware.json b/test/case/statd/sensors/ietf-hardware.json
new file mode 100644
index 000000000..144df05d7
--- /dev/null
+++ b/test/case/statd/sensors/ietf-hardware.json
@@ -0,0 +1,74 @@
+{
+ "ietf-hardware:hardware": {
+ "component": [
+ {
+ "name": "mainboard",
+ "class": "iana-hardware:chassis",
+ "mfg-name": "Microchip",
+ "model-name": "EV23X71A",
+ "infix-hardware:phys-address": "00:a0:85:00:03:00",
+ "state": {
+ "admin-state": "unknown",
+ "oper-state": "enabled"
+ }
+ },
+ {
+ "name": "vpd-cpu",
+ "infix-hardware:vpd-data": {
+ "product-name": "CPU board",
+ "serial-number": "0123456789"
+ },
+ "class": "infix-hardware:vpd",
+ "model-name": "CPU board",
+ "serial-num": "0123456789"
+ },
+ {
+ "name": "cpu",
+ "class": "iana-hardware:cpu",
+ "parent": "mainboard",
+ "state": {
+ "admin-state": "unknown",
+ "oper-state": "enabled"
+ }
+ },
+ {
+ "name": "cpu-thermal",
+ "class": "iana-hardware:sensor",
+ "sensor-data": {
+ "value": 48000,
+ "value-type": "celsius",
+ "value-scale": "milli",
+ "value-precision": 0,
+ "value-timestamp": "2026-01-02T20:43:23+00:00",
+ "oper-status": "ok"
+ },
+ "parent": "cpu"
+ },
+ {
+ "name": "s5-temp",
+ "class": "iana-hardware:sensor",
+ "sensor-data": {
+ "value": 59500,
+ "value-type": "celsius",
+ "value-scale": "milli",
+ "value-precision": 0,
+ "value-timestamp": "2026-01-02T20:43:23+00:00",
+ "oper-status": "ok"
+ },
+ "parent": "cpu"
+ },
+ {
+ "name": "pwmfan",
+ "class": "iana-hardware:sensor",
+ "sensor-data": {
+ "value": 3200,
+ "value-type": "rpm",
+ "value-scale": "units",
+ "value-precision": 0,
+ "value-timestamp": "2026-01-02T20:43:23+00:00",
+ "oper-status": "ok"
+ }
+ }
+ ]
+ }
+}
diff --git a/test/case/statd/sensors/operational.json b/test/case/statd/sensors/operational.json
new file mode 100644
index 000000000..144df05d7
--- /dev/null
+++ b/test/case/statd/sensors/operational.json
@@ -0,0 +1,74 @@
+{
+ "ietf-hardware:hardware": {
+ "component": [
+ {
+ "name": "mainboard",
+ "class": "iana-hardware:chassis",
+ "mfg-name": "Microchip",
+ "model-name": "EV23X71A",
+ "infix-hardware:phys-address": "00:a0:85:00:03:00",
+ "state": {
+ "admin-state": "unknown",
+ "oper-state": "enabled"
+ }
+ },
+ {
+ "name": "vpd-cpu",
+ "infix-hardware:vpd-data": {
+ "product-name": "CPU board",
+ "serial-number": "0123456789"
+ },
+ "class": "infix-hardware:vpd",
+ "model-name": "CPU board",
+ "serial-num": "0123456789"
+ },
+ {
+ "name": "cpu",
+ "class": "iana-hardware:cpu",
+ "parent": "mainboard",
+ "state": {
+ "admin-state": "unknown",
+ "oper-state": "enabled"
+ }
+ },
+ {
+ "name": "cpu-thermal",
+ "class": "iana-hardware:sensor",
+ "sensor-data": {
+ "value": 48000,
+ "value-type": "celsius",
+ "value-scale": "milli",
+ "value-precision": 0,
+ "value-timestamp": "2026-01-02T20:43:23+00:00",
+ "oper-status": "ok"
+ },
+ "parent": "cpu"
+ },
+ {
+ "name": "s5-temp",
+ "class": "iana-hardware:sensor",
+ "sensor-data": {
+ "value": 59500,
+ "value-type": "celsius",
+ "value-scale": "milli",
+ "value-precision": 0,
+ "value-timestamp": "2026-01-02T20:43:23+00:00",
+ "oper-status": "ok"
+ },
+ "parent": "cpu"
+ },
+ {
+ "name": "pwmfan",
+ "class": "iana-hardware:sensor",
+ "sensor-data": {
+ "value": 3200,
+ "value-type": "rpm",
+ "value-scale": "units",
+ "value-precision": 0,
+ "value-timestamp": "2026-01-02T20:43:23+00:00",
+ "oper-status": "ok"
+ }
+ }
+ ]
+ }
+}
diff --git a/test/case/statd/sensors/system/rootfs/run/system.json b/test/case/statd/sensors/system/rootfs/run/system.json
new file mode 100644
index 000000000..bd99fa3a0
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/run/system.json
@@ -0,0 +1,16 @@
+{
+ "vendor": "Microchip",
+ "product-name": "EV23X71A",
+ "mac-address": "00:a0:85:00:03:00",
+ "vpd": {
+ "cpu": {
+ "board": "cpu",
+ "available": true,
+ "trusted": true,
+ "data": {
+ "product-name": "CPU board",
+ "serial-number": "0123456789"
+ }
+ }
+ }
+}
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon0/name b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon0/name
new file mode 100644
index 000000000..0b40a5f51
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon0/name
@@ -0,0 +1 @@
+s5_temp
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon0/temp1_input b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon0/temp1_input
new file mode 100644
index 000000000..3a4d1c5c9
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon0/temp1_input
@@ -0,0 +1 @@
+59500
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon1/fan1_input b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon1/fan1_input
new file mode 100644
index 000000000..a6981b371
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon1/fan1_input
@@ -0,0 +1 @@
+3200
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon1/name b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon1/name
new file mode 100644
index 000000000..50d26d52f
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon1/name
@@ -0,0 +1 @@
+pwmfan
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon2/name b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon2/name
new file mode 100644
index 000000000..c82fe532c
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon2/name
@@ -0,0 +1 @@
+cpu_thermal
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon2/temp1_input b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon2/temp1_input
new file mode 100644
index 000000000..22f0d241a
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/hwmon/hwmon2/temp1_input
@@ -0,0 +1 @@
+48000
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/thermal/thermal_zone0/temp b/test/case/statd/sensors/system/rootfs/sys/class/thermal/thermal_zone0/temp
new file mode 100644
index 000000000..22f0d241a
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/thermal/thermal_zone0/temp
@@ -0,0 +1 @@
+48000
diff --git a/test/case/statd/sensors/system/rootfs/sys/class/thermal/thermal_zone0/type b/test/case/statd/sensors/system/rootfs/sys/class/thermal/thermal_zone0/type
new file mode 100644
index 000000000..0744c8e0c
--- /dev/null
+++ b/test/case/statd/sensors/system/rootfs/sys/class/thermal/thermal_zone0/type
@@ -0,0 +1 @@
+cpu-thermal
diff --git a/test/case/statd/sensors/system/run/ls_+sys+class+hwmon b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon
new file mode 100644
index 000000000..b51997471
--- /dev/null
+++ b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon
@@ -0,0 +1,3 @@
+hwmon0
+hwmon1
+hwmon2
diff --git a/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon0 b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon0
new file mode 100644
index 000000000..e26f6d2d4
--- /dev/null
+++ b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon0
@@ -0,0 +1,2 @@
+name
+temp1_input
diff --git a/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon1 b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon1
new file mode 100644
index 000000000..74e4d3de6
--- /dev/null
+++ b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon1
@@ -0,0 +1,2 @@
+name
+fan1_input
diff --git a/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon2 b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon2
new file mode 100644
index 000000000..e26f6d2d4
--- /dev/null
+++ b/test/case/statd/sensors/system/run/ls_+sys+class+hwmon+hwmon2
@@ -0,0 +1,2 @@
+name
+temp1_input
diff --git a/test/case/statd/sensors/system/run/ls_+sys+class+thermal b/test/case/statd/sensors/system/run/ls_+sys+class+thermal
new file mode 100644
index 000000000..7dc59779b
--- /dev/null
+++ b/test/case/statd/sensors/system/run/ls_+sys+class+thermal
@@ -0,0 +1,2 @@
+thermal_zone0
+cooling_device0
diff --git a/test/case/statd/sensors/system/timestamp b/test/case/statd/sensors/system/timestamp
new file mode 100644
index 000000000..3b0175f96
--- /dev/null
+++ b/test/case/statd/sensors/system/timestamp
@@ -0,0 +1 @@
+1767386603
\ No newline at end of file
diff --git a/test/case/statd/sensors/test b/test/case/statd/sensors/test
new file mode 100755
index 000000000..540442dac
--- /dev/null
+++ b/test/case/statd/sensors/test
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Synthetic system state, hand written rather than captured from a
+# device, to cover sensors no board in the test rig has: an SoC die
+# temperature from hwmon (Microchip s5_temp), one from a thermal zone
+# (cpu-thermal), and a fan. Verifies that both land under the CPU
+# component, and that the fan does not.
+#
+# The VPD is named "cpu", as on Alder, so the CPU component has to pick
+# another name rather than collide with it.
+
+yang_models="ietf-hardware"
+
+cli_commands="show-hardware"
+
+. $(readlink -f $(dirname $0)/../test.sh)
+main "$@"
diff --git a/test/case/statd/system/ietf-hardware.json b/test/case/statd/system/ietf-hardware.json
index e93345405..aedcbb1f5 100644
--- a/test/case/statd/system/ietf-hardware.json
+++ b/test/case/statd/system/ietf-hardware.json
@@ -13,7 +13,7 @@
}
},
{
- "name": "product",
+ "name": "vpd-product",
"infix-hardware:vpd-data": {}
},
{
diff --git a/test/case/statd/system/operational.json b/test/case/statd/system/operational.json
index 8a436a9df..f3067f7f2 100644
--- a/test/case/statd/system/operational.json
+++ b/test/case/statd/system/operational.json
@@ -14,7 +14,7 @@
},
{
"infix-hardware:vpd-data": {},
- "name": "product"
+ "name": "vpd-product"
},
{
"class": "infix-hardware:usb",
diff --git a/test/case/statd/test.sh b/test/case/statd/test.sh
index 941981fc8..b00acfdb4 100644
--- a/test/case/statd/test.sh
+++ b/test/case/statd/test.sh
@@ -212,6 +212,8 @@ cli_exec()
cli_gen()
{
+ [ "$cli_commands" ] || return 0
+
mkdir -p "$casedir/cli"
set $cli_commands
@@ -226,6 +228,8 @@ cli_check()
local diff=
local status=
+ [ "$cli_commands" ] || return 0
+
set $cli_commands
while [ $# -gt 0 ]; do
diff="$(mktemp)"