boot: uboot-microchipsw: use mainline U-Boot

Use mainline U-Boot with pending patches for LAN969x instead of the
old vendor U-Boot.

Both existing boards are supported.

Signed-off-by: Robert Marko <robert.marko@sartura.hr>
This commit is contained in:
Robert Marko committed 2026-09-23 15:09:08 +02:00
1 parent fa6c94b6e9
commit 1f89cfd701
19 files changed
+13618 -71

No files matched your search

+6 -7
View File
@@ -1,12 +1,11 @@
include $(TOPDIR)/rules.mk
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/microchip-ung/u-boot.git
PKG_SOURCE_DATE:=2025-09-22
PKG_SOURCE_VERSION:=c1abab62a00a6b8f43f663a0a30dd0a7fd6a4e95
PKG_MIRROR_HASH:=6405c426afd8bacbb4cc985da4ca1bd04b54a0d2aa3bb3ba8f7571dbe5913055
PKG_VERSION:=2026.10-rc5
PKG_SOURCE_URL:=https://git.u-boot-project.org/u-boot/u-boot.git
PKG_SOURCE_VERSION:=a06e89ab05eaa2b8344d521319399333cd760ae5
PKG_MIRROR_HASH:=26bd795d7b727d9c71bbf6cfd7d3d1b1465ec706a2a3be2e529a70f396283c6a
PKG_MAINTAINER:=Robert Marko <robert.marko@sartura.hr>
@@ -24,14 +23,14 @@ define U-Boot/ev23x71a
NAME:=Microchip EV23X71A
BUILD_DEVICES:=microchip_ev23x71a
BUILD_SUBTARGET:=lan969x
UBOOT_CONFIG:=mchp_lan969x
UBOOT_CONFIG:=microchip_ev23x71a
endef
define U-Boot/tactical-1000
NAME:=Novarq Tactical 1000
BUILD_DEVICES:=novarq_tactical-1000
BUILD_SUBTARGET:=lan969x
UBOOT_CONFIG:=mchp_lan969x
UBOOT_CONFIG:=novarq_tactical_1000
endef
UBOOT_TARGETS:= \
@@ -0,0 +1,25 @@
From 12f9c378b05393ffe0e61b92ceaf7eb0da9f2d12 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 4 Dec 2025 14:52:17 +0100
Subject: [PATCH 01/17] serial: atmel-usart: allow selecting from
ARCH_MICROCHIPSW
USART driver is reused by a lot of Microchip platforms, in this case we
need it for LAN969x so allow selecting it when ARCH_MICROCHIPSW is used.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/serial/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -681,7 +681,7 @@ config ARM_DCC
config ATMEL_USART
bool "Atmel USART support"
- depends on ARCH_AT91
+ depends on ARCH_AT91 || ARCH_MICROCHIPSW
help
Select this to enable USART support for Atmel SoCs. It can be
configured in the device tree, and input clock frequency can
@@ -0,0 +1,628 @@
From c79ea0bb0241734ca5c242bd190c2822f9500eb5 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 4 Dec 2025 17:42:37 +0100
Subject: [PATCH 02/17] pinctrl: add Microchip LAN969x driver
Add pinctrl, pinconf and GPIO driver for Microchip LAN969x.
This is updated version of the vendor U-Boot driver to include all
pinmux functions supported in Linux as well as printing the current
pinmux as set in the SoC.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/pinctrl/Kconfig | 8 +
drivers/pinctrl/Makefile | 1 +
drivers/pinctrl/pinctrl-lan969x.c | 579 ++++++++++++++++++++++++++++++
3 files changed, 588 insertions(+)
create mode 100644 drivers/pinctrl/pinctrl-lan969x.c
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -227,6 +227,14 @@ config PINCTRL_INTEL
driver which must be separately enabled. The driver supports setting
pins on start-up and changing the GPIO attributes.
+config PINCTRL_LAN969X
+ bool "Microchip LAN969X pinctrl driver"
+ depends on DM && TARGET_LAN969X
+ select PINCONF
+ select REGMAP
+ help
+ This option is to enable the LAN969X pinctrl driver.
+
config PINCTRL_PIC32
bool "Microchip PIC32 pin-control and pin-mux driver"
depends on DM && MACH_PIC32
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_PINCTRL_AT91PIO4) += pinct
obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/
obj-$(CONFIG_PINCTRL_INTEL) += intel/
obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o
+obj-$(CONFIG_PINCTRL_LAN969X) += pinctrl-lan969x.o
obj-$(CONFIG_PINCTRL_MESON) += meson/
obj-$(CONFIG_PINCTRL_MSCC) += mscc/
obj-$(CONFIG_PINCTRL_MTK) += mediatek/
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-lan969x.c
@@ -0,0 +1,579 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+#include <asm/gpio.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/devres.h>
+#include <dm/device-internal.h>
+#include <dm/pinctrl.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <regmap.h>
+
+/* GPIO standard registers */
+#define LAN969X_FUNC_PER_PIN 8
+
+/* GPIO standard registers */
+#define LAN969X_GPIO_OUT_SET 0x0
+#define LAN969X_GPIO_OUT_CLR 0x4
+#define LAN969X_GPIO_OUT 0x8
+#define LAN969X_GPIO_IN 0xc
+#define LAN969X_GPIO_OE 0x10
+#define LAN969X_GPIO_INTR 0x14
+#define LAN969X_GPIO_INTR_ENA 0x18
+#define LAN969X_GPIO_INTR_IDENT 0x1c
+#define LAN969X_GPIO_ALT0 0x20
+#define LAN969X_GPIO_ALT1 0x24
+#define LAN969X_GPIO_ALT2 0x28
+#define LAN969X_GPIO_SD_MAP 0x2c
+
+enum {
+ FUNC_CAN0_a,
+ FUNC_CAN0_b,
+ FUNC_CAN1,
+ FUNC_CLKMON,
+ FUNC_NONE,
+ FUNC_FAN,
+ FUNC_FC,
+ FUNC_FC_SHRD,
+ FUNC_FUSA,
+ FUNC_GPIO,
+ FUNC_IRQ0,
+ FUNC_IRQ1,
+ FUNC_IRQ3,
+ FUNC_IRQ4,
+ FUNC_MIIM,
+ FUNC_MIIM_Sa,
+ FUNC_MIIM_IRQ,
+ FUNC_PCIE_PERST,
+ FUNC_PTPSYNC_0,
+ FUNC_PTPSYNC_1,
+ FUNC_PTPSYNC_2,
+ FUNC_PTPSYNC_3,
+ FUNC_PTPSYNC_4,
+ FUNC_PTPSYNC_5,
+ FUNC_PTPSYNC_6,
+ FUNC_PTPSYNC_7,
+ FUNC_QSPI1,
+ FUNC_R,
+ FUNC_SD,
+ FUNC_SFP_SD,
+ FUNC_SGPIO_a,
+ FUNC_SYNCE,
+ FUNC_TWI,
+ FUNC_USB_POWER,
+ FUNC_USB2PHY_RST,
+ FUNC_USB_OVER_DETECT,
+ FUNC_USB_ULPI,
+ FUNC_EMMC_SD,
+ FUNC_MAX
+};
+
+static const char *const lan969x_function_names[FUNC_MAX] = {
+ [FUNC_CAN0_a] = "can0_a",
+ [FUNC_CAN0_b] = "can0_b",
+ [FUNC_CAN1] = "can1",
+ [FUNC_CLKMON] = "clkmon",
+ [FUNC_NONE] = "none",
+ [FUNC_FAN] = "fan",
+ [FUNC_FC] = "fc",
+ [FUNC_FC_SHRD] = "fc_shrd",
+ [FUNC_FUSA] = "fusa",
+ [FUNC_GPIO] = "gpio",
+ [FUNC_IRQ0] = "irq0",
+ [FUNC_IRQ1] = "irq1",
+ [FUNC_IRQ3] = "irq3",
+ [FUNC_IRQ4] = "irq4",
+ [FUNC_MIIM] = "miim",
+ [FUNC_MIIM_Sa] = "miim_slave_a",
+ [FUNC_MIIM_IRQ] = "miim_irq",
+ [FUNC_PCIE_PERST] = "pcie_perst",
+ [FUNC_PTPSYNC_0] = "ptpsync_0",
+ [FUNC_PTPSYNC_1] = "ptpsync_1",
+ [FUNC_PTPSYNC_2] = "ptpsync_2",
+ [FUNC_PTPSYNC_3] = "ptpsync_3",
+ [FUNC_PTPSYNC_4] = "ptpsync_4",
+ [FUNC_PTPSYNC_5] = "ptpsync_5",
+ [FUNC_PTPSYNC_6] = "ptpsync_6",
+ [FUNC_PTPSYNC_7] = "ptpsync_7",
+ [FUNC_QSPI1] = "qspi1",
+ [FUNC_R] = "reserved",
+ [FUNC_SD] = "sd",
+ [FUNC_SFP_SD] = "sfp_sd",
+ [FUNC_SGPIO_a] = "sgpio_a",
+ [FUNC_SYNCE] = "synce",
+ [FUNC_TWI] = "twi",
+ [FUNC_USB_POWER] = "usb_power",
+ [FUNC_USB2PHY_RST] = "usb2phy_rst",
+ [FUNC_USB_OVER_DETECT] = "usb_over_detect",
+ [FUNC_USB_ULPI] = "usb_ulpi",
+ [FUNC_EMMC_SD] = "emmc_sd",
+};
+
+struct lan969x_pin_caps {
+ unsigned int pin;
+ unsigned char functions[LAN969X_FUNC_PER_PIN];
+};
+
+struct lan969x_pin_data {
+ const char *name;
+ struct lan969x_pin_caps *drv_data;
+};
+
+#define LAN969X_P(p, f0, f1, f2, f3, f4, f5, f6, f7) \
+static struct lan969x_pin_caps lan969x_pin_##p = { \
+ .pin = p, \
+ .functions = { \
+ FUNC_##f0, FUNC_##f1, FUNC_##f2, \
+ FUNC_##f3, FUNC_##f4, FUNC_##f5, \
+ FUNC_##f6, FUNC_##f7 \
+ }, \
+}
+
+#define REG(r, info, p) ((r) * (info)->stride + (4 * ((p) / 32)))
+
+struct lan969x_pmx_func {
+ const char **groups;
+ unsigned int ngroups;
+};
+
+struct lan969x_pinctrl {
+ struct udevice *dev;
+ struct pinctrl_dev *pctl;
+ struct regmap *map;
+ void __iomem *pincfg;
+ struct lan969x_pmx_func *func;
+ int num_func;
+ const struct lan969x_pin_data *lan969x_pins;
+ int num_pins;
+ const char * const *function_names;
+ const unsigned long *lan969x_gpios;
+ u8 stride;
+};
+
+/* Pinmuxing table taken from data sheet */
+/* Pin FUNC0 FUNC1 FUNC2 FUNC3 FUNC4 FUNC5 FUNC6 FUNC7 */
+LAN969X_P(0, GPIO, IRQ0, FC_SHRD, PCIE_PERST, NONE, NONE, NONE, R);
+LAN969X_P(1, GPIO, IRQ1, FC_SHRD, USB_POWER, NONE, NONE, NONE, R);
+LAN969X_P(2, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(3, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(4, GPIO, FC, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(5, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(6, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(7, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(8, GPIO, SGPIO_a, NONE, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(9, GPIO, MIIM, MIIM_Sa, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(10, GPIO, MIIM, MIIM_Sa, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(11, GPIO, MIIM_IRQ, MIIM_Sa, CLKMON, NONE, NONE, NONE, R);
+LAN969X_P(12, GPIO, IRQ3, FC_SHRD, USB2PHY_RST, NONE, NONE, NONE, R);
+LAN969X_P(13, GPIO, IRQ4, FC_SHRD, USB_OVER_DETECT, NONE, NONE, NONE, R);
+LAN969X_P(14, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R);
+LAN969X_P(15, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R);
+LAN969X_P(16, GPIO, EMMC_SD, QSPI1, FC, NONE, NONE, NONE, R);
+LAN969X_P(17, GPIO, EMMC_SD, QSPI1, PTPSYNC_0, USB_POWER, NONE, NONE, R);
+LAN969X_P(18, GPIO, EMMC_SD, QSPI1, PTPSYNC_1, USB2PHY_RST, NONE, NONE, R);
+LAN969X_P(19, GPIO, EMMC_SD, QSPI1, PTPSYNC_2, USB_OVER_DETECT, NONE, NONE, R);
+LAN969X_P(20, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(21, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(22, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(23, GPIO, EMMC_SD, NONE, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(24, GPIO, EMMC_SD, NONE, NONE, NONE, NONE, NONE, R);
+LAN969X_P(25, GPIO, FAN, FUSA, CAN0_a, QSPI1, NONE, NONE, R);
+LAN969X_P(26, GPIO, FAN, FUSA, CAN0_a, QSPI1, NONE, NONE, R);
+LAN969X_P(27, GPIO, SYNCE, FC, MIIM, QSPI1, NONE, NONE, R);
+LAN969X_P(28, GPIO, SYNCE, FC, MIIM, QSPI1, NONE, NONE, R);
+LAN969X_P(29, GPIO, SYNCE, FC, MIIM_IRQ, QSPI1, NONE, NONE, R);
+LAN969X_P(30, GPIO, PTPSYNC_0, USB_ULPI, FC_SHRD, QSPI1, NONE, NONE, R);
+LAN969X_P(31, GPIO, PTPSYNC_1, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(32, GPIO, PTPSYNC_2, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(33, GPIO, SD, USB_ULPI, FC_SHRD, NONE, NONE, NONE, R);
+LAN969X_P(34, GPIO, SD, USB_ULPI, CAN1, FC_SHRD, NONE, NONE, R);
+LAN969X_P(35, GPIO, SD, USB_ULPI, CAN1, FC_SHRD, NONE, NONE, R);
+LAN969X_P(36, GPIO, SD, USB_ULPI, PCIE_PERST, FC_SHRD, NONE, NONE, R);
+LAN969X_P(37, GPIO, SD, USB_ULPI, CAN0_b, NONE, NONE, NONE, R);
+LAN969X_P(38, GPIO, SD, USB_ULPI, CAN0_b, NONE, NONE, NONE, R);
+LAN969X_P(39, GPIO, SD, USB_ULPI, MIIM, NONE, NONE, NONE, R);
+LAN969X_P(40, GPIO, SD, USB_ULPI, MIIM, NONE, NONE, NONE, R);
+LAN969X_P(41, GPIO, SD, USB_ULPI, MIIM_IRQ, NONE, NONE, NONE, R);
+LAN969X_P(42, GPIO, PTPSYNC_3, CAN1, NONE, NONE, NONE, NONE, R);
+LAN969X_P(43, GPIO, PTPSYNC_4, CAN1, NONE, NONE, NONE, NONE, R);
+LAN969X_P(44, GPIO, PTPSYNC_5, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(45, GPIO, PTPSYNC_6, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(46, GPIO, PTPSYNC_7, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(47, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(48, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(49, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(50, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(51, GPIO, NONE, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(52, GPIO, FAN, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(53, GPIO, FAN, SFP_SD, NONE, NONE, NONE, NONE, R);
+LAN969X_P(54, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R);
+LAN969X_P(55, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R);
+LAN969X_P(56, GPIO, SYNCE, FC, NONE, NONE, NONE, NONE, R);
+LAN969X_P(57, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_3, NONE, NONE, R);
+LAN969X_P(58, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_4, NONE, NONE, R);
+LAN969X_P(59, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_5, NONE, NONE, R);
+LAN969X_P(60, GPIO, SFP_SD, FC_SHRD, TWI, PTPSYNC_6, NONE, NONE, R);
+LAN969X_P(61, GPIO, MIIM, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(62, GPIO, MIIM, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(63, GPIO, MIIM_IRQ, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(64, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(65, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R);
+LAN969X_P(66, GPIO, FC, FC_SHRD, TWI, NONE, NONE, NONE, R);
+
+#define LAN969X_PIN(n) { \
+ .name = "GPIO_"#n, \
+ .drv_data = &lan969x_pin_##n \
+}
+
+static const struct lan969x_pin_data lan969x_pins[] = {
+ LAN969X_PIN(0),
+ LAN969X_PIN(1),
+ LAN969X_PIN(2),
+ LAN969X_PIN(3),
+ LAN969X_PIN(4),
+ LAN969X_PIN(5),
+ LAN969X_PIN(6),
+ LAN969X_PIN(7),
+ LAN969X_PIN(8),
+ LAN969X_PIN(9),
+ LAN969X_PIN(10),
+ LAN969X_PIN(11),
+ LAN969X_PIN(12),
+ LAN969X_PIN(13),
+ LAN969X_PIN(14),
+ LAN969X_PIN(15),
+ LAN969X_PIN(16),
+ LAN969X_PIN(17),
+ LAN969X_PIN(18),
+ LAN969X_PIN(19),
+ LAN969X_PIN(20),
+ LAN969X_PIN(21),
+ LAN969X_PIN(22),
+ LAN969X_PIN(23),
+ LAN969X_PIN(24),
+ LAN969X_PIN(25),
+ LAN969X_PIN(26),
+ LAN969X_PIN(27),
+ LAN969X_PIN(28),
+ LAN969X_PIN(29),
+ LAN969X_PIN(30),
+ LAN969X_PIN(31),
+ LAN969X_PIN(32),
+ LAN969X_PIN(33),
+ LAN969X_PIN(34),
+ LAN969X_PIN(35),
+ LAN969X_PIN(36),
+ LAN969X_PIN(37),
+ LAN969X_PIN(38),
+ LAN969X_PIN(39),
+ LAN969X_PIN(40),
+ LAN969X_PIN(41),
+ LAN969X_PIN(42),
+ LAN969X_PIN(43),
+ LAN969X_PIN(44),
+ LAN969X_PIN(45),
+ LAN969X_PIN(46),
+ LAN969X_PIN(47),
+ LAN969X_PIN(48),
+ LAN969X_PIN(49),
+ LAN969X_PIN(50),
+ LAN969X_PIN(51),
+ LAN969X_PIN(52),
+ LAN969X_PIN(53),
+ LAN969X_PIN(54),
+ LAN969X_PIN(55),
+ LAN969X_PIN(56),
+ LAN969X_PIN(57),
+ LAN969X_PIN(58),
+ LAN969X_PIN(59),
+ LAN969X_PIN(60),
+ LAN969X_PIN(61),
+ LAN969X_PIN(62),
+ LAN969X_PIN(63),
+ LAN969X_PIN(64),
+ LAN969X_PIN(65),
+ LAN969X_PIN(66),
+};
+
+static int lan969x_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv;
+
+ uc_priv = dev_get_uclass_priv(dev);
+ uc_priv->bank_name = "lan969x-gpio";
+ uc_priv->gpio_count = ARRAY_SIZE(lan969x_pins);
+
+ return 0;
+}
+
+static int lan969x_gpio_get(struct udevice *dev, unsigned int offset)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+ unsigned int val;
+
+ regmap_read(info->map, REG(LAN969X_GPIO_IN, info, offset), &val);
+
+ return !!(val & BIT(offset % 32));
+}
+
+static int lan969x_gpio_set(struct udevice *dev, unsigned int offset, int value)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+
+ if (value)
+ regmap_write(info->map, REG(LAN969X_GPIO_OUT_SET, info, offset),
+ BIT(offset % 32));
+ else
+ regmap_write(info->map, REG(LAN969X_GPIO_OUT_CLR, info, offset),
+ BIT(offset % 32));
+
+ return 0;
+}
+
+static int lan969x_gpio_get_direction(struct udevice *dev, unsigned int offset)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+ unsigned int val;
+
+ regmap_read(info->map, REG(LAN969X_GPIO_OE, info, offset), &val);
+
+ if (val & BIT(offset % 32))
+ return GPIOF_OUTPUT;
+
+ return GPIOF_INPUT;
+}
+
+static int lan969x_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+
+ regmap_write(info->map, REG(LAN969X_GPIO_OE, info, offset),
+ ~BIT(offset % 32));
+
+ return 0;
+}
+
+static int lan969x_gpio_direction_output(struct udevice *dev,
+ unsigned int offset, int value)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev->parent);
+
+ regmap_write(info->map, REG(LAN969X_GPIO_OE, info, offset),
+ BIT(offset % 32));
+
+ return lan969x_gpio_set(dev, offset, value);
+}
+
+const struct dm_gpio_ops lan969x_gpio_ops = {
+ .set_value = lan969x_gpio_set,
+ .get_value = lan969x_gpio_get,
+ .get_function = lan969x_gpio_get_direction,
+ .direction_input = lan969x_gpio_direction_input,
+ .direction_output = lan969x_gpio_direction_output,
+};
+
+static int lan969x_pctl_get_groups_count(struct udevice *dev)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->num_pins;
+}
+
+static const char *lan969x_pctl_get_group_name(struct udevice *dev,
+ unsigned int group)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->lan969x_pins[group].name;
+}
+
+static int lan969x_get_functions_count(struct udevice *dev)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->num_func;
+}
+
+static const char *lan969x_get_function_name(struct udevice *dev,
+ unsigned int function)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+
+ return info->function_names[function];
+}
+
+static int lan969x_pin_function_idx(unsigned int pin, unsigned int function,
+ const struct lan969x_pin_data *lan969x_pins)
+{
+ struct lan969x_pin_caps *p = lan969x_pins[pin].drv_data;
+ int i;
+
+ for (i = 0; i < LAN969X_FUNC_PER_PIN; i++) {
+ if (function == p->functions[i])
+ return i;
+ }
+
+ return -1;
+}
+
+#define REG_ALT(msb, info, p) (LAN969X_GPIO_ALT0 * (info)->stride + 4 * ((msb) + ((info)->stride * ((p) / 32))))
+
+static int lan969x_pinmux_set_mux(struct udevice *dev,
+ unsigned int pin_selector, unsigned int selector)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+ struct lan969x_pin_caps *pin = info->lan969x_pins[pin_selector].drv_data;
+ unsigned int p = pin->pin % 32;
+ int f;
+
+ f = lan969x_pin_function_idx(pin_selector, selector, info->lan969x_pins);
+ if (f < 0)
+ return -EINVAL;
+
+ /*
+ * f is encoded on two bits.
+ * bit 0 of f goes in BIT(pin) of ALT[0], bit 1 of f goes in BIT(pin) of
+ * ALT[1], bit 2 of f goes in BIT(pin) of ALT[2]
+ * This is racy because both registers can't be updated at the same time
+ * but it doesn't matter much for now.
+ * Note: ALT0/ALT1/ALT2 are organized specially for 78 gpio targets
+ */
+ regmap_update_bits(info->map, REG_ALT(0, info, pin->pin),
+ BIT(p), f << p);
+ regmap_update_bits(info->map, REG_ALT(1, info, pin->pin),
+ BIT(p), (f >> 1) << p);
+ regmap_update_bits(info->map, REG_ALT(2, info, pin->pin),
+ BIT(p), (f >> 2) << p);
+
+ return 0;
+}
+
+static int lan969x_get_pin_muxing(struct udevice *dev, unsigned int selector,
+ char *buf, int size)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+ struct lan969x_pin_caps *pin = info->lan969x_pins[selector].drv_data;
+ unsigned int alt0, alt1, alt2, function = 0;
+
+ regmap_read(info->map, REG_ALT(0, info, pin->pin), &alt0);
+ regmap_read(info->map, REG_ALT(1, info, pin->pin), &alt1);
+ regmap_read(info->map, REG_ALT(2, info, pin->pin), &alt2);
+
+ function |= FIELD_PREP(BIT(0), field_get(BIT(pin->pin), alt0));
+ function |= FIELD_PREP(BIT(1), field_get(BIT(pin->pin), alt1));
+ function |= FIELD_PREP(BIT(2), field_get(BIT(pin->pin), alt2));
+
+ snprintf(buf, size, "%s", lan969x_get_function_name(dev, pin->functions[function]));
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(PINCONF)
+static const struct pinconf_param lan969x_pinconf_params[] = {
+ { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+ { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+ { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+};
+
+static int lan969x_pinconf_set(struct udevice *dev, unsigned int pin,
+ unsigned int param, unsigned int arg)
+{
+ struct lan969x_pinctrl *info = dev_get_priv(dev);
+ unsigned int val;
+ int err = 0;
+
+ if (info->pincfg == NULL)
+ return err;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ val = readl(info->pincfg + (pin * 4));
+ val &= ~(BIT(3) | BIT(2));
+ val |= (param == PIN_CONFIG_BIAS_DISABLE) ? 0 :
+ (param == PIN_CONFIG_BIAS_PULL_UP) ? BIT(3) : BIT(2);
+ writel(val, info->pincfg + (pin * 4));
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ if (arg <= 3) {
+ val = readl(info->pincfg + (pin * 4));
+ val &= ~GENMASK(1, 0);
+ val |= arg;
+ writel(val, info->pincfg + (pin * 4));
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -ENOTSUPP;
+ }
+
+ return err;
+}
+#endif
+
+const struct pinctrl_ops lan969x_pinctrl_ops = {
+ .get_pins_count = lan969x_pctl_get_groups_count,
+ .get_pin_name = lan969x_pctl_get_group_name,
+ .get_pin_muxing = lan969x_get_pin_muxing,
+ .get_functions_count = lan969x_get_functions_count,
+ .get_function_name = lan969x_get_function_name,
+ .pinmux_set = lan969x_pinmux_set_mux,
+ .set_state = pinctrl_generic_set_state,
+#if CONFIG_IS_ENABLED(PINCONF)
+ .pinconf_num_params = ARRAY_SIZE(lan969x_pinconf_params),
+ .pinconf_params = lan969x_pinconf_params,
+ .pinconf_set = lan969x_pinconf_set,
+#endif
+};
+
+static struct driver lan969x_gpio_driver = {
+ .name = "lan969x-gpio",
+ .id = UCLASS_GPIO,
+ .probe = lan969x_gpio_probe,
+ .ops = &lan969x_gpio_ops,
+};
+
+int lan969x_pinctrl_probe(struct udevice *dev)
+{
+ struct lan969x_pinctrl *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
+ if (ret)
+ return -EINVAL;
+
+ priv->pincfg = dev_remap_addr_index(dev, 1);
+
+ priv->func = devm_kzalloc(dev, FUNC_MAX * sizeof(struct lan969x_pmx_func), GFP_KERNEL);
+ priv->num_func = FUNC_MAX;
+ priv->function_names = lan969x_function_names;
+
+ priv->lan969x_pins = lan969x_pins;
+ priv->num_pins = ARRAY_SIZE(lan969x_pins);
+ priv->stride = 1 + (priv->num_pins - 1) / 32;
+
+ ret = device_bind(dev, &lan969x_gpio_driver, "lan969x-gpio", NULL,
+ dev_ofnode(dev), NULL);
+
+ return ret;
+}
+
+static const struct udevice_id lan969x_pinctrl_of_match[] = {
+ {.compatible = "microchip,lan9691-pinctrl"},
+ {},
+};
+
+U_BOOT_DRIVER(lan969x_pinctrl) = {
+ .name = "lan969x-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = of_match_ptr(lan969x_pinctrl_of_match),
+ .probe = lan969x_pinctrl_probe,
+ .priv_auto = sizeof(struct lan969x_pinctrl),
+ .ops = &lan969x_pinctrl_ops,
+};
@@ -0,0 +1,248 @@
From a92e1d8da2de5e5ede7ec97a8df5603a6e6bfb72 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 5 Dec 2025 11:12:58 +0100
Subject: [PATCH 03/17] clk: add Microchip LAN966x and LAN969x support
Import clock driver for Microchip LAN966x and LAN969x SoC-s from the vendor
U-Boot as it is based on the upstream Linux driver.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/clk/Makefile | 2 +-
drivers/clk/microchip/Kconfig | 7 +
drivers/clk/microchip/Makefile | 3 +-
drivers/clk/microchip/clk-lan966x.c | 198 ++++++++++++++++++++++++++++
4 files changed, 208 insertions(+), 2 deletions(-)
create mode 100644 drivers/clk/microchip/clk-lan966x.c
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -39,7 +39,7 @@ obj-$(CONFIG_CLK_EXYNOS) += exynos/
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o
obj-$(CONFIG_CLK_K210) += clk_k210.o
obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
-obj-$(CONFIG_CLK_MPFS) += microchip/
+obj-y += microchip/
obj-$(CONFIG_CLK_MVEBU) += mvebu/
obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o
obj-$(CONFIG_CLK_OWL) += owl/
--- a/drivers/clk/microchip/Kconfig
+++ b/drivers/clk/microchip/Kconfig
@@ -1,3 +1,10 @@
+config CLK_LAN966X
+ bool "Microchip LAN966X and LAN969X clock support"
+ depends on ARCH_MICROCHIPSW
+ depends on CLK
+ help
+ Clock driver for Microchip LAN969X platforms.
+
config CLK_MPFS
bool "Clock support for Microchip PolarFire SoC"
depends on CLK && CLK_CCF
--- a/drivers/clk/microchip/Makefile
+++ b/drivers/clk/microchip/Makefile
@@ -1 +1,2 @@
-obj-y += mpfs_clk.o mpfs_clk_cfg.o mpfs_clk_periph.o mpfs_clk_msspll.o
+obj-$(CONFIG_CLK_LAN966X) += clk-lan966x.o
+obj-$(CONFIG_CLK_MPFS) += += mpfs_clk.o mpfs_clk_cfg.o mpfs_clk_periph.o mpfs_clk_msspll.o
--- /dev/null
+++ b/drivers/clk/microchip/clk-lan966x.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <asm/io.h>
+#include <clk-uclass.h>
+#include <div64.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitfield.h>
+
+#define GCK_ENA BIT(0)
+#define GCK_SRC_SEL GENMASK(9, 8)
+#define GCK_PRESCALER GENMASK(23, 16)
+
+struct lan966x_soc_clk_gate_desc {
+ const char *name;
+ int bit_idx;
+};
+
+static const struct lan966x_soc_clk_gate_desc lan966x_clk_gate_desc[] = {
+ { "uhphs", 11 },
+ { "udphs", 10 },
+ { "mcramc", 9 },
+ { "hmatrix", 8 },
+ { }
+};
+
+static const struct lan966x_soc_clk_gate_desc lan969x_clk_gate_desc[] = {
+ { "usb_drd", 10 },
+ { "mcramc", 9 },
+ { "hmatrix", 8 },
+ { }
+};
+
+struct lan966x_clk {
+ void *base;
+ void *gate;
+ int clk_cnt;
+ int clk_gate_cnt;
+ const struct lan966x_soc_clk_gate_desc *clk_gate_desc;
+ ulong parent_rate;
+};
+
+struct lan966x_driver_data {
+ int clk_cnt;
+ int clk_gate_cnt;
+ const struct lan966x_soc_clk_gate_desc *clk_gate_desc;
+ ulong parent_rate;
+};
+
+static struct lan966x_driver_data lan966x_data = {
+ .clk_cnt = 14,
+ .clk_gate_cnt = 4,
+ .clk_gate_desc = lan966x_clk_gate_desc,
+ .parent_rate = 600000000,
+};
+
+static struct lan966x_driver_data lan969x_data = {
+ .clk_cnt = 12,
+ .clk_gate_cnt = 3,
+ .clk_gate_desc = lan969x_clk_gate_desc,
+ .parent_rate = 1000000000,
+};
+
+static void* lan966x_clk_ctlreg(struct lan966x_clk *gck, u8 id)
+{
+ return gck->base + (id * sizeof(u32));
+}
+
+static ulong lan966x_clk_set_rate(struct clk *clk, ulong rate)
+{
+ struct lan966x_clk *gck = dev_get_priv(clk->dev);
+ unsigned long parent_rate = gck->parent_rate;
+ u32 div;
+
+ if (clk->id >= gck->clk_cnt)
+ return -ENODEV;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ /* Calc divisor */
+ div = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+ /* Set src, prescaler */
+ clrsetbits_le32(lan966x_clk_ctlreg(gck, clk->id),
+ GCK_SRC_SEL | GCK_PRESCALER,
+ /* Select CPU_CLK as source always */
+ FIELD_PREP(GCK_SRC_SEL, 0x0) |
+ /* Divisor - 1 */
+ FIELD_PREP(GCK_PRESCALER, (div - 1)));
+
+ return 0;
+}
+
+static ulong lan966x_clk_get_rate(struct clk *clk)
+{
+ struct lan966x_clk *gck = dev_get_priv(clk->dev);
+ unsigned long parent_rate = gck->parent_rate;
+ u32 div, val;
+
+ if (clk->id >= gck->clk_cnt)
+ return -ENODEV;
+
+ val = readl(lan966x_clk_ctlreg(gck, clk->id));
+
+ div = 1 + FIELD_GET(GCK_PRESCALER, val);
+
+ return parent_rate / div;
+}
+
+static int lan966x_clk_enable(struct clk *clk)
+{
+ struct lan966x_clk *gck = dev_get_priv(clk->dev);
+
+ if (clk->id >= gck->clk_cnt) {
+ /* If there are no gate clock then this is not allowed */
+ if (gck->gate == NULL)
+ return -ENODEV;
+
+ if (clk->id >= gck->clk_cnt + gck->clk_gate_cnt)
+ return -ENODEV;
+
+ setbits_le32(gck->gate,
+ BIT(gck->clk_gate_desc[clk->id - gck->clk_cnt].bit_idx));
+
+ return 0;
+ }
+
+ setbits_le32(lan966x_clk_ctlreg(gck, clk->id), GCK_ENA);
+
+ return 0;
+}
+
+static int lan966x_clk_disable(struct clk *clk)
+{
+ struct lan966x_clk *gck = dev_get_priv(clk->dev);
+
+ if (clk->id >= gck->clk_cnt) {
+ /* If there are no gate clock then this is not allowed */
+ if (gck->gate == NULL)
+ return -ENODEV;
+
+ if (clk->id >= gck->clk_cnt + gck->clk_gate_cnt)
+ return -ENODEV;
+
+ clrbits_le32(gck->gate, BIT(gck->clk_gate_desc[clk->id - gck->clk_cnt].bit_idx));
+
+ return 0;
+ }
+
+ clrbits_le32(lan966x_clk_ctlreg(gck, clk->id), GCK_ENA);
+
+ return 0;
+}
+
+static int lan966x_clk_probe(struct udevice *dev)
+{
+ struct lan966x_clk *priv = dev_get_priv(dev);
+ struct lan966x_driver_data *data;
+
+ priv->base = dev_remap_addr(dev);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->gate = dev_remap_addr_index(dev, 1);
+
+ /* Get clock count for target device */
+ data = (struct lan966x_driver_data*)dev_get_driver_data(dev);
+ priv->clk_cnt = data->clk_cnt;
+ priv->clk_gate_cnt = data->clk_gate_cnt;
+ priv->clk_gate_desc = data->clk_gate_desc;
+ priv->parent_rate = data->parent_rate;
+
+ return 0;
+}
+
+static struct clk_ops lan966x_clk_ops = {
+ .disable = lan966x_clk_disable,
+ .enable = lan966x_clk_enable,
+ .get_rate = lan966x_clk_get_rate,
+ .set_rate = lan966x_clk_set_rate,
+};
+
+static const struct udevice_id lan966x_clk_ids[] = {
+ { .compatible = "microchip,lan966x-gck", .data = (unsigned long)&lan966x_data },
+ { .compatible = "microchip,lan9691-gck", .data = (unsigned long)&lan969x_data },
+ { }
+};
+
+U_BOOT_DRIVER(lan966x_clk) = {
+ .name = "lan966x_clk",
+ .id = UCLASS_CLK,
+ .of_match = lan966x_clk_ids,
+ .priv_auto = sizeof(struct lan966x_clk),
+ .ops = &lan966x_clk_ops,
+ .probe = lan966x_clk_probe,
+};
@@ -0,0 +1,22 @@
From 49acec149a1f0d1e4aeeb7f49433114f49ef21fb Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 5 Dec 2025 11:23:47 +0100
Subject: [PATCH 04/17] mmc: atmel: remove duplicate depends on ARCH_AT91
Dependency on ARCH_AT91 is duplicated, so drop the extra one.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/mmc/Kconfig | 1 -
1 file changed, 1 deletion(-)
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -566,7 +566,6 @@ config MMC_SDHCI_ASPEED
config MMC_SDHCI_ATMEL
bool "Atmel SDHCI controller support"
depends on ARCH_AT91
- depends on ARCH_AT91
depends on MMC_SDHCI
help
This enables support for the Atmel SDHCI controller, which supports
@@ -0,0 +1,46 @@
From 2811b2fe69bab6e9ab7e405dd7d83fd1360bc604 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 5 Dec 2025 11:45:42 +0100
Subject: [PATCH 05/17] mmc: atmel-sdhci: set GCK rate based on compatible
In order to add support for LAN969x we need to set the GCK rate based on
compatible instead of defaulting to 240000000 Hz as LAN969x uses only
100000000 Hz.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/mmc/atmel_sdhci.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -96,6 +96,7 @@ static int atmel_sdhci_probe(struct udev
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct atmel_sdhci_plat *plat = dev_get_plat(dev);
struct sdhci_host *host = dev_get_priv(dev);
+ u32 gck_rate = dev_get_driver_data(dev);
u32 max_clk;
struct clk clk;
int ret;
@@ -119,7 +120,7 @@ static int atmel_sdhci_probe(struct udev
if (ret)
return ret;
- clk_set_rate(&clk, ATMEL_SDHC_GCK_RATE);
+ clk_set_rate(&clk, gck_rate);
max_clk = clk_get_rate(&clk);
if (!max_clk)
@@ -163,9 +164,9 @@ static int atmel_sdhci_bind(struct udevi
}
static const struct udevice_id atmel_sdhci_ids[] = {
- { .compatible = "atmel,sama5d2-sdhci" },
- { .compatible = "microchip,sam9x60-sdhci" },
- { .compatible = "microchip,sama7g5-sdhci" },
+ { .compatible = "atmel,sama5d2-sdhci", .data = ATMEL_SDHC_GCK_RATE },
+ { .compatible = "microchip,sam9x60-sdhci", .data = ATMEL_SDHC_GCK_RATE },
+ { .compatible = "microchip,sama7g5-sdhci", .data = ATMEL_SDHC_GCK_RATE },
{ }
};
@@ -0,0 +1,26 @@
From d57e2958dc7e70031eacaf04e813390815193666 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 30 Dec 2025 17:28:51 +0100
Subject: [PATCH 06/17] mmc: atmel-sdhci: include arch specific clk.h only for
AT91
Microchip LAN969x will not include any arch specific clk.h, so in order to
support it only include <asm/arch/clk.h> when AT91 is selected.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/mmc/atmel_sdhci.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -8,7 +8,9 @@
#include <dm.h>
#include <malloc.h>
#include <sdhci.h>
+#if IS_ENABLED(CONFIG_ARCH_AT91)
#include <asm/arch/clk.h>
+#endif
#include <asm/global_data.h>
#define ATMEL_SDHC_MIN_FREQ 400000
@@ -0,0 +1,43 @@
From ff476d7eb7eb4acf6dd6681a3464bf308359ae3e Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 5 Dec 2025 11:47:23 +0100
Subject: [PATCH 07/17] mmc: atmel-sdhci: add support for LAN969x
LAN969x is compatible with the existing driver, however it requires the
GCK clock rate to be set to 100000000 Hz instead.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/mmc/Kconfig | 2 +-
drivers/mmc/atmel_sdhci.c | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -565,7 +565,7 @@ config MMC_SDHCI_ASPEED
config MMC_SDHCI_ATMEL
bool "Atmel SDHCI controller support"
- depends on ARCH_AT91
+ depends on ARCH_AT91 || ARCH_MICROCHIPSW
depends on MMC_SDHCI
help
This enables support for the Atmel SDHCI controller, which supports
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -15,6 +15,7 @@
#define ATMEL_SDHC_MIN_FREQ 400000
#define ATMEL_SDHC_GCK_RATE 240000000
+#define LAN969X_GCK_RATE 100000000
#define ATMEL_SDHC_MC1R 0x204
#define ATMEL_SDHC_MC1R_FCD 0x80
@@ -169,6 +170,7 @@ static const struct udevice_id atmel_sdh
{ .compatible = "atmel,sama5d2-sdhci", .data = ATMEL_SDHC_GCK_RATE },
{ .compatible = "microchip,sam9x60-sdhci", .data = ATMEL_SDHC_GCK_RATE },
{ .compatible = "microchip,sama7g5-sdhci", .data = ATMEL_SDHC_GCK_RATE },
+ { .compatible = "microchip,lan9691-sdhci", .data = LAN969X_GCK_RATE },
{ }
};
@@ -0,0 +1,26 @@
From 6ab447ab0490b23f424d437fa8b1e14fa4c87bf2 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Mon, 19 Jan 2026 13:29:50 +0100
Subject: [PATCH 08/17] i2c: at91-i2c: include arch specific clk.h only for
AT91
Microchip LAN969x will not include any arch specific clk.h, so in order to
support it only include <asm/arch/clk.h> when AT91 is selected.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/i2c/at91_i2c.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/i2c/at91_i2c.c
+++ b/drivers/i2c/at91_i2c.c
@@ -14,7 +14,9 @@
#include <fdtdec.h>
#include <i2c.h>
#include <linux/bitops.h>
+#if IS_ENABLED(CONFIG_ARCH_AT91)
#include <mach/clk.h>
+#endif
#include "at91_i2c.h"
@@ -0,0 +1,25 @@
From a6a3c5438ae73a14fda838763f4ace4b2b6b9f20 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Mon, 19 Jan 2026 13:30:27 +0100
Subject: [PATCH 09/17] i2c: i2c-at91: allow selecting from ARCH_MICROCHIPSW
AT91 I2C driver is reused by a lot of Microchip platforms, in this case we
need it for LAN969x so allow selecting it when ARCH_MICROCHIPSW is used.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/i2c/Kconfig | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -163,7 +163,8 @@ config SYS_I2C_ADI
config SYS_I2C_AT91
bool "Atmel I2C driver"
- depends on DM_I2C && ARCH_AT91
+ depends on DM_I2C
+ depends on ARCH_AT91 || ARCH_MICROCHIPSW
help
Add support for the Atmel I2C driver. A serious problem is that there
is no documented way to issue repeated START conditions for more than
@@ -0,0 +1,23 @@
From 69a87c4153a874afbbb2319d0055f2a7ea419f9d Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 5 Dec 2025 14:34:36 +0100
Subject: [PATCH 10/17] usb: dwc3-generic: add support for Microchip LAN969x
Add Microchip LAN969x support, by using rk_ops as LAN969x uses single
node to describe glue and ctrl.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/usb/dwc3/dwc3-generic.c | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -731,6 +731,7 @@ static const struct udevice_id dwc3_glue
{ .compatible = "intel,tangier-dwc3" },
{ .compatible = "samsung,exynos7870-dwusb3" },
{ .compatible = "samsung,exynos850-dwusb3" },
+ { .compatible = "microchip,lan9691-dwc3", .data = (ulong)&rk_ops },
{ }
};
@@ -0,0 +1,59 @@
From c8ea2cc976d650f39cf8dd2021f951b669a0f233 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Mon, 15 Dec 2025 23:03:02 +0100
Subject: [PATCH 11/17] spi: atmel-quadspi: add Microchip LAN969x support
Add support for Microchip LAN969x SoC-s.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/spi/Kconfig | 2 +-
drivers/spi/atmel-quadspi.c | 11 +++++++++++
2 files changed, 12 insertions(+), 1 deletion(-)
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -103,7 +103,7 @@ config ATH79_SPI
config ATMEL_QSPI
bool "Atmel Quad SPI Controller"
- depends on ARCH_AT91
+ depends on ARCH_AT91 || ARCH_MICROCHIPSW
select SPI_MEM
help
Enable the Atmel Quad SPI controller in master mode. This driver
--- a/drivers/spi/atmel-quadspi.c
+++ b/drivers/spi/atmel-quadspi.c
@@ -24,7 +24,9 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/ioport.h>
+#if IS_ENABLED(CONFIG_ARCH_AT91)
#include <mach/clk.h>
+#endif
#include <spi.h>
#include <spi-mem.h>
@@ -1311,6 +1313,11 @@ static const struct atmel_qspi_caps atme
.has_gclk = true,
};
+static const struct atmel_qspi_caps microchip_lan9691_qspi_caps = {
+ .has_gclk = true,
+ .has_ricr = true,
+};
+
static const struct udevice_id atmel_qspi_ids[] = {
{
.compatible = "atmel,sama5d2-qspi",
@@ -1328,6 +1335,10 @@ static const struct udevice_id atmel_qsp
.compatible = "microchip,sama7g5-qspi",
.data = (ulong)&atmel_sama7g5_qspi_caps,
},
+ {
+ .compatible = "microchip,lan9691-qspi",
+ .data = (ulong)&microchip_lan9691_qspi_caps,
+ },
{ /* sentinel */ }
};
@@ -0,0 +1,230 @@
From cffde5cc761235f8e1ee0bd9644eb5beb7f8043e Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 23 Dec 2025 14:17:01 +0100
Subject: [PATCH 13/17] net: phy: add Microchip LAN8841 support
Add driver for the Microchip LAN8841 PHY.
It provides fixes for erratas, as well as support for enabling the required
RGMII delays based on the PHY mode.
It is based on the upstream Linux driver.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/net/phy/Kconfig | 3 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/microchip.c | 185 ++++++++++++++++++++++++++++++++++++
3 files changed, 189 insertions(+)
create mode 100644 drivers/net/phy/microchip.c
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -232,6 +232,9 @@ config PHY_MICREL_KSZ8XXX
endif # PHY_MICREL
+config PHY_MICROCHIP
+ bool "Microchip Ethernet PHYs support"
+
config PHY_MOTORCOMM
bool "Motorcomm PHYs"
help
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -25,6 +25,7 @@ obj-y += mediatek/
obj-y += airoha/
obj-$(CONFIG_PHY_MICREL_KSZ8XXX) += micrel_ksz8xxx.o
obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o
+obj-$(CONFIG_PHY_MICROCHIP) += microchip.o
obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o
obj-$(CONFIG_PHY_MOTORCOMM) += motorcomm.o
obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
--- /dev/null
+++ b/drivers/net/phy/microchip.c
@@ -0,0 +1,185 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <phy.h>
+#include <linux/bitops.h>
+
+#define PHY_ID_MATCH_MODEL_MASK GENMASK(31, 4)
+#define PHY_ID_LAN8841 0x00221650
+
+#define LAN8841_MMD_COMMON_CTRL_REG 2
+#define LAN8841_RXC_DLL_CTRL 76
+#define LAN8841_TXC_DLL_CTRL 77
+#define LAN8841_DLL_ENABLE_DELAY 0
+
+#define LAN8841_MMD_TIMER_REG 0
+#define LAN8841_MMD0_REGISTER_17 17
+#define LAN8841_MMD0_REGISTER_17_DROP_OPT(x) ((x) & 0x3)
+#define LAN8841_MMD0_REGISTER_17_XMIT_TOG_TX_DIS BIT(3)
+#define LAN8841_OPERATION_MODE_STRAP_OVERRIDE_LOW_REG 2
+#define LAN8841_OPERATION_MODE_STRAP_OVERRIDE_LOW_REG_MAGJACK BIT(14)
+#define LAN8841_MMD_ANALOG_REG 28
+#define LAN8841_ANALOG_CONTROL_1 1
+#define LAN8841_ANALOG_CONTROL_1_PLL_TRIM(x) (((x) & 0x3) << 5)
+#define LAN8841_ANALOG_CONTROL_10 13
+#define LAN8841_ANALOG_CONTROL_10_PLL_DIV(x) ((x) & 0x3)
+#define LAN8841_ANALOG_CONTROL_11 14
+#define LAN8841_ANALOG_CONTROL_11_LDO_REF(x) (((x) & 0x7) << 12)
+#define LAN8841_TX_LOW_I_CH_C_D_POWER_MANAGMENT 69
+#define LAN8841_TX_LOW_I_CH_C_D_POWER_MANAGMENT_VAL 0xbffc
+#define LAN8841_BTRX_POWER_DOWN 70
+#define LAN8841_BTRX_POWER_DOWN_QBIAS_CH_A BIT(0)
+#define LAN8841_BTRX_POWER_DOWN_BTRX_CH_A BIT(1)
+#define LAN8841_BTRX_POWER_DOWN_QBIAS_CH_B BIT(2)
+#define LAN8841_BTRX_POWER_DOWN_BTRX_CH_B BIT(3)
+#define LAN8841_BTRX_POWER_DOWN_BTRX_CH_C BIT(5)
+#define LAN8841_BTRX_POWER_DOWN_BTRX_CH_D BIT(7)
+#define LAN8841_ADC_CHANNEL_MASK 198
+#define LAN8841_PTP_RX_PARSE_L2_ADDR_EN 370
+#define LAN8841_PTP_RX_PARSE_IP_ADDR_EN 371
+#define LAN8841_PTP_RX_VERSION 374
+#define LAN8841_PTP_TX_PARSE_L2_ADDR_EN 434
+#define LAN8841_PTP_TX_PARSE_IP_ADDR_EN 435
+#define LAN8841_PTP_TX_VERSION 438
+#define LAN8841_PTP_CMD_CTL 256
+#define LAN8841_PTP_CMD_CTL_PTP_ENABLE BIT(2)
+#define LAN8841_PTP_CMD_CTL_PTP_DISABLE BIT(1)
+#define LAN8841_PTP_CMD_CTL_PTP_RESET BIT(0)
+#define LAN8841_PTP_RX_PARSE_CONFIG 368
+#define LAN8841_PTP_TX_PARSE_CONFIG 432
+#define LAN8841_PTP_RX_MODE 381
+#define LAN8841_PTP_INSERT_TS_EN BIT(0)
+#define LAN8841_PTP_INSERT_TS_32BIT BIT(1)
+
+static int lan8841_config_rgmii_delay(struct phy_device *phydev)
+{
+ u16 rxcdll_val, txcdll_val;
+ int ret;
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ rxcdll_val = BIT(14);
+ txcdll_val = BIT(14);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ rxcdll_val = LAN8841_DLL_ENABLE_DELAY;
+ txcdll_val = LAN8841_DLL_ENABLE_DELAY;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ rxcdll_val = LAN8841_DLL_ENABLE_DELAY;
+ txcdll_val = BIT(14);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ rxcdll_val = BIT(14);
+ txcdll_val = LAN8841_DLL_ENABLE_DELAY;
+ break;
+ default:
+ return 0;
+ }
+
+ ret = phy_modify_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_RXC_DLL_CTRL, BIT_MASK(14),
+ rxcdll_val);
+ if (ret < 0)
+ return ret;
+
+ return phy_modify_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_TXC_DLL_CTRL, BIT_MASK(14),
+ txcdll_val);
+}
+
+static int lan8841_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phy_interface_is_rgmii(phydev)) {
+ ret = lan8841_config_rgmii_delay(phydev);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Initialize the HW by resetting everything */
+ phy_modify_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_CMD_CTL,
+ LAN8841_PTP_CMD_CTL_PTP_RESET,
+ LAN8841_PTP_CMD_CTL_PTP_RESET);
+
+ phy_modify_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_CMD_CTL,
+ LAN8841_PTP_CMD_CTL_PTP_ENABLE,
+ LAN8841_PTP_CMD_CTL_PTP_ENABLE);
+
+ /* Don't process any frames */
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_RX_PARSE_CONFIG, 0);
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_TX_PARSE_CONFIG, 0);
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_TX_PARSE_L2_ADDR_EN, 0);
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_RX_PARSE_L2_ADDR_EN, 0);
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_TX_PARSE_IP_ADDR_EN, 0);
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_RX_PARSE_IP_ADDR_EN, 0);
+
+ /* Disable checking for minorVersionPTP field */
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_RX_VERSION, 0xff00);
+ phy_write_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_PTP_TX_VERSION, 0xff00);
+
+ /* 100BT Clause 40 improvement errata */
+ phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG,
+ LAN8841_ANALOG_CONTROL_1,
+ LAN8841_ANALOG_CONTROL_1_PLL_TRIM(0x2));
+ phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG,
+ LAN8841_ANALOG_CONTROL_10,
+ LAN8841_ANALOG_CONTROL_10_PLL_DIV(0x1));
+
+ /* 10M/100M Ethernet Signal Tuning Errata for Shorted-Center Tap
+ * Magnetics
+ */
+ ret = phy_read_mmd(phydev, LAN8841_MMD_COMMON_CTRL_REG,
+ LAN8841_OPERATION_MODE_STRAP_OVERRIDE_LOW_REG);
+ if (ret & LAN8841_OPERATION_MODE_STRAP_OVERRIDE_LOW_REG_MAGJACK) {
+ phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG,
+ LAN8841_TX_LOW_I_CH_C_D_POWER_MANAGMENT,
+ LAN8841_TX_LOW_I_CH_C_D_POWER_MANAGMENT_VAL);
+ phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG,
+ LAN8841_BTRX_POWER_DOWN,
+ LAN8841_BTRX_POWER_DOWN_QBIAS_CH_A |
+ LAN8841_BTRX_POWER_DOWN_BTRX_CH_A |
+ LAN8841_BTRX_POWER_DOWN_QBIAS_CH_B |
+ LAN8841_BTRX_POWER_DOWN_BTRX_CH_B |
+ LAN8841_BTRX_POWER_DOWN_BTRX_CH_C |
+ LAN8841_BTRX_POWER_DOWN_BTRX_CH_D);
+ }
+
+ /* LDO Adjustment errata */
+ phy_write_mmd(phydev, LAN8841_MMD_ANALOG_REG,
+ LAN8841_ANALOG_CONTROL_11,
+ LAN8841_ANALOG_CONTROL_11_LDO_REF(1));
+
+ /* 100BT RGMII latency tuning errata */
+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD,
+ LAN8841_ADC_CHANNEL_MASK, 0x0);
+ phy_write_mmd(phydev, LAN8841_MMD_TIMER_REG,
+ LAN8841_MMD0_REGISTER_17,
+ LAN8841_MMD0_REGISTER_17_DROP_OPT(2) |
+ LAN8841_MMD0_REGISTER_17_XMIT_TOG_TX_DIS);
+
+ /* Disable Power Down */
+ phy_modify(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_PDOWN, 0);
+
+ return 0;
+}
+
+U_BOOT_PHY_DRIVER(lan8841) = {
+ .name = "Microchip LAN8841",
+ .uid = PHY_ID_LAN8841,
+ .mask = PHY_ID_MATCH_MODEL_MASK,
+ .features = PHY_GBIT_FEATURES,
+ .config = &lan8841_config_init,
+ .startup = &genphy_startup,
+ .shutdown = &genphy_shutdown,
+};
@@ -0,0 +1,39 @@
From b7aef16df60bf7d0d46dc995a373d28eb4f50561 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 13 Jan 2026 12:20:37 +0100
Subject: [PATCH 16/17] microchip: lan969x: add OpenWrt default environment
Add the required default environment for OpenWrt.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
board/microchip/lan969x/lan969x.env | 12 ++++++++++++
configs/microchip_ev23x71a_defconfig | 1 +
2 files changed, 13 insertions(+)
create mode 100644 board/microchip/lan969x/lan969x.env
--- /dev/null
+++ b/board/microchip/lan969x/lan969x.env
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+fdt_high=0xffffffff
+baudrate=115200
+bootdelay=3
+loadaddr=0x64000000
+bootargs=console=ttyAT0,115200 root=PARTLABEL=rootfs rootwait
+mmc_read_kernel=mmc read $loadaddr $part_addr 0x100 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr $part_addr $image_size
+boot_system=part start mmc 0 kernel part_addr && part size mmc 0 kernel part_size && run mmc_read_kernel && bootm
+bootcmd=run boot_system
+filesize_to_blk=setexpr cnt $filesize + 0x1ff && setexpr cnt $cnt / 0x200
+mmc_write_fip=part start mmc 0 fip part_addr && part size mmc 0 fip part_size && run filesize_to_blk && test 0x$cnt -le 0x$part_size && mmc erase fip && mmc write $loadaddr $part_addr $cnt
--- a/configs/microchip_ev23x71a_defconfig
+++ b/configs/microchip_ev23x71a_defconfig
@@ -3,6 +3,7 @@ CONFIG_POSITION_INDEPENDENT=y
# CONFIG_ARM64_SUPPORT_AARCH32 is not set
CONFIG_ARCH_MICROCHIPSW=y
CONFIG_TFABOOT=y
+CONFIG_ENV_SOURCE_FILE="lan969x"
CONFIG_NR_DRAM_BANKS=3
CONFIG_ENV_OFFSET=0x0
CONFIG_DEFAULT_DEVICE_TREE="lan9696-ev23x71a"
@@ -1,6 +1,70 @@
From 909c1d76c0011578acb293412d08588cb6fec43e Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Mon, 19 Jan 2026 13:10:45 +0100
Subject: [PATCH 17/17] cmd: add imsz and imszb
These are used to get the image sizes in OpenWrt.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
boot/image-fit.c | 41 ++++++++++++++++++++++++++++
cmd/bootm.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
include/image.h | 1 +
3 files changed, 112 insertions(+)
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -2131,6 +2131,47 @@ static const char *fit_get_image_type_pr
return "unknown";
}
+size_t fit_get_totalsize(const void *fit)
+{
+ int ret, ndepth, noffset, images_noffset;
+ size_t data_size, hdrsize, img_total, max_size = 0;
+ const void *data;
+
+ ret = fdt_check_header(fit);
+ if (ret) {
+ debug("Wrong FIT format: not a flattened device tree (err=%d)\n",
+ ret);
+ return 0;
+ }
+
+ hdrsize = fdt_totalsize(fit);
+
+ /* take care of simple FIT with internal images */
+ max_size = hdrsize;
+
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0)
+ goto out;
+
+ for (ndepth = 0,
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ ret = fit_image_get_data(fit, noffset, &data, &data_size);
+ if (ret)
+ goto out;
+
+ img_total = data_size + (data - fit);
+
+ max_size = (max_size > img_total) ? max_size : img_total;
+ }
+ }
+
+out:
+ return max_size;
+}
+
int fit_image_load(struct bootm_headers *images, ulong addr,
const char **fit_unamep, const char **fit_uname_configp,
int arch, int ph_type, int bootstage_id,
--- a/cmd/bootm.c
+++ b/cmd/bootm.c
@@ -260,6 +260,76 @@ U_BOOT_CMD(
@@ -257,6 +257,76 @@ U_BOOT_CMD(
/* iminfo - print header info for a requested image */
/*******************************************************************/
#if defined(CONFIG_CMD_IMI)
@@ -77,59 +141,9 @@
static int do_iminfo(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -2054,6 +2054,47 @@ static const char *fit_get_image_type_pr
return "unknown";
}
+size_t fit_get_totalsize(const void *fit)
+{
+ int ret, ndepth, noffset, images_noffset;
+ size_t data_size, hdrsize, img_total, max_size = 0;
+ const void *data;
+
+ ret = fdt_check_header(fit);
+ if (ret) {
+ debug("Wrong FIT format: not a flattened device tree (err=%d)\n",
+ ret);
+ return 0;
+ }
+
+ hdrsize = fdt_totalsize(fit);
+
+ /* take care of simple FIT with internal images */
+ max_size = hdrsize;
+
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0)
+ goto out;
+
+ for (ndepth = 0,
+ noffset = fdt_next_node(fit, images_noffset, &ndepth);
+ (noffset >= 0) && (ndepth > 0);
+ noffset = fdt_next_node(fit, noffset, &ndepth)) {
+ if (ndepth == 1) {
+ ret = fit_image_get_data(fit, noffset, &data, &data_size);
+ if (ret)
+ goto out;
+
+ img_total = data_size + (data - fit);
+
+ max_size = (max_size > img_total) ? max_size : img_total;
+ }
+ }
+
+out:
+ return max_size;
+}
+
int fit_image_load(struct bootm_headers *images, ulong addr,
const char **fit_unamep, const char **fit_uname_configp,
int arch, int ph_type, int bootstage_id,
--- a/include/image.h
+++ b/include/image.h
@@ -1113,6 +1113,7 @@ int fit_parse_subimage(const char *spec,
@@ -1213,6 +1213,7 @@ int fit_parse_subimage(const char *spec,
ulong *addr, const char **image_name);
int fit_get_subimage_count(const void *fit, int images_noffset);
@@ -1,12 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
fdt_high=0xffffffff
baudrate=115200
bootdelay=3
loadaddr=0x64000000
bootargs=console=ttyAT0,115200 root=PARTLABEL=rootfs rootwait
mmc_read_kernel=mmc read $loadaddr $part_addr 0x100 && imszb $loadaddr image_size && test 0x$image_size -le 0x$part_size && mmc read $loadaddr $part_addr $image_size
boot_system=part start mmc 0 kernel part_addr && part size mmc 0 kernel part_size && run mmc_read_kernel && bootm
bootcmd=run boot_system
filesize_to_blk=setexpr cnt $filesize + 0x1ff && setexpr cnt $cnt / 0x200
mmc_write_fip=part start mmc 0 fip part_addr && part size mmc 0 fip part_size && run filesize_to_blk && test 0x$cnt -le 0x$part_size && mmc erase fip && mmc write $loadaddr $part_addr $cnt