From s.trumtrar at pengutronix.de  Mon Feb  3 00:23:22 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Mon, 03 Feb 2025 09:23:22 +0100
Subject: [PATCH] ARM: Layerscape: LS1046a: select early i2c
Message-ID: <20250203-v2025-01-0-topic-ls1046a-v1-1-2e2c372dbdb9@pengutronix.de>

The TQMLS1046a board uses i2c to determine the HW variant.
Therefore early i2c is needed.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 arch/arm/mach-layerscape/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-layerscape/Kconfig b/arch/arm/mach-layerscape/Kconfig
index 415ee93b996db780b49c807813a7d5bd4d2b5ecb..0f559863eccca1c46164f0fc034676e3990e5904 100644
--- a/arch/arm/mach-layerscape/Kconfig
+++ b/arch/arm/mach-layerscape/Kconfig
@@ -34,6 +34,7 @@ config MACH_TQMLS1046A
 	bool "TQ TQMLS1046A Board"
 	select ARCH_LS1046
 	select MCI_IMX_ESDHC_PBL
+	select I2C_IMX_EARLY
 	select DDR_FSL
 	select DDR_FSL_DDR4
 	select FIRMWARE_LS1046A_ATF

---
base-commit: fb590cfa8fea6906d3f78dd409856d350e24b582
change-id: 20250203-v2025-01-0-topic-ls1046a-8a7a62ffa605

Best regards,
-- 
Steffen Trumtrar <s.trumtrar at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb  3 01:17:27 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 03 Feb 2025 10:17:27 +0100
Subject: [PATCH] ARM: Layerscape: LS1046a: select early i2c
In-Reply-To: <20250203-v2025-01-0-topic-ls1046a-v1-1-2e2c372dbdb9@pengutronix.de>
References: <20250203-v2025-01-0-topic-ls1046a-v1-1-2e2c372dbdb9@pengutronix.de>
Message-ID: <173857424733.3522011.15635100404901542475.b4-ty@pengutronix.de>


On Mon, 03 Feb 2025 09:23:22 +0100, Steffen Trumtrar wrote:
> The TQMLS1046a board uses i2c to determine the HW variant.
> Therefore early i2c is needed.
> 
> 

Applied, thanks!

[1/1] ARM: Layerscape: LS1046a: select early i2c
      https://git.pengutronix.de/cgit/barebox/commit/?id=0a88e7d52b43 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb  3 01:18:17 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 03 Feb 2025 10:18:17 +0100
Subject: [PATCH] kbuild: Use uname for BAREBOX_COMPILE_HOST
In-Reply-To: <20250131-hostname-fix-v1-1-8d7ae619fcf4@gmail.com>
References: <20250131-hostname-fix-v1-1-8d7ae619fcf4@gmail.com>
Message-ID: <173857429720.3522156.14761012076799558840.b4-ty@pengutronix.de>


On Fri, 31 Jan 2025 22:59:08 -0500, David Dgien wrote:
> Adoption of Linux Commit:
> 
> | commit 1e66d50ad3a1dbf0169b14d502be59a4b1213149
> | Author: Chris Down <chris at chrisdown.name>
> | Date:   Tue Oct 20 10:34:59 2020 +0100
> |
> |     kbuild: Use uname for LINUX_COMPILE_HOST detection
> |
> |     `hostname` may not be present on some systems as it's not mandated by
> |     POSIX/SUSv4. This isn't just a theoretical problem: on Arch Linux,
> |     `hostname` is provided by `inetutils`, which isn't part of the base
> |     distribution.
> |
> |         ./scripts/mkcompile_h: line 38: hostname: command not found
> |
> |     Use `uname -n` instead, which is more likely to be available (and
> |     mandated by standards).
> |
> |     Signed-off-by: Chris Down <chris at chrisdown.name>
> |     Signed-off-by: Masahiro Yamada <masahiroy at kernel.org>
> 
> [...]

Applied, thanks!

[1/1] kbuild: Use uname for BAREBOX_COMPILE_HOST
      https://git.pengutronix.de/cgit/barebox/commit/?id=b001dfee2bd0 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From eagle.alexander923 at gmail.com  Mon Feb  3 23:31:50 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Tue,  4 Feb 2025 10:31:50 +0300
Subject: [PATCH] i2c: Remove dead link to struct i2c_algorithm
Message-ID: <20250204073151.16501-1-eagle.alexander923@gmail.com>

struct i2c_algorithm is not defined anywhere.

Signed-off-by: Alexander Shiyan <eagle.alexander923 at gmail.com>
---
 include/i2c/i2c-algo-bit.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/include/i2c/i2c-algo-bit.h b/include/i2c/i2c-algo-bit.h
index 91c8436188..e5c5fa817c 100644
--- a/include/i2c/i2c-algo-bit.h
+++ b/include/i2c/i2c-algo-bit.h
@@ -49,6 +49,5 @@ struct i2c_algo_bit_data {
 };
 
 int i2c_bit_add_numbered_bus(struct i2c_adapter *);
-extern const struct i2c_algorithm i2c_bit_algo;
 
 #endif /* _LINUX_I2C_ALGO_BIT_H */
-- 
2.39.1



From eagle.alexander923 at gmail.com  Tue Feb  4 05:22:07 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Tue,  4 Feb 2025 16:22:07 +0300
Subject: [PATCH] i2c: rockchip: Replace driver from kernel repository
Message-ID: <20250204132207.332918-1-eagle.alexander923@gmail.com>

The current Rockchip i2c driver was taken from the u-boot repository,
so it has minimal functionality and is designed to be the simplest.
Development with the Rockchip SOC led to the idea that it is not
sufficient to handle some i2c devices (in my case, this i2c EEPROMs
and i2c MUXes).
This patch replaces the driver code from the Linux kernel repository
to make the driver more flexible with SDA/SCL setup/hold settings and
as a result, more stable across boards.
Tested with cusom rk3568-based board.

Signed-off-by: Alexander Shiyan <eagle.alexander923 at gmail.com>
---
 drivers/i2c/busses/Makefile       |    2 +-
 drivers/i2c/busses/i2c-rk3x.c     | 1176 +++++++++++++++++++++++++++++
 drivers/i2c/busses/i2c-rockchip.c |  462 ------------
 3 files changed, 1177 insertions(+), 463 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-rk3x.c
 delete mode 100644 drivers/i2c/busses/i2c-rockchip.c

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 30005c2bf8..f7ae1d1f83 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -12,5 +12,5 @@ obj-$(CONFIG_I2C_TEGRA)		+= i2c-tegra.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
 obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o
 obj-$(CONFIG_I2C_STM32)		+= i2c-stm32.o
-obj-$(CONFIG_I2C_RK3X)		+= i2c-rockchip.o
+obj-$(CONFIG_I2C_RK3X)		+= i2c-rk3x.o
 obj-$(CONFIG_I2C_CADENCE)	+= i2c-cadence.o
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
new file mode 100644
index 0000000000..c7566dd2c4
--- /dev/null
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -0,0 +1,1176 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for I2C adapter in Rockchip RK3xxx SoC
+ *
+ * Max Schwarz <max.schwarz at online.de>
+ * based on the patches by Rockchip Inc.
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <i2c/i2c.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <mfd/syscon.h>
+
+/* Register Map */
+#define REG_CON			0x00 /* control register */
+#define REG_CLKDIV		0x04 /* clock divisor register */
+#define REG_MRXADDR		0x08 /* target address for REGISTER_TX */
+#define REG_MRXRADDR		0x0c /* target register address for REGISTER_TX */
+#define REG_MTXCNT		0x10 /* number of bytes to be transmitted */
+#define REG_MRXCNT		0x14 /* number of bytes to be received */
+#define REG_IEN			0x18 /* interrupt enable */
+#define REG_IPD			0x1c /* interrupt pending */
+#define REG_FCNT		0x20 /* finished count */
+
+/* Data buffer offsets */
+#define TXBUFFER_BASE		0x100
+#define RXBUFFER_BASE		0x200
+
+/* REG_CON bits */
+#define REG_CON_EN		BIT(0)
+enum {
+	REG_CON_MOD_TX = 0,		/* transmit data */
+	REG_CON_MOD_REGISTER_TX,	/* select register and restart */
+	REG_CON_MOD_RX,			/* receive data */
+	REG_CON_MOD_REGISTER_RX,	/* broken: transmits read addr AND writes
+					 * register addr */
+};
+#define REG_CON_MOD(mod)	((mod) << 1)
+#define REG_CON_MOD_MASK	(BIT(1) | BIT(2))
+#define REG_CON_START		BIT(3)
+#define REG_CON_STOP		BIT(4)
+#define REG_CON_LASTACK		BIT(5) /* 1: send NACK after last received byte */
+#define REG_CON_ACTACK		BIT(6) /* 1: stop if NACK is received */
+
+#define REG_CON_TUNING_MASK GENMASK_ULL(15, 8)
+
+#define REG_CON_SDA_CFG(cfg)	((cfg) << 8)
+#define REG_CON_STA_CFG(cfg)	((cfg) << 12)
+#define REG_CON_STO_CFG(cfg)	((cfg) << 14)
+
+/* REG_MRXADDR bits */
+#define REG_MRXADDR_VALID(x)	BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
+
+/* REG_IEN/REG_IPD bits */
+#define REG_INT_BTF		BIT(0) /* a byte was transmitted */
+#define REG_INT_BRF		BIT(1) /* a byte was received */
+#define REG_INT_MBTF		BIT(2) /* controller data transmit finished */
+#define REG_INT_MBRF		BIT(3) /* controller data receive finished */
+#define REG_INT_START		BIT(4) /* START condition generated */
+#define REG_INT_STOP		BIT(5) /* STOP condition generated */
+#define REG_INT_NAKRCV		BIT(6) /* NACK received */
+#define REG_INT_ALL		0x7f
+
+/* Constants */
+#define WAIT_TIMEOUT		SECOND
+#define DEFAULT_SCL_RATE	(100 * 1000) /* Hz */
+
+/**
+ * struct i2c_spec_values - I2C specification values for various modes
+ * @min_hold_start_ns: min hold time (repeated) START condition
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
+ */
+struct i2c_spec_values {
+	unsigned long min_hold_start_ns;
+	unsigned long min_low_ns;
+	unsigned long min_high_ns;
+	unsigned long min_setup_start_ns;
+	unsigned long max_data_hold_ns;
+	unsigned long min_data_setup_ns;
+	unsigned long min_setup_stop_ns;
+	unsigned long min_hold_buffer_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+	.min_hold_start_ns = 4000,
+	.min_low_ns = 4700,
+	.min_high_ns = 4000,
+	.min_setup_start_ns = 4700,
+	.max_data_hold_ns = 3450,
+	.min_data_setup_ns = 250,
+	.min_setup_stop_ns = 4000,
+	.min_hold_buffer_ns = 4700,
+};
+
+static const struct i2c_spec_values fast_mode_spec = {
+	.min_hold_start_ns = 600,
+	.min_low_ns = 1300,
+	.min_high_ns = 600,
+	.min_setup_start_ns = 600,
+	.max_data_hold_ns = 900,
+	.min_data_setup_ns = 100,
+	.min_setup_stop_ns = 600,
+	.min_hold_buffer_ns = 1300,
+};
+
+static const struct i2c_spec_values fast_mode_plus_spec = {
+	.min_hold_start_ns = 260,
+	.min_low_ns = 500,
+	.min_high_ns = 260,
+	.min_setup_start_ns = 260,
+	.max_data_hold_ns = 400,
+	.min_data_setup_ns = 50,
+	.min_setup_stop_ns = 260,
+	.min_hold_buffer_ns = 500,
+};
+
+/**
+ * struct rk3x_i2c_calced_timings - calculated V1 timings
+ * @div_low: Divider output for low
+ * @div_high: Divider output for high
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
+ */
+struct rk3x_i2c_calced_timings {
+	unsigned long div_low;
+	unsigned long div_high;
+	unsigned int tuning;
+};
+
+enum rk3x_i2c_state {
+	STATE_IDLE,
+	STATE_START,
+	STATE_READ,
+	STATE_WRITE,
+	STATE_STOP
+};
+
+/**
+ * struct rk3x_i2c_soc_data - SOC-specific data
+ * @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
+ */
+struct rk3x_i2c_soc_data {
+	int grf_offset;
+	int (*calc_timings)(unsigned long, struct i2c_timings *,
+			    struct rk3x_i2c_calced_timings *);
+};
+
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
+ * @t: I2C known timing information
+ * @msg: current i2c message
+ * @addr: addr of i2c target device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
+struct rk3x_i2c {
+	struct i2c_adapter adap;
+	struct device *dev;
+	const struct rk3x_i2c_soc_data *soc_data;
+
+	/* Hardware resources */
+	void __iomem *regs;
+	struct clk *clk;
+	struct clk *pclk;
+
+	/* Settings */
+	struct i2c_timings t;
+
+	/* Current message */
+	struct i2c_msg *msg;
+	u8 addr;
+	unsigned int mode;
+	bool is_last_msg;
+
+	/* I2C state machine */
+	enum rk3x_i2c_state state;
+	unsigned int processed;
+	int error;
+};
+
+static inline void i2c_writel(struct rk3x_i2c *i2c, u32 value,
+			      unsigned int offset)
+{
+	writel(value, i2c->regs + offset);
+}
+
+static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset)
+{
+	return readl(i2c->regs + offset);
+}
+
+/* Reset all interrupt pending bits */
+static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
+{
+	i2c_writel(i2c, REG_INT_ALL, REG_IPD);
+}
+
+/**
+ * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt.
+ * @i2c: target controller data
+ */
+static void rk3x_i2c_start(struct rk3x_i2c *i2c)
+{
+	u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+
+	i2c_writel(i2c, REG_INT_START, REG_IEN);
+
+	/* enable adapter with correct mode, send START condition */
+	val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+
+	/* if we want to react to NACK, set ACTACK bit */
+	if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
+		val |= REG_CON_ACTACK;
+
+	i2c_writel(i2c, val, REG_CON);
+}
+
+/**
+ * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
+ * @i2c: target controller data
+ * @error: Error code to return in rk3x_i2c_xfer
+ */
+static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
+{
+	unsigned int ctrl;
+
+	i2c->processed = 0;
+	i2c->msg = NULL;
+	i2c->error = error;
+
+	if (i2c->is_last_msg) {
+		/* Enable stop interrupt */
+		i2c_writel(i2c, REG_INT_STOP, REG_IEN);
+
+		i2c->state = STATE_STOP;
+
+		ctrl = i2c_readl(i2c, REG_CON);
+		ctrl |= REG_CON_STOP;
+		i2c_writel(i2c, ctrl, REG_CON);
+	} else {
+		/* Signal rk3x_i2c_xfer to start the next message. */
+		i2c->state = STATE_IDLE;
+
+		/*
+		 * The HW is actually not capable of REPEATED START. But we can
+		 * get the intended effect by resetting its internal state
+		 * and issuing an ordinary START.
+		 */
+		ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+		i2c_writel(i2c, ctrl, REG_CON);
+	}
+}
+
+/**
+ * rk3x_i2c_prepare_read - Setup a read according to i2c->msg
+ * @i2c: target controller data
+ */
+static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
+{
+	unsigned int len = i2c->msg->len - i2c->processed;
+	u32 con;
+
+	con = i2c_readl(i2c, REG_CON);
+
+	/*
+	 * The hw can read up to 32 bytes at a time. If we need more than one
+	 * chunk, send an ACK after the last byte of the current chunk.
+	 */
+	if (len > 32) {
+		len = 32;
+		con &= ~REG_CON_LASTACK;
+	} else {
+		con |= REG_CON_LASTACK;
+	}
+
+	/* make sure we are in plain RX mode if we read a second chunk */
+	if (i2c->processed != 0) {
+		con &= ~REG_CON_MOD_MASK;
+		con |= REG_CON_MOD(REG_CON_MOD_RX);
+	}
+
+	i2c_writel(i2c, con, REG_CON);
+	i2c_writel(i2c, len, REG_MRXCNT);
+}
+
+/**
+ * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg
+ * @i2c: target controller data
+ */
+static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c)
+{
+	unsigned int i, j;
+	u32 cnt = 0;
+	u32 val;
+	u8 byte;
+
+	for (i = 0; i < 8; ++i) {
+		val = 0;
+		for (j = 0; j < 4; ++j) {
+			if ((i2c->processed == i2c->msg->len) && (cnt != 0))
+				break;
+
+			if (i2c->processed == 0 && cnt == 0)
+				byte = (i2c->addr & 0x7f) << 1;
+			else
+				byte = i2c->msg->buf[i2c->processed++];
+
+			val |= byte << (j * 8);
+			cnt++;
+		}
+
+		i2c_writel(i2c, val, TXBUFFER_BASE + 4 * i);
+
+		if (i2c->processed == i2c->msg->len)
+			break;
+	}
+
+	i2c_writel(i2c, cnt, REG_MTXCNT);
+}
+
+/* IRQ handlers for individual states */
+
+static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+	if (!(ipd & REG_INT_START)) {
+		rk3x_i2c_stop(i2c, -EIO);
+		dev_warn(i2c->dev, "unexpected irq in START: 0x%x\n", ipd);
+		rk3x_i2c_clean_ipd(i2c);
+		return;
+	}
+
+	/* ack interrupt */
+	i2c_writel(i2c, REG_INT_START, REG_IPD);
+
+	/* disable start bit */
+	i2c_writel(i2c, i2c_readl(i2c, REG_CON) & ~REG_CON_START, REG_CON);
+
+	/* enable appropriate interrupts and transition */
+	if (i2c->mode == REG_CON_MOD_TX) {
+		i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN);
+		i2c->state = STATE_WRITE;
+		rk3x_i2c_fill_transmit_buf(i2c);
+	} else {
+		/* in any other case, we are going to be reading. */
+		i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN);
+		i2c->state = STATE_READ;
+		rk3x_i2c_prepare_read(i2c);
+	}
+}
+
+static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+	if (!(ipd & REG_INT_MBTF)) {
+		rk3x_i2c_stop(i2c, -EIO);
+		dev_err(i2c->dev, "unexpected irq in WRITE: 0x%x\n", ipd);
+		rk3x_i2c_clean_ipd(i2c);
+		return;
+	}
+
+	/* ack interrupt */
+	i2c_writel(i2c, REG_INT_MBTF, REG_IPD);
+
+	/* are we finished? */
+	if (i2c->processed == i2c->msg->len)
+		rk3x_i2c_stop(i2c, i2c->error);
+	else
+		rk3x_i2c_fill_transmit_buf(i2c);
+}
+
+static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+	unsigned int i, len = i2c->msg->len - i2c->processed;
+	u32 val = 0;
+	u8 byte;
+
+	/* we only care for MBRF here. */
+	if (!(ipd & REG_INT_MBRF))
+		return;
+
+	/* ack interrupt (read also produces a spurious START flag, clear it too) */
+	i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD);
+
+	/* Can only handle a maximum of 32 bytes at a time */
+	if (len > 32)
+		len = 32;
+
+	/* read the data from receive buffer */
+	for (i = 0; i < len; ++i) {
+		if (i % 4 == 0)
+			val = i2c_readl(i2c, RXBUFFER_BASE + (i / 4) * 4);
+
+		byte = (val >> ((i % 4) * 8)) & 0xff;
+		i2c->msg->buf[i2c->processed++] = byte;
+	}
+
+	/* are we finished? */
+	if (i2c->processed == i2c->msg->len)
+		rk3x_i2c_stop(i2c, i2c->error);
+	else
+		rk3x_i2c_prepare_read(i2c);
+}
+
+static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, unsigned int ipd)
+{
+	unsigned int con;
+
+	if (!(ipd & REG_INT_STOP)) {
+		rk3x_i2c_stop(i2c, -EIO);
+		dev_err(i2c->dev, "unexpected irq in STOP: 0x%x\n", ipd);
+		rk3x_i2c_clean_ipd(i2c);
+		return;
+	}
+
+	/* ack interrupt */
+	i2c_writel(i2c, REG_INT_STOP, REG_IPD);
+
+	/* disable STOP bit */
+	con = i2c_readl(i2c, REG_CON);
+	con &= ~REG_CON_STOP;
+	i2c_writel(i2c, con, REG_CON);
+
+	i2c->state = STATE_IDLE;
+}
+
+static void rk3x_i2c_irq(struct rk3x_i2c *i2c)
+{
+	unsigned int ipd = i2c_readl(i2c, REG_IPD);
+
+	dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd);
+
+	/* Clean interrupt bits we don't care about */
+	ipd &= ~(REG_INT_BRF | REG_INT_BTF);
+
+	if (ipd & REG_INT_NAKRCV) {
+		/*
+		 * We got a NACK in the last operation. Depending on whether
+		 * IGNORE_NAK is set, we have to stop the operation and report
+		 * an error.
+		 */
+		i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD);
+
+		ipd &= ~REG_INT_NAKRCV;
+
+		if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
+			rk3x_i2c_stop(i2c, -ENXIO);
+	}
+
+	/* is there anything left to handle? */
+	if ((ipd & REG_INT_ALL) == 0)
+		return;
+
+	switch (i2c->state) {
+	case STATE_START:
+		rk3x_i2c_handle_start(i2c, ipd);
+		break;
+	case STATE_WRITE:
+		rk3x_i2c_handle_write(i2c, ipd);
+		break;
+	case STATE_READ:
+		rk3x_i2c_handle_read(i2c, ipd);
+		break;
+	case STATE_STOP:
+		rk3x_i2c_handle_stop(i2c, ipd);
+		break;
+	default:
+		break;
+	}
+}
+
+/**
+ * rk3x_i2c_get_spec - Get timing values of I2C specification
+ * @speed: Desired SCL frequency
+ *
+ * Return: Matched i2c_spec_values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+	if (speed <= I2C_MAX_STANDARD_MODE_FREQ)
+		return &standard_mode_spec;
+	else if (speed <= I2C_MAX_FAST_MODE_FREQ)
+		return &fast_mode_spec;
+	else
+		return &fast_mode_plus_spec;
+}
+
+/**
+ * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
+ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ */
+static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
+{
+	unsigned long min_low_ns, min_high_ns;
+	unsigned long max_low_ns, min_total_ns;
+
+	unsigned long clk_rate_khz, scl_rate_khz;
+
+	unsigned long min_low_div, min_high_div;
+	unsigned long max_low_div;
+
+	unsigned long min_div_for_hold, min_total_div;
+	unsigned long extra_div, extra_low_div, ideal_low_div;
+
+	unsigned long data_hold_buffer_ns = 50;
+	const struct i2c_spec_values *spec;
+	int ret = 0;
+
+	/* Only support standard-mode and fast-mode */
+	if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ))
+		t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
+
+	/* prevent scl_rate_khz from becoming 0 */
+	if (WARN_ON(t->bus_freq_hz < 1000))
+		t->bus_freq_hz = 1000;
+
+	/*
+	 * min_low_ns:  The minimum number of ns we need to hold low to
+	 *		meet I2C specification, should include fall time.
+	 * min_high_ns: The minimum number of ns we need to hold high to
+	 *		meet I2C specification, should include rise time.
+	 * max_low_ns:  The maximum number of ns we can hold low to meet
+	 *		I2C specification.
+	 *
+	 * Note: max_low_ns should be (maximum data hold time * 2 - buffer)
+	 *	 This is because the i2c host on Rockchip holds the data line
+	 *	 for half the low time.
+	 */
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+
+	/*
+	 * Timings for repeated start:
+	 * - controller appears to drop SDA at .875x (7/8) programmed clk high.
+	 * - controller appears to keep SCL high for 2x programmed clk high.
+	 *
+	 * We need to account for those rules in picking our "high" time so
+	 * we meet tSU;STA and tHD;STA times.
+	 */
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+		spec->min_high_ns), 2));
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	max_low_ns =  spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
+	min_total_ns = min_low_ns + min_high_ns;
+
+	/* Adjust to avoid overflow */
+	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+	scl_rate_khz = t->bus_freq_hz / 1000;
+
+	/*
+	 * We need the total div to be >= this number
+	 * so we don't clock too fast.
+	 */
+	min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+	/* These are the min dividers needed for min hold times. */
+	min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+	min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+	min_div_for_hold = (min_low_div + min_high_div);
+
+	/*
+	 * This is the maximum divider so we don't go over the maximum.
+	 * We don't round up here (we round down) since this is a maximum.
+	 */
+	max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
+
+	if (min_low_div > max_low_div) {
+		WARN_ONCE(true,
+			  "Conflicting, min_low_div %lu, max_low_div %lu\n",
+			  min_low_div, max_low_div);
+		max_low_div = min_low_div;
+	}
+
+	if (min_div_for_hold > min_total_div) {
+		/*
+		 * Time needed to meet hold requirements is important.
+		 * Just use that.
+		 */
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
+	} else {
+		/*
+		 * We've got to distribute some time among the low and high
+		 * so we don't run too fast.
+		 */
+		extra_div = min_total_div - min_div_for_hold;
+
+		/*
+		 * We'll try to split things up perfectly evenly,
+		 * biasing slightly towards having a higher div
+		 * for low (spend more time low).
+		 */
+		ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
+					     scl_rate_khz * 8 * min_total_ns);
+
+		/* Don't allow it to go over the maximum */
+		if (ideal_low_div > max_low_div)
+			ideal_low_div = max_low_div;
+
+		/*
+		 * Handle when the ideal low div is going to take up
+		 * more than we have.
+		 */
+		if (ideal_low_div > min_low_div + extra_div)
+			ideal_low_div = min_low_div + extra_div;
+
+		/* Give low the "ideal" and give high whatever extra is left */
+		extra_low_div = ideal_low_div - min_low_div;
+		t_calc->div_low = ideal_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+	}
+
+	/*
+	 * Adjust to the fact that the hardware has an implicit "+1".
+	 * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
+	 */
+	t_calc->div_low--;
+	t_calc->div_high--;
+
+	/* Give the tuning value 0, that would not update con register */
+	t_calc->tuning = 0;
+	/* Maximum divider supported by hw is 0xffff */
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
+		ret = -EINVAL;
+	}
+
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+/**
+ * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
+ * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ * The following formulas are v1's method to calculate timings.
+ *
+ * l = divl + 1;
+ * h = divh + 1;
+ * s = sda_update_config + 1;
+ * u = start_setup_config + 1;
+ * p = stop_setup_config + 1;
+ * T = Tclk_i2c;
+ *
+ * tHigh = 8 * h * T;
+ * tLow = 8 * l * T;
+ *
+ * tHD;sda = (l * s + 1) * T;
+ * tSU;sda = [(8 - s) * l + 1] * T;
+ * tI2C = 8 * (l + h) * T;
+ *
+ * tSU;sta = (8h * u + 1) * T;
+ * tHD;sta = [8h * (u + 1) - 1] * T;
+ * tSU;sto = (8h * p + 1) * T;
+ */
+static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
+{
+	unsigned long min_low_ns, min_high_ns;
+	unsigned long min_setup_start_ns, min_setup_data_ns;
+	unsigned long min_setup_stop_ns, max_hold_data_ns;
+
+	unsigned long clk_rate_khz, scl_rate_khz;
+
+	unsigned long min_low_div, min_high_div;
+
+	unsigned long min_div_for_hold, min_total_div;
+	unsigned long extra_div, extra_low_div;
+	unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
+
+	const struct i2c_spec_values *spec;
+	int ret = 0;
+
+	/* Support standard-mode, fast-mode and fast-mode plus */
+	if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ))
+		t->bus_freq_hz = I2C_MAX_FAST_MODE_PLUS_FREQ;
+
+	/* prevent scl_rate_khz from becoming 0 */
+	if (WARN_ON(t->bus_freq_hz < 1000))
+		t->bus_freq_hz = 1000;
+
+	/*
+	 * min_low_ns: The minimum number of ns we need to hold low to
+	 *	       meet I2C specification, should include fall time.
+	 * min_high_ns: The minimum number of ns we need to hold high to
+	 *	        meet I2C specification, should include rise time.
+	 */
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+
+	/* calculate min-divh and min-divl */
+	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+	scl_rate_khz = t->bus_freq_hz / 1000;
+	min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+	min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+
+	/*
+	 * Final divh and divl must be greater than 0, otherwise the
+	 * hardware would not output the i2c clk.
+	 */
+	min_high_div = (min_high_div < 1) ? 2 : min_high_div;
+	min_low_div = (min_low_div < 1) ? 2 : min_low_div;
+
+	/* These are the min dividers needed for min hold times. */
+	min_div_for_hold = (min_low_div + min_high_div);
+
+	/*
+	 * This is the maximum divider so we don't go over the maximum.
+	 * We don't round up here (we round down) since this is a maximum.
+	 */
+	if (min_div_for_hold >= min_total_div) {
+		/*
+		 * Time needed to meet hold requirements is important.
+		 * Just use that.
+		 */
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
+	} else {
+		/*
+		 * We've got to distribute some time among the low and high
+		 * so we don't run too fast.
+		 * We'll try to split things up by the scale of min_low_div and
+		 * min_high_div, biasing slightly towards having a higher div
+		 * for low (spend more time low).
+		 */
+		extra_div = min_total_div - min_div_for_hold;
+		extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
+					     min_div_for_hold);
+
+		t_calc->div_low = min_low_div + extra_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+	}
+
+	/*
+	 * calculate sda data hold count by the rules, data_upd_st:3
+	 * is a appropriate value to reduce calculated times.
+	 */
+	for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
+		max_hold_data_ns =  DIV_ROUND_UP((sda_update_cfg
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+		    (min_setup_data_ns > spec->min_data_setup_ns))
+			break;
+	}
+
+	/* calculate setup start config */
+	min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+	stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	/* calculate setup stop config */
+	min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+	stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+			 REG_CON_STA_CFG(--stp_sta_cfg) |
+			 REG_CON_STO_CFG(--stp_sto_cfg);
+
+	t_calc->div_low--;
+	t_calc->div_high--;
+
+	/* Maximum divider supported by hw is 0xffff */
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
+		ret = -EINVAL;
+	}
+
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
+{
+	struct i2c_timings *t = &i2c->t;
+	struct rk3x_i2c_calced_timings calc;
+	u64 t_low_ns, t_high_ns;
+	u32 val;
+	int ret;
+
+	ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
+	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
+
+	clk_enable(i2c->pclk);
+
+	val = i2c_readl(i2c, REG_CON);
+	val &= ~REG_CON_TUNING_MASK;
+	val |= calc.tuning;
+	i2c_writel(i2c, val, REG_CON);
+	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+		   REG_CLKDIV);
+
+	clk_disable(i2c->pclk);
+
+	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+			    clk_rate);
+	dev_dbg(i2c->dev,
+		"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
+		clk_rate / 1000,
+		1000000000 / t->bus_freq_hz,
+		t_low_ns, t_high_ns);
+}
+
+/**
+ * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num.
+ * @i2c: target controller data
+ * @msgs: I2C msgs to process
+ * @num: Number of msgs
+ *
+ * Return: Number of I2C msgs processed or negative in case of error
+ */
+static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
+{
+	u32 addr = (msgs[0].addr & 0x7f) << 1;
+	int ret = 0;
+
+	/*
+	 * The I2C adapter can issue a small (len < 4) write packet before
+	 * reading. This speeds up SMBus-style register reads.
+	 * The MRXADDR/MRXRADDR hold the target address and the target register
+	 * address in this case.
+	 */
+
+	if (num >= 2 && msgs[0].len < 4 &&
+	    !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
+		u32 reg_addr = 0;
+		int i;
+
+		dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n",
+			addr >> 1);
+
+		/* Fill MRXRADDR with the register address(es) */
+		for (i = 0; i < msgs[0].len; ++i) {
+			reg_addr |= msgs[0].buf[i] << (i * 8);
+			reg_addr |= REG_MRXADDR_VALID(i);
+		}
+
+		/* msgs[0] is handled by hw. */
+		i2c->msg = &msgs[1];
+
+		i2c->mode = REG_CON_MOD_REGISTER_TX;
+
+		i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR);
+		i2c_writel(i2c, reg_addr, REG_MRXRADDR);
+
+		ret = 2;
+	} else {
+		/*
+		 * We'll have to do it the boring way and process the msgs
+		 * one-by-one.
+		 */
+
+		if (msgs[0].flags & I2C_M_RD) {
+			addr |= 1; /* set read bit */
+
+			/*
+			 * We have to transmit the target addr first. Use
+			 * MOD_REGISTER_TX for that purpose.
+			 */
+			i2c->mode = REG_CON_MOD_REGISTER_TX;
+			i2c_writel(i2c, addr | REG_MRXADDR_VALID(0),
+				   REG_MRXADDR);
+			i2c_writel(i2c, 0, REG_MRXRADDR);
+		} else {
+			i2c->mode = REG_CON_MOD_TX;
+		}
+
+		i2c->msg = &msgs[0];
+
+		ret = 1;
+	}
+
+	i2c->addr = msgs[0].addr;
+	i2c->state = STATE_START;
+	i2c->processed = 0;
+	i2c->error = 0;
+
+	rk3x_i2c_clean_ipd(i2c);
+
+	return ret;
+}
+
+static int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c)
+{
+	uint64_t start = get_time_ns();
+
+	while (!is_timeout(start, WAIT_TIMEOUT)) {
+		rk3x_i2c_irq(i2c);
+		if (i2c->state == STATE_IDLE)
+			return 0;
+		udelay(5);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int rk3x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
+	u32 val;
+	int i, ret = 0;
+
+	clk_enable(i2c->clk);
+	clk_enable(i2c->pclk);
+
+	i2c->is_last_msg = false;
+
+	/*
+	 * Process msgs. We can handle more than one message at once (see
+	 * rk3x_i2c_setup()).
+	 */
+	for (i = 0; i < num; i += ret) {
+		int xfer_ret;
+
+		ret = rk3x_i2c_setup(i2c, msgs + i, num - i);
+		if (ret < 0) {
+			dev_err(i2c->dev, "rk3x_i2c_setup() failed\n");
+			break;
+		}
+
+		if (i + ret >= num)
+			i2c->is_last_msg = true;
+
+		rk3x_i2c_start(i2c);
+
+		xfer_ret = rk3x_i2c_wait_xfer_poll(i2c);
+		if (xfer_ret) {
+			/* Force a STOP condition without interrupt */
+			i2c_writel(i2c, 0, REG_IEN);
+			val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+			val |= REG_CON_EN | REG_CON_STOP;
+			i2c_writel(i2c, val, REG_CON);
+
+			i2c->state = STATE_IDLE;
+
+			ret = xfer_ret;
+			break;
+		}
+
+		if (i2c->error) {
+			ret = i2c->error;
+			break;
+		}
+	}
+
+	clk_disable(i2c->pclk);
+	clk_disable(i2c->clk);
+
+	return ret < 0 ? ret : num;
+}
+
+static const struct rk3x_i2c_soc_data rv1108_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v1_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rv1126_soc_data = {
+	.grf_offset = 0x118,
+	.calc_timings = rk3x_i2c_v1_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+	.grf_offset = 0x154,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+	.grf_offset = 0x0a4,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v1_calc_timings,
+};
+
+static const struct of_device_id rk3x_i2c_match[] = {
+	{
+		.compatible = "rockchip,rv1108-i2c",
+		.data = &rv1108_soc_data
+	},
+	{
+		.compatible = "rockchip,rv1126-i2c",
+		.data = &rv1126_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3066-i2c",
+		.data = &rk3066_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3188-i2c",
+		.data = &rk3188_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3228-i2c",
+		.data = &rk3228_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3288-i2c",
+		.data = &rk3288_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3399-i2c",
+		.data = &rk3399_soc_data
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
+
+static int rk3x_i2c_probe(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct rk3x_i2c_soc_data *data;
+	struct resource *iores;
+	unsigned long clk_rate;
+	struct rk3x_i2c *i2c;
+	int ret;
+
+	i2c = xzalloc(sizeof(*i2c));
+	i2c->dev = dev;
+
+	ret = dev_get_drvdata(dev, (const void **)&data);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to retrieve driver data\n");
+
+	i2c->soc_data = data;
+
+	/* use common interface to get I2C timing properties */
+	i2c_parse_fw_timings(dev, &i2c->t, true);
+
+	i2c->adap.master_xfer = rk3x_i2c_xfer;
+	i2c->adap.retries = 3;
+	i2c->adap.dev.of_node = np;
+	i2c->adap.algo_data = i2c;
+	i2c->adap.dev.parent = dev;
+	i2c->adap.nr = of_alias_get_id(np, "i2c");
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	dev->priv = i2c;
+	i2c->regs = IOMEM(iores->start);
+
+	/*
+	 * Switch to new interface if the SoC also offers the old one.
+	 * The control bit is located in the GRF register space.
+	 */
+	if (i2c->soc_data->grf_offset >= 0) {
+		struct regmap *grf;
+		u32 value;
+
+		grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+		if (IS_ERR(grf))
+			return dev_err_probe(dev, PTR_ERR(grf),
+					     "rk3x-i2c needs 'rockchip,grf' property\n");
+
+		if (i2c->adap.nr < 0)
+			return dev_err_probe(dev, -EINVAL,
+					     "rk3x-i2c needs i2cX alias\n");
+
+		/* rv1126 i2c2 uses non-sequential write mask 20, value 4 */
+		if (i2c->soc_data == &rv1126_soc_data && i2c->adap.nr == 2)
+			value = BIT(20) | BIT(4);
+		else
+			/* 27+i: write mask, 11+i: value */
+			value = BIT(27 + i2c->adap.nr) | BIT(11 + i2c->adap.nr);
+
+		ret = regmap_write(grf, i2c->soc_data->grf_offset, value);
+		if (ret)
+			return dev_err_probe(dev, ret, "Could not write to GRF\n");
+	}
+
+	if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
+		/* Only one clock to use for bus clock and peripheral clock */
+		i2c->clk = clk_get(dev, NULL);
+		i2c->pclk = i2c->clk;
+	} else {
+		i2c->clk = clk_get(dev, "i2c");
+		i2c->pclk = clk_get(dev, "pclk");
+	}
+
+	if (IS_ERR(i2c->clk))
+		return dev_err_probe(dev, PTR_ERR(i2c->clk),
+				     "Can't get bus clk\n");
+
+	if (IS_ERR(i2c->pclk))
+		return dev_err_probe(dev, PTR_ERR(i2c->pclk),
+				     "Can't get periph clk\n");
+
+	ret = clk_enable(i2c->clk);
+	if (ret < 0)
+		return dev_err_probe(dev, ret,  "Can't enable bus clk\n");
+
+	clk_rate = clk_get_rate(i2c->clk);
+	rk3x_i2c_adapt_div(i2c, clk_rate);
+
+	clk_disable(i2c->clk);
+
+	return i2c_add_numbered_adapter(&i2c->adap);
+}
+
+static struct driver rk3x_i2c_driver = {
+	.name  = "rk3x-i2c",
+	.of_compatible = rk3x_i2c_match,
+	.probe   = rk3x_i2c_probe,
+};
+coredevice_platform_driver(rk3x_i2c_driver);
+
+MODULE_DESCRIPTION("Rockchip RK3xxx I2C Bus driver");
+MODULE_AUTHOR("Max Schwarz <max.schwarz at online.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
deleted file mode 100644
index a7bd66781f..0000000000
--- a/drivers/i2c/busses/i2c-rockchip.c
+++ /dev/null
@@ -1,462 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * (C) Copyright 2015 Google, Inc
- *
- * (C) Copyright 2008-2014 Rockchip Electronics
- * Peter, Software Engineering, <superpeter.cai at gmail.com>.
- */
-
-#include <common.h>
-#include <i2c/i2c.h>
-#include <linux/iopoll.h>
-#include <errno.h>
-#include <linux/err.h>
-#include <driver.h>
-#include <io.h>
-#include <linux/clk.h>
-#include <mfd/syscon.h>
-#include <linux/regmap.h>
-#include <linux/sizes.h>
-
-struct i2c_regs {
-	u32 con;
-	u32 clkdiv;
-	u32 mrxaddr;
-	u32 mrxraddr;
-	u32 mtxcnt;
-	u32 mrxcnt;
-	u32 ien;
-	u32 ipd;
-	u32 fcnt;
-	u32 reserved0[0x37];
-	u32 txdata[8];
-	u32 reserved1[0x38];
-	u32 rxdata[8];
-};
-
-/* Control register */
-#define I2C_CON_EN		(1 << 0)
-#define I2C_CON_MOD(mod)	((mod) << 1)
-#define I2C_MODE_TX		0x00
-#define I2C_MODE_TRX		0x01
-#define I2C_MODE_RX		0x02
-#define I2C_MODE_RRX		0x03
-#define I2C_CON_MASK		(3 << 1)
-
-#define I2C_CON_START		(1 << 3)
-#define I2C_CON_STOP		(1 << 4)
-#define I2C_CON_LASTACK		(1 << 5)
-#define I2C_CON_ACTACK		(1 << 6)
-
-/* Clock divider register */
-#define I2C_CLKDIV_VAL(divl, divh) \
-	(((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))
-
-/* the slave address accessed  for master rx mode */
-#define I2C_MRXADDR_SET(vld, addr)	(((vld) << 24) | (addr))
-
-/* the slave register address accessed  for master rx mode */
-#define I2C_MRXRADDR_SET(vld, raddr)	(((vld) << 24) | (raddr))
-
-/* interrupt enable register */
-#define I2C_BTFIEN		(1 << 0)
-#define I2C_BRFIEN		(1 << 1)
-#define I2C_MBTFIEN		(1 << 2)
-#define I2C_MBRFIEN		(1 << 3)
-#define I2C_STARTIEN		(1 << 4)
-#define I2C_STOPIEN		(1 << 5)
-#define I2C_NAKRCVIEN		(1 << 6)
-
-/* interrupt pending register */
-#define I2C_BTFIPD              (1 << 0)
-#define I2C_BRFIPD              (1 << 1)
-#define I2C_MBTFIPD             (1 << 2)
-#define I2C_MBRFIPD             (1 << 3)
-#define I2C_STARTIPD            (1 << 4)
-#define I2C_STOPIPD             (1 << 5)
-#define I2C_NAKRCVIPD           (1 << 6)
-#define I2C_IPD_ALL_CLEAN       0x7f
-
-/* i2c timeout */
-#define I2C_TIMEOUT_US		(100 * USEC_PER_MSEC)
-
-/* rk i2c fifo max transfer bytes */
-#define RK_I2C_FIFO_SIZE	32
-
-struct rk_i2c {
-	struct i2c_adapter	adapter;
-	struct clk *clk;
-	struct i2c_regs *regs;
-	unsigned int speed;
-};
-
-static inline struct rk_i2c *to_rk_i2c(struct i2c_adapter *adapter)
-{
-	return container_of(adapter, struct rk_i2c, adapter);
-}
-
-static inline void rk_i2c_get_div(int div, int *divh, int *divl)
-{
-	*divl = div / 2;
-	*divh = DIV_ROUND_UP(div, 2);
-}
-
-/*
- * SCL Divisor = 8 * (CLKDIVL+1 + CLKDIVH+1)
- * SCL = PCLK / SCLK Divisor
- * i2c_rate = PCLK
- */
-static void rk_i2c_set_clk(struct rk_i2c *i2c, uint32_t scl_rate)
-{
-	struct device *dev = i2c->adapter.dev.parent;
-	uint32_t i2c_rate;
-	int div, divl, divh;
-
-	/* First get i2c rate from pclk */
-	i2c_rate = clk_get_rate(i2c->clk);
-
-	div = DIV_ROUND_UP(i2c_rate, scl_rate * 8) - 2;
-	divh = 0;
-	divl = 0;
-	if (div >= 0)
-		rk_i2c_get_div(div, &divh, &divl);
-	writel(I2C_CLKDIV_VAL(divl, divh), &i2c->regs->clkdiv);
-
-	dev_dbg(dev, "rk_i2c_set_clk: i2c rate = %d, scl rate = %d\n", i2c_rate,
-		scl_rate);
-	dev_dbg(dev, "set i2c clk div = %d, divh = %d, divl = %d\n", div, divh, divl);
-	dev_dbg(dev, "set clk(I2C_CLKDIV: 0x%08x)\n", readl(&i2c->regs->clkdiv));
-}
-
-static void rk_i2c_show_regs(struct rk_i2c *i2c)
-{
-	struct device *dev = &i2c->adapter.dev;
-	struct i2c_regs *regs = i2c->regs;
-	int i;
-
-	dev_dbg(dev, "i2c_con: 0x%08x\n", readl(&regs->con));
-	dev_dbg(dev, "i2c_clkdiv: 0x%08x\n", readl(&regs->clkdiv));
-	dev_dbg(dev, "i2c_mrxaddr: 0x%08x\n", readl(&regs->mrxaddr));
-	dev_dbg(dev, "i2c_mrxraddR: 0x%08x\n", readl(&regs->mrxraddr));
-	dev_dbg(dev, "i2c_mtxcnt: 0x%08x\n", readl(&regs->mtxcnt));
-	dev_dbg(dev, "i2c_mrxcnt: 0x%08x\n", readl(&regs->mrxcnt));
-	dev_dbg(dev, "i2c_ien: 0x%08x\n", readl(&regs->ien));
-	dev_dbg(dev, "i2c_ipd: 0x%08x\n", readl(&regs->ipd));
-	dev_dbg(dev, "i2c_fcnt: 0x%08x\n", readl(&regs->fcnt));
-
-	for (i = 0; i < 8; i++)
-		dev_dbg(dev, "i2c_txdata%d: 0x%08x\n", i, readl(&regs->txdata[i]));
-	for (i = 0; i < 8; i++)
-		dev_dbg(dev, "i2c_rxdata%d: 0x%08x\n", i, readl(&regs->rxdata[i]));
-}
-
-static int rk_i2c_send_start_bit(struct rk_i2c *i2c)
-{
-	struct device *dev = &i2c->adapter.dev;
-	struct i2c_regs *regs = i2c->regs;
-	u32 val;
-	int err;
-
-	dev_dbg(dev, "I2c Send Start bit.\n");
-	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
-
-	writel(I2C_CON_EN | I2C_CON_START, &regs->con);
-	writel(I2C_STARTIEN, &regs->ien);
-
-	err = readl_poll_timeout(&regs->ipd, val, val & I2C_STARTIPD, I2C_TIMEOUT_US);
-	if (err) {
-		dev_dbg(dev, "I2C Send Start Bit Timeout\n");
-		rk_i2c_show_regs(i2c);
-		return err;
-	}
-
-	writel(I2C_STARTIPD, &regs->ipd);
-	return 0;
-}
-
-static int rk_i2c_send_stop_bit(struct rk_i2c *i2c)
-{
-	struct device *dev = &i2c->adapter.dev;
-	struct i2c_regs *regs = i2c->regs;
-	u32 val;
-	int err;
-
-	dev_dbg(dev, "I2c Send Stop bit.\n");
-	writel(I2C_IPD_ALL_CLEAN, &regs->ipd);
-
-	writel(I2C_CON_EN | I2C_CON_STOP, &regs->con);
-	writel(I2C_CON_STOP, &regs->ien);
-
-	err = readl_poll_timeout(&regs->ipd, val, val & I2C_STOPIPD, I2C_TIMEOUT_US);
-	if (err) {
-		dev_dbg(dev, "I2C Send Start Bit Timeout\n");
-		rk_i2c_show_regs(i2c);
-		return err;
-	}
-
-	writel(I2C_STOPIPD, &regs->ipd);
-	return 0;
-}
-
-static inline void rk_i2c_disable(struct rk_i2c *i2c)
-{
-	writel(0, &i2c->regs->con);
-}
-
-static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
-		       uchar *buf, uint b_len)
-{
-	struct device *dev = &i2c->adapter.dev;
-	struct i2c_regs *regs = i2c->regs;
-	uchar *pbuf = buf;
-	uint bytes_remain_len = b_len;
-	uint bytes_xferred = 0;
-	uint words_xferred = 0;
-	uint con = 0;
-	uint rxdata;
-	uint i, j;
-	int err;
-	u32 val;
-	bool snd_chunk = false;
-
-	dev_dbg(dev, "rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
-	      chip, reg, r_len, b_len);
-
-	err = rk_i2c_send_start_bit(i2c);
-	if (err)
-		return err;
-
-	writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
-	if (r_len == 0) {
-		writel(0, &regs->mrxraddr);
-	} else if (r_len < 4) {
-		writel(I2C_MRXRADDR_SET(r_len, reg), &regs->mrxraddr);
-	} else {
-		dev_dbg(dev, "I2C Read: addr len %d not supported\n", r_len);
-		return -EIO;
-	}
-
-	while (bytes_remain_len) {
-		if (bytes_remain_len > RK_I2C_FIFO_SIZE) {
-			con = I2C_CON_EN;
-			bytes_xferred = RK_I2C_FIFO_SIZE;
-		} else {
-			/*
-			 * The hw can read up to 32 bytes at a time. If we need
-			 * more than one chunk, send an ACK after the last byte.
-			 */
-			con = I2C_CON_EN | I2C_CON_LASTACK;
-			bytes_xferred = bytes_remain_len;
-		}
-		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
-
-		/*
-		 * make sure we are in plain RX mode if we read a second chunk
-		 */
-		if (snd_chunk)
-			con |= I2C_CON_MOD(I2C_MODE_RX);
-		else
-			con |= I2C_CON_MOD(I2C_MODE_TRX);
-
-		writel(con, &regs->con);
-		writel(bytes_xferred, &regs->mrxcnt);
-		writel(I2C_MBRFIEN | I2C_NAKRCVIEN, &regs->ien);
-
-		err = readl_poll_timeout(&regs->ipd, val, val & (I2C_NAKRCVIPD|I2C_MBRFIPD), I2C_TIMEOUT_US);
-		if (err) {
-			dev_dbg(dev, "I2C Read Data Timeout\n");
-			goto i2c_exit;
-		}
-
-		if (val & I2C_NAKRCVIPD) {
-			writel(I2C_NAKRCVIPD, &regs->ipd);
-			err = -EREMOTEIO;
-			goto i2c_exit;
-		}
-
-		writel(I2C_MBRFIPD, &regs->ipd);
-
-		for (i = 0; i < words_xferred; i++) {
-			rxdata = readl(&regs->rxdata[i]);
-			dev_dbg(dev, "I2c Read RXDATA[%d] = 0x%x\n", i, rxdata);
-			for (j = 0; j < 4; j++) {
-				if ((i * 4 + j) == bytes_xferred)
-					break;
-				*pbuf++ = (rxdata >> (j * 8)) & 0xff;
-			}
-		}
-
-		bytes_remain_len -= bytes_xferred;
-		snd_chunk = true;
-		dev_dbg(dev, "I2C Read bytes_remain_len %d\n", bytes_remain_len);
-	}
-
-i2c_exit:
-	if (err)
-		rk_i2c_show_regs(i2c);
-	rk_i2c_disable(i2c);
-
-	return err;
-}
-
-static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
-			uchar *buf, uint b_len)
-{
-	struct device *dev = &i2c->adapter.dev;
-	struct i2c_regs *regs = i2c->regs;
-	u32 val;
-	int err;
-	uchar *pbuf = buf;
-	uint bytes_remain_len = b_len + r_len + 1;
-	uint bytes_xferred = 0;
-	uint words_xferred = 0;
-	uint txdata;
-	uint i, j;
-
-	dev_dbg(dev, "rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
-	      chip, reg, r_len, b_len);
-	err = rk_i2c_send_start_bit(i2c);
-	if (err)
-		return err;
-
-	while (bytes_remain_len) {
-		if (bytes_remain_len > RK_I2C_FIFO_SIZE)
-			bytes_xferred = RK_I2C_FIFO_SIZE;
-		else
-			bytes_xferred = bytes_remain_len;
-		words_xferred = DIV_ROUND_UP(bytes_xferred, 4);
-
-		for (i = 0; i < words_xferred; i++) {
-			txdata = 0;
-			for (j = 0; j < 4; j++) {
-				if ((i * 4 + j) == bytes_xferred)
-					break;
-
-				if (i == 0 && j == 0 && pbuf == buf) {
-					txdata |= (chip << 1);
-				} else if (i == 0 && j <= r_len && pbuf == buf) {
-					txdata |= (reg &
-						(0xff << ((j - 1) * 8))) << 8;
-				} else {
-					txdata |= (*pbuf++)<<(j * 8);
-				}
-			}
-			writel(txdata, &regs->txdata[i]);
-			dev_dbg(dev, "I2c Write TXDATA[%d] = 0x%08x\n", i, txdata);
-		}
-
-		writel(I2C_CON_EN | I2C_CON_MOD(I2C_MODE_TX), &regs->con);
-		writel(bytes_xferred, &regs->mtxcnt);
-		writel(I2C_MBTFIEN | I2C_NAKRCVIEN, &regs->ien);
-
-		err = readl_poll_timeout(&regs->ipd, val, val & (I2C_NAKRCVIPD|I2C_MBTFIPD), I2C_TIMEOUT_US);
-		if (err) {
-			dev_dbg(dev, "I2C Write Data Timeout\n");
-			goto i2c_exit;
-		}
-
-		if (val & I2C_NAKRCVIPD) {
-			writel(I2C_NAKRCVIPD, &regs->ipd);
-			err = -EREMOTEIO;
-			goto i2c_exit;
-		}
-
-		writel(I2C_MBTFIPD, &regs->ipd);
-
-		bytes_remain_len -= bytes_xferred;
-		dev_dbg(dev, "I2C Write bytes_remain_len %d\n", bytes_remain_len);
-	}
-
-i2c_exit:
-	if (err)
-		rk_i2c_show_regs(i2c);
-	rk_i2c_disable(i2c);
-
-	return err;
-}
-
-static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
-			     int nmsgs)
-{
-	struct rk_i2c *i2c = to_rk_i2c(adapter);
-	struct device *dev = &adapter->dev;
-	int i, ret = 0;
-
-	dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
-	for (i = 0; i < nmsgs; i++) {
-		struct i2c_msg *msg = &msgs[i];
-
-		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
-		if (msg->flags & I2C_M_RD) {
-			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
-					  msg->len);
-		} else {
-			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
-					   msg->len);
-		}
-		if (ret) {
-			dev_dbg(dev, "i2c_write: error sending: %pe\n",
-				ERR_PTR(ret));
-			ret = -EREMOTEIO;
-			break;
-		}
-	}
-
-	rk_i2c_send_stop_bit(i2c);
-	rk_i2c_disable(i2c);
-
-	return ret < 0 ? ret : nmsgs;
-}
-
-static int rk_i2c_probe(struct device *dev)
-{
-	struct device_node *np = dev->of_node;
-	struct resource *iores;
-	struct rk_i2c *i2c;
-	unsigned bitrate;
-
-	iores = dev_request_mem_resource(dev, 0);
-	if (IS_ERR(iores))
-		return PTR_ERR(iores);
-
-	i2c = kzalloc(sizeof(struct rk_i2c), GFP_KERNEL);
-	if (!i2c)
-		return -ENOMEM;
-
-	dev->priv = i2c;
-	i2c->regs = IOMEM(iores->start);
-
-	/* Only one clock to use for bus clock and peripheral clock */
-	i2c->clk = clk_get(dev, NULL);
-	if (IS_ERR(i2c->clk))
-		return dev_err_probe(dev, PTR_ERR(i2c->clk), "Can't get bus clk\n");
-
-	i2c->adapter.master_xfer = rockchip_i2c_xfer;
-	i2c->adapter.nr = -1;
-	i2c->adapter.dev.parent = dev;
-	i2c->adapter.dev.of_node = np;
-
-	/* Set up clock divider */
-	bitrate = 100000;
-	of_property_read_u32(np, "clock-frequency", &bitrate);
-
-	rk_i2c_set_clk(i2c, bitrate);
-
-	return i2c_add_numbered_adapter(&i2c->adapter);
-}
-
-static const struct of_device_id rk_i2c_match[] = {
-	{ .compatible = "rockchip,rv1108-i2c" },
-	{ .compatible = "rockchip,rk3228-i2c" },
-	{ .compatible = "rockchip,rk3288-i2c" },
-	{ .compatible = "rockchip,rk3399-i2c" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, rk_i2c_match);
-
-static struct driver rk_i2c_driver = {
-	.name  = "rk3x-i2c",
-	.of_compatible = rk_i2c_match,
-	.probe   = rk_i2c_probe,
-};
-coredevice_platform_driver(rk_i2c_driver);
-- 
2.38.2



From eagle.alexander923 at gmail.com  Tue Feb  4 07:31:00 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Tue, 4 Feb 2025 18:31:00 +0300
Subject: Devicetree add-on
In-Reply-To: <Z5zNy19vd_13rRsY@pengutronix.de>
References: <CAP1tNvRa-1XPm087pzti1XmqvRDqchKOWZgvgYmcAQh+uOayBg@mail.gmail.com>
 <Z5uBCoIy69dB3QH_@pengutronix.de> <CAP1tNvR3SwMo2b1kUMzdL6BQM85yVYaK2YwxnHSKm53vg0aZow@mail.gmail.com>
 <Z5zNy19vd_13rRsY@pengutronix.de>
Message-ID: <CAP1tNvSnOaCbW9qFt34JX_L5Ljiz2cxd1A4cgtOiiHmHjzd2ag@mail.gmail.com>

Hello All!

Eventually I switched to using overlays.
Of course, there are some unsolved problems, such as already occupied aliases
if they are specified in the overlay, or, for example, using
"assigned-clocks" in
overlays for already probed devices. I will give two examples from my
current projects,
criticize them if it is not difficult, maybe an idea will arise on how
to do it better.
The first link with two overlays [1], the third with three [2]:)

[1] https://github.com/MacroGroup/barebox/blob/macro/arch/arm/boards/diasom-rk3568/board.c
[2] https://github.com/shcgit/barebox-github/blob/milas/arch/arm/boards/mm-sm-sama5d2/board.c

Thanks!

??, 31 ???. 2025??. ? 16:19, Sascha Hauer <s.hauer at pengutronix.de>:
>
> On Thu, Jan 30, 2025 at 04:45:48PM +0300, Alexander Shiyan wrote:
> > Hello.
> >
> > Yes, I understand that.
> > But maybe we can make another entry point to start from scratch,
> > but with another tree, roughly the same way we do with pbl?
>
> It's not universally possible to jump into the currently running image.
> Static variables in the data section might be modified already.
>
> Of course you can load the barebox image from the boot device again
> manually and jump into it, with a device tree passed in a pointer this
> time.
>
> Sascha
>
> --
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Feb  5 01:48:08 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:08 +0100
Subject: [PATCH 0/9] ARM: K3 updates
Message-ID: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>

This series has some updates for the TI K3 architecture.

We add support for bootstrapping boards via USB DFU. This has been sent
earlier, this time booting from eMMC is added as well.

On K3 SoCs we need a bunch of images after the first stage has been
loaded: OP-TEE, ti-dm firmware, TF-A binary and finally a barebox
binary. Until now these are expected as distinct images on the SD cards
FAT partition. This is impractical for booting from eMMC boot partitions
and also DFU boot, so this series adds support for handling a FIP image
containing these binaries.

Also some misc patches like enabling the 32k crystal needed for accurate
RTC frequency

Sascha

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
Sascha Hauer (9):
      ARM: k3: Add function to enable 32k crystal
      ARM: k3: add function to detect eMMC boot
      ARM: k3: do not mount /boot when booting from eMMC
      ARM: k3: r5: add USB DFU and eMMC boot support
      ARM: am625-sk: enable 32k crystal
      mci: am654: parse generic mmc node properties
      ARM: k3: limit eMMC frequency to 25MHz
      ARM: am625-sk: put environment on eMMC when booting from it
      serial: omap: Use ttyS as Linux console name

 Documentation/boards/ti-k3.rst       |  47 +++++
 arch/arm/boards/am625-sk/Makefile    |   1 +
 arch/arm/boards/am625-sk/board.c     |  35 ++++
 arch/arm/dts/k3-am625-beagleplay.dts |   4 +
 arch/arm/dts/k3-am625-sk.dts         |  19 ++
 arch/arm/mach-k3/common.c            |  36 ++++
 arch/arm/mach-k3/r5.c                | 367 ++++++++++++++++++++++++++++++++---
 drivers/mci/am654-sdhci.c            |   1 +
 drivers/serial/serial_ns16550.c      |   4 +-
 include/mach/k3/common.h             |   9 +
 10 files changed, 490 insertions(+), 33 deletions(-)
---
base-commit: a40a4c0d054f3b6aac272236c982d24c4ac72eaa
change-id: 20250205-k3-emmc-eaa3df9f3ffd

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb  5 01:48:17 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:17 +0100
Subject: [PATCH 9/9] serial: omap: Use ttyS as Linux console name
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-9-06679246be41@pengutronix.de>

Traditionally Linux used ttyO as console name for Omap devices. This has
been changed to ttyS in 2014. Since then ttyO gets translated to ttyS by
the Kernel. Use ttyS directly to avoid the translation in the Kernel.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/serial/serial_ns16550.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index 45341d1c9b..56a1c6c6b9 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -402,13 +402,13 @@ static struct ns16550_drvdata ns16550_drvdata = {
 
 static __maybe_unused struct ns16550_drvdata omap_drvdata = {
 	.init_port = ns16550_omap_init_port,
-	.linux_console_name = "ttyO",
+	.linux_console_name = "ttyS",
 	.linux_earlycon_name = "omap8250",
 };
 
 static __maybe_unused struct ns16550_drvdata omap_clk48m_drvdata = {
 	.init_port = ns16550_omap_init_port,
-	.linux_console_name = "ttyO",
+	.linux_console_name = "ttyS",
 	.clk_default = 48000000,
 };
 

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:09 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:09 +0100
Subject: [PATCH 1/9] ARM: k3: Add function to enable 32k crystal
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-1-06679246be41@pengutronix.de>

The external 32k crystal is optional and by default LFOSC0 is sourced
by a RC oscillator. This adds a function to be called by board code
when the 32k crystal is present and shall be used to source LFOSC0
from the crystal.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/common.c | 20 ++++++++++++++++++++
 include/mach/k3/common.h  |  1 +
 2 files changed, 21 insertions(+)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 3922a0ff19..c779e873c9 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -170,6 +170,26 @@ static void of_delete_node_path(struct device_node *root, const char *path)
 	of_delete_node(np);
 }
 
+#define MCU_CTRL_MMR0_BASE			0x04500000
+#define MCU_CTRL_LFXOSC_CTRL			(MCU_CTRL_MMR0_BASE + 0x8038)
+#define MCU_CTRL_LFXOSC_32K_DISABLE_VAL		BIT(7)
+#define MCU_CTRL_DEVICE_CLKOUT_LFOSC_SELECT_VAL	(0x3)
+#define MCU_CTRL_DEVICE_CLKOUT_32K_CTRL		(MCU_CTRL_MMR0_BASE + 0x8058)
+
+void am625_enable_32k_crystal(void)
+{
+	u32 val;
+
+	/* Enable 32k crystal */
+	val = readl(MCU_CTRL_LFXOSC_CTRL);
+	val &= ~(MCU_CTRL_LFXOSC_32K_DISABLE_VAL);
+	writel(val, MCU_CTRL_LFXOSC_CTRL);
+
+	/* select 32k clock from LFOSC0 */
+	writel(MCU_CTRL_DEVICE_CLKOUT_LFOSC_SELECT_VAL,
+	       MCU_CTRL_DEVICE_CLKOUT_32K_CTRL);
+}
+
 #define CTRLMMR_WKUP_JTAG_DEVICE_ID	(AM625_WKUP_CTRL_MMR0_BASE + 0x18)
 
 #define JTAG_DEV_CORE_NR		GENMASK(21, 19)
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index d7ceea51d7..3377dc8895 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -6,5 +6,6 @@
 void am625_get_bootsource(enum bootsource *src, int *instance);
 u64 am625_sdram_size(void);
 void am625_register_dram(void);
+void am625_enable_32k_crystal(void);
 
 #endif /* __MACH_K3_COMMON_H */

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:15 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:15 +0100
Subject: [PATCH 7/9] ARM: k3: limit eMMC frequency to 25MHz
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-7-06679246be41@pengutronix.de>

The eMMCs on am625 currently only work reliably with 25MHz. Until this
issue is sorted out limit them to 25MHz on the affected boards
(beagleplay and am625-sk).

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/dts/k3-am625-beagleplay.dts | 4 ++++
 arch/arm/dts/k3-am625-sk.dts         | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/arch/arm/dts/k3-am625-beagleplay.dts b/arch/arm/dts/k3-am625-beagleplay.dts
index 60340ab8ca..73ac950414 100644
--- a/arch/arm/dts/k3-am625-beagleplay.dts
+++ b/arch/arm/dts/k3-am625-beagleplay.dts
@@ -29,3 +29,7 @@ AM62X_IOPAD(0x0224, PIN_INPUT, 0) /* (D22) MMC1_DAT3 */
 		AM62X_IOPAD(0x0240, PIN_INPUT, 0) /* (D17) MMC1_SDCD */
 	>;
 };
+
+&sdhci0 {
+	max-frequency = <26000000>;
+};
diff --git a/arch/arm/dts/k3-am625-sk.dts b/arch/arm/dts/k3-am625-sk.dts
index 1982c34388..56d5681519 100644
--- a/arch/arm/dts/k3-am625-sk.dts
+++ b/arch/arm/dts/k3-am625-sk.dts
@@ -7,3 +7,7 @@
  * DRAM size differs between board variants. Real size is read from DDRSS
  */
 /delete-node/ &{/memory at 80000000};
+
+&sdhci0 {
+	max-frequency = <26000000>;
+};

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:13 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:13 +0100
Subject: [PATCH 5/9] ARM: am625-sk: enable 32k crystal
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-5-06679246be41@pengutronix.de>

The am625-sk board has the 32k crystal equipped. Enable it to source the
RTC from the crystal rather than from the imprecise RC oscillator.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/boards/am625-sk/Makefile |  1 +
 arch/arm/boards/am625-sk/board.c  | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/arch/arm/boards/am625-sk/Makefile b/arch/arm/boards/am625-sk/Makefile
index 1ff9e75a00..8c45b1e154 100644
--- a/arch/arm/boards/am625-sk/Makefile
+++ b/arch/arm/boards/am625-sk/Makefile
@@ -1,3 +1,4 @@
 pbl-y += lowlevel.o
+obj-y += board.o
 pbl-$(CONFIG_MACH_K3_CORTEX_A) += entry.o
 pbl-$(CONFIG_MACH_K3_CORTEX_R5) += entry-r5.o am625-sk-ddr.o am625sip-sk-ddr.o
diff --git a/arch/arm/boards/am625-sk/board.c b/arch/arm/boards/am625-sk/board.c
new file mode 100644
index 0000000000..fd3bcdeac6
--- /dev/null
+++ b/arch/arm/boards/am625-sk/board.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "am625-sk: " fmt
+
+#include <linux/kernel.h>
+#include <mach/k3/common.h>
+#include <driver.h>
+#include <bbu.h>
+
+static int am625_sk_probe(struct device *dev)
+{
+	am625_enable_32k_crystal();
+
+	return 0;
+}
+
+static __maybe_unused struct of_device_id am625_sk_ids[] = {
+	{
+		.compatible = "ti,am625-sk",
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver am625_sk_driver = {
+	.name = "am625-sk",
+	.probe = am625_sk_probe,
+	.of_compatible = am625_sk_ids,
+};
+coredevice_platform_driver(am625_sk_driver);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:11 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:11 +0100
Subject: [PATCH 3/9] ARM: k3: do not mount /boot when booting from eMMC
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-3-06679246be41@pengutronix.de>

When booting from eMMC we load the subsequent stages from eMMC boot
partitions, so we do not need a boot FAT partition on eMMC. We can
use an unpartitioned area in the eMMC user area in this case, so
bail out from mounting /boot when eMMC boot is detected.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/common.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 7ded1f3f04..97cb46d58e 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -275,6 +275,9 @@ static int omap_env_init(void)
 	if (bootsource_get() != BOOTSOURCE_MMC)
 		return 0;
 
+	if (k3_boot_is_emmc())
+		return 0;
+
 	instance = bootsource_get_instance();
 
 	cdevname = xasprintf("mmc%d", instance);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:10 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:10 +0100
Subject: [PATCH 2/9] ARM: k3: add function to detect eMMC boot
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-2-06679246be41@pengutronix.de>

Booting from eMMC on K3 SoCs requires some special handling. With SD
card boot we put the environment in the boot FAT partition whereas with
eMMC boot we want to put it into the raw eMMC device. Also with eMMC
boot we have to load the subsequent stages from the eMMC boot partitions
and from the boot FAT otherwise. Add a function to detect eMMC boot
to base these decisions on.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/common.c | 13 +++++++++++++
 include/mach/k3/common.h  |  1 +
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index c779e873c9..7ded1f3f04 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -162,6 +162,19 @@ void am625_get_bootsource(enum bootsource *src, int *instance)
 	k3_get_bootsource(devstat, src, instance);
 }
 
+bool k3_boot_is_emmc(void)
+{
+	u32 bootmode = readl(AM625_BOOT_PARAM_TABLE_INDEX_OCRAM);
+	u32 devstat = readl(AM625_CTRLMMR_MAIN_DEVSTAT);
+
+	if (bootmode != K3_PRIMARY_BOOTMODE)
+		return false;
+	if (FIELD_GET(MAIN_DEVSTAT_PRIMARY_BOOTMODE, devstat) != BOOT_DEVICE_EMMC)
+		return false;
+
+	return true;
+}
+
 static void of_delete_node_path(struct device_node *root, const char *path)
 {
 	struct device_node *np;
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index 3377dc8895..7f0796f7f4 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -4,6 +4,7 @@
 #include <bootsource.h>
 
 void am625_get_bootsource(enum bootsource *src, int *instance);
+bool k3_boot_is_emmc(void);
 u64 am625_sdram_size(void);
 void am625_register_dram(void);
 void am625_enable_32k_crystal(void);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:16 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:16 +0100
Subject: [PATCH 8/9] ARM: am625-sk: put environment on eMMC when booting
 from it
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-8-06679246be41@pengutronix.de>

When booting from eMMC put the environment on the eMMC as well.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/boards/am625-sk/board.c |  5 +++++
 arch/arm/dts/k3-am625-sk.dts     | 15 +++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/arm/boards/am625-sk/board.c b/arch/arm/boards/am625-sk/board.c
index fd3bcdeac6..c716f30e69 100644
--- a/arch/arm/boards/am625-sk/board.c
+++ b/arch/arm/boards/am625-sk/board.c
@@ -11,6 +11,11 @@ static int am625_sk_probe(struct device *dev)
 {
 	am625_enable_32k_crystal();
 
+	k3_bbu_emmc_register("emmc", "/dev/mmc0", BBU_HANDLER_FLAG_DEFAULT);
+
+	if (k3_boot_is_emmc())
+		of_device_enable_path("/chosen/environment-emmc");
+
 	return 0;
 }
 
diff --git a/arch/arm/dts/k3-am625-sk.dts b/arch/arm/dts/k3-am625-sk.dts
index 56d5681519..8d7a73babf 100644
--- a/arch/arm/dts/k3-am625-sk.dts
+++ b/arch/arm/dts/k3-am625-sk.dts
@@ -3,6 +3,16 @@
 #include <arm64/ti/k3-am625-sk.dts>
 #include "k3-am625.dtsi"
 
+/ {
+	chosen {
+		environment-emmc {
+			compatible = "barebox,environment";
+			device-path = &env_emmc;
+			status = "disabled";
+		};
+	};
+};
+
 /*
  * DRAM size differs between board variants. Real size is read from DDRSS
  */
@@ -10,4 +20,9 @@
 
 &sdhci0 {
 	max-frequency = <26000000>;
+
+	env_emmc: partition at e0000 {
+		label = "barebox-environment";
+		reg = <0x0 0xe0000 0x0 0x20000>;
+	};
 };

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:14 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:14 +0100
Subject: [PATCH 6/9] mci: am654: parse generic mmc node properties
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-6-06679246be41@pengutronix.de>

Call mci_of_parse_node() to parse generic node properties like
max-frequency to lower the maximum allowed frequency.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/mci/am654-sdhci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c
index 9787642011..2c1fa5d804 100644
--- a/drivers/mci/am654-sdhci.c
+++ b/drivers/mci/am654-sdhci.c
@@ -594,6 +594,7 @@ static int am654_sdhci_probe(struct device *dev)
 	mci = &plat->mci;
 	mci->f_max = clk_get_rate(plat->clk);
 	mci->f_min = 50000000 / 256;
+	mci_of_parse_node(mci, np);
 
 	if (plat->soc_data->flags & DLL_PRESENT) {
 		ret = of_property_read_u32(np, "ti,trm-icp", &plat->trm_icp);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:12 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 05 Feb 2025 10:48:12 +0100
Subject: [PATCH 4/9] ARM: k3: r5: add USB DFU and eMMC boot support
In-Reply-To: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
References: <20250205-k3-emmc-v1-0-06679246be41@pengutronix.de>
Message-ID: <20250205-k3-emmc-v1-4-06679246be41@pengutronix.de>

This patch adds USB DFU and eMMC boot support for the k3 SoCs.

DFU mode is entered when the SoC is booted from USB. For continuing the
boot we need several binaries (bl31, OP-TEE, barebox, ti-dm firmware),
these can be uploaded as distinct files or combined together as a FIP
image. This patch also adds the possibility to put a FIP image on the
SD/eMMC card which is then preferred over the distinct files which were
previously expected on SD/eMMC cards.

Also the K3 SoCs have a boot mode to boot from eMMC boot partitions for
which this patch adds support. When this bootmode is selected the
tiboot3.bin file is loaded from the active boot partition. We then need
to load the FIP image from the same boot partition. This image is
expected to be at offset 1MiB in the boot partition.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 Documentation/boards/ti-k3.rst |  47 ++++++
 arch/arm/mach-k3/r5.c          | 367 +++++++++++++++++++++++++++++++++++++----
 include/mach/k3/common.h       |   7 +
 3 files changed, 390 insertions(+), 31 deletions(-)

diff --git a/Documentation/boards/ti-k3.rst b/Documentation/boards/ti-k3.rst
index a1bf0b92e8..4b3822c020 100644
--- a/Documentation/boards/ti-k3.rst
+++ b/Documentation/boards/ti-k3.rst
@@ -69,6 +69,9 @@ OP-TEE is built from https://github.com/OP-TEE/optee_os.git::
         PLATFORM=k3-am62x
   cp out/arm-plat-k3/core/tee-raw.bin $TI_BOOT/optee.bin
 
+OP-TEE is optional. barebox will continue without ``optee.bin`` when the file
+does not exist.
+
 Copying ti-dm.bin
 -----------------
 
@@ -77,3 +80,47 @@ copied to the eMMC/SD as well::
 
   cp $TI_LINUX_FIRMWARE/ti-dm/am62xx/ipc_echo_testb_mcu1_0_release_strip.xer5f $TI_BOOT/ti-dm.bin
 
+Combining binaries into a FIP image
+-----------------------------------
+
+Alternatively to putting the different binaries (``barebox.bin``, ``bl31.bin``, ``optee.bin``
+and ``ti-dm.bin``) into the FAT image the files can be combined into a FIP image named
+``k3.fip``.::
+
+  fiptool create --soc-fw bl31.bin \
+    --tos-fw optee.bin \
+    --nt-fw barebox-beagleplay.img \
+    --blob uuid=9e8c2017-8b94-4e2b-a7b3-a0f88eabb8ae,file=ti-dm.bin k3.fip
+
+USB DFU boot
+------------
+K3 Boards can be booted via USB DFU. When in USB boot mode the initial stage can be uploaded
+using ``dfu-util``::
+
+  dfu-util -D barebox-beagleplay-r5.img -a bootloader
+
+This will start the initial stage which then expects the following stages which can
+be uploaded with ``dfu-util`` as well, either as FIP image::
+
+  dfu-util -D k3.fip -a fip
+
+or as separate files::
+
+  dfu-util -D blb31.bin -a tfa
+  dfu-util -D optee.bin -a optee
+  dfu-util -D ti-dm.bin -a ti-dm
+  dfu-util -D barebox-beagleplay.img -a barebox
+
+Uploading optee.bin can be skipped in case it's not needed.
+
+eMMC boot
+---------
+K3 boards can boot from eMMC boot partitions. In this mode the ROM reads the tiboot3.bin
+raw from the active boot partition. In this mode barebox expects the FIP image with the
+following stages in the same boot partition at offset 1MiB. There is a barebox update handler
+which takes a combined image consisting of tiboot3.bin and the FIP image to allow for a
+failsafe update. This image can't be generated by the barebox build system though. It has
+to be generated by a build system or manually::
+
+  dd if=images/barebox-beagleplay-r5.img of=barebox-beagleplay-emmc.img
+  dd if=k3.fip of=barebox-beagleplay-emmc.img bs=1024 seek=1024
diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index 32d98fe89a..8fa65eaaf9 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -6,6 +6,7 @@
 #include <init.h>
 #include <libfile.h>
 #include <fs.h>
+#include <fip.h>
 #include <firmware.h>
 #include <linux/remoteproc.h>
 #include <soc/ti/ti_sci_protocol.h>
@@ -14,6 +15,10 @@
 #include <asm/cache.h>
 #include <linux/sizes.h>
 #include <barebox.h>
+#include <bootsource.h>
+#include <linux/usb/gadget-multi.h>
+#include <mach/k3/common.h>
+#include <mci.h>
 
 #define RTC_BASE_ADDRESS		0x2b1f0000
 #define K3RTC_KICK0_UNLOCK_VALUE	0x83e70b13
@@ -217,38 +222,279 @@ void am625_early_init(void)
 	ti_pd_wait(pd_base, 0);
 }
 
+#if IN_PROPER
+
 /*
  * The bl31 and optee binaries are relocatable, but these addresses
  * are hardcoded as reserved mem regions in the upstream device trees.
  */
-#define BL31_ADDRESS 0x9e780000
-#define OPTEE_ADDRESS 0x9e800000
+#define BL31_ADDRESS (void *)0x9e780000
+#define BL32_ADDRESS (void *)0x9e800000
+#define BAREBOX_ADDRESS (void *)0x80080000
 
-static int k3_r5_start_image(void)
+static void *k3_ti_dm;
+
+static bool have_bl31;
+static bool have_bl32;
+static bool have_bl33;
+
+static uuid_t uuid_bl31 = UUID_EL3_RUNTIME_FIRMWARE_BL31;
+static uuid_t uuid_ti_dm_fw = UUID_TI_DM_FW;
+static uuid_t uuid_bl33 = UUID_NON_TRUSTED_FIRMWARE_BL33;
+static uuid_t uuid_bl32 = UUID_SECURE_PAYLOAD_BL32;
+
+struct fip_image {
+	struct list_head entries;
+	void *buf;
+};
+
+struct fip_image_entry {
+	struct fip_toc_entry entry;
+	struct list_head list;
+};
+
+static void fip_image_free(struct fip_image *fip_image)
 {
-	int err;
-	void *ti_dm_buf;
-	ssize_t size;
-	struct firmware fw;
-	const struct ti_sci_handle *ti_sci;
-	void *bl31 = (void *)BL31_ADDRESS;
-	void *barebox = (void *)0x80080000;
-	void *optee = (void *)OPTEE_ADDRESS;
-	struct elf_image *elf;
-	void __noreturn (*ti_dm)(void);
-	struct rproc *arm64_rproc;
+	struct fip_image_entry *e, *tmp;
 
-	ti_sci = ti_sci_get_handle(NULL);
-	if (IS_ERR(ti_sci))
-		return -EINVAL;
+	if (!fip_image)
+		return;
 
-	arm64_rproc = ti_k3_am64_get_handle();
-	if (!arm64_rproc) {
-		pr_err("Cannot get rproc handle\n");
-		return -EINVAL;
+	list_for_each_entry_safe(e, tmp, &fip_image->entries, list)
+		free(e);
+
+	free(fip_image->buf);
+	free(fip_image);
+}
+
+static struct fip_image *open_fip(const char *filename, size_t offset)
+{
+	fip_toc_header_t toc_header;
+	int ret;
+	int fd;
+	struct fip_image *fip_image = NULL;
+	LIST_HEAD(entries);
+	size_t fip_headers_size, total = 0;
+	struct fip_image_entry *e;
+	off_t pos;
+	int n_entries = 0;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return ERR_PTR(fd);
+
+	pos = lseek(fd, offset, SEEK_SET);
+	if (pos != offset) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	fip_image = xzalloc(sizeof(*fip_image));
+	INIT_LIST_HEAD(&fip_image->entries);
+
+	ret = read_full(fd, &toc_header, sizeof(toc_header));
+	if (ret < 0)
+		goto err;
+
+	if (ret < sizeof(toc_header)) {
+		ret = -ENODATA;
+		goto err;
+	}
+
+	if (toc_header.name != TOC_HEADER_NAME) {
+		pr_err("%s is not a FIP file: unknown magic = 0x%08x\n",
+		       filename, toc_header.name);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* read all toc entries */
+	while (1) {
+		struct fip_image_entry *entry = xzalloc(sizeof(*entry));
+		struct fip_toc_entry *toc_entry = &entry->entry;
+
+		ret = read_full(fd, toc_entry, sizeof(*toc_entry));
+		if (ret < 0)
+			goto err;
+		if (ret < sizeof(*toc_entry)) {
+			ret = -ENODATA;
+			goto err;
+		}
+
+		list_add_tail(&entry->list, &fip_image->entries);
+
+		pr_debug("Read TOC entry %pU %llu %llu\n", &toc_entry->uuid,
+			 toc_entry->offset_address, toc_entry->size);
+
+		/* Found the ToC terminator, we are done. */
+		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0)
+			break;
+	}
+
+	/* determine buffer size */
+	list_for_each_entry(e, &fip_image->entries, list) {
+		uint64_t this_end = e->entry.offset_address + e->entry.size;
+
+		if (this_end > total)
+			total = this_end;
+		n_entries++;
+	}
+
+	fip_headers_size = n_entries * sizeof(struct fip_toc_entry) + sizeof(fip_toc_header_t);
+
+	total -= fip_headers_size;
+
+	fip_image->buf = malloc(total);
+	if (!fip_image->buf) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = read_full(fd, fip_image->buf, total);
+	if (ret < 0)
+		goto err;
+
+	if (ret < total) {
+		ret = -ENODATA;
+		goto err;
 	}
 
-	size = read_file_into_buf("/boot/optee.bin", optee, SZ_32M);
+	close(fd);
+
+	list_for_each_entry(e, &fip_image->entries, list)
+		e->entry.offset_address -= fip_headers_size;
+
+	return fip_image;
+err:
+	close(fd);
+	fip_image_free(fip_image);
+
+	return ERR_PTR(ret);
+}
+
+static void fip_copy(struct fip_image *fip_image)
+{
+	struct fip_image_entry *e;
+	void *buf = fip_image->buf;
+
+	list_for_each_entry(e, &fip_image->entries, list) {
+		struct fip_toc_entry *toc_entry = &e->entry;
+
+		if (!memcmp(&toc_entry->uuid, &uuid_bl31, sizeof(uuid_t))) {
+			memcpy(BL31_ADDRESS, buf + toc_entry->offset_address, toc_entry->size);
+			have_bl31 = true;
+		}
+
+		if (!memcmp(&toc_entry->uuid, &uuid_bl33, sizeof(uuid_t))) {
+			memcpy(BAREBOX_ADDRESS, buf + toc_entry->offset_address, toc_entry->size);
+			have_bl33 = true;
+		}
+
+		if (!memcmp(&toc_entry->uuid, &uuid_bl32, sizeof(uuid_t))) {
+			memcpy(BL32_ADDRESS, buf + toc_entry->offset_address, toc_entry->size);
+			have_bl32 = true;
+		}
+
+		if (!memcmp(&toc_entry->uuid, &uuid_ti_dm_fw, sizeof(uuid_t))) {
+			k3_ti_dm = xmemdup(buf + toc_entry->offset_address, toc_entry->size);
+		}
+	}
+}
+
+static int load_fip(const char *filename, off_t offset)
+{
+	struct fip_image *fip_image;
+
+	fip_image = open_fip(filename, offset);
+	if (IS_ERR(fip_image)) {
+		pr_err("Cannot open FIP image: %pe\n", fip_image);
+		return PTR_ERR(fip_image);
+	}
+
+	fip_copy(fip_image);
+
+	fip_image_free(fip_image);
+
+	return 0;
+}
+
+static void do_dfu(void)
+{
+	struct usbgadget_funcs funcs = {};
+	int ret;
+	struct stat s;
+	ssize_t size;
+
+	funcs.flags |= USBGADGET_DFU;
+	funcs.dfu_opts = "/optee.bin(optee)c,"
+			 "/bl31.bin(tfa)c,"
+			 "/ti-dm.bin(ti-dm)c,"
+			 "/barebox.bin(barebox)cs,"
+			 "/fip.img(fip)cs";
+
+	ret = usbgadget_prepare_register(&funcs);
+	if (ret)
+		goto err;
+
+	while (1) {
+		if (!have_bl32) {
+			size = read_file_into_buf("/optee.bin", BL32_ADDRESS, SZ_32M);
+			if (size > 0) {
+				printf("Downloaded OP-TEE\n");
+				have_bl32 = true;
+			}
+		}
+
+		if (!have_bl31) {
+			size = read_file_into_buf("/bl31.bin", BL31_ADDRESS, SZ_32M);
+			if (size > 0) {
+				printf("Downloaded TF-A\n");
+				have_bl31 = true;
+			}
+		}
+
+		if (!k3_ti_dm) {
+			ret = read_file_2("/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
+			if (!ret) {
+				printf("Downloaded TI-DM\n");
+			}
+		}
+
+		size = read_file_into_buf("/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
+		if (size > 0) {
+			have_bl33 = true;
+			printf("Downloaded barebox image, DFU done\n");
+			break;
+		}
+
+		ret = stat("/fip.img", &s);
+		if (!ret) {
+			printf("Downloaded FIP image, DFU done\n");
+			load_fip("/fip.img", 0);
+			break;
+		}
+
+		command_slice_release();
+		mdelay(50);
+		command_slice_acquire();
+	};
+
+	return;
+
+err:
+	pr_err("DFU failed with: %pe\n", ERR_PTR(ret));
+}
+
+static int load_images(void)
+{
+	ssize_t size;
+	int err;
+
+	err = load_fip("/boot/k3.fip", 0);
+	if (!err)
+		return 0;
+
+	size = read_file_into_buf("/boot/optee.bin", BL32_ADDRESS, SZ_32M);
 	if (size < 0) {
 		if (size != -ENOENT) {
 			pr_err("Cannot load optee.bin: %pe\n", ERR_PTR(size));
@@ -256,31 +502,89 @@ static int k3_r5_start_image(void)
 		}
 		pr_info("optee.bin not found, continue without\n");
 	} else {
-		pr_debug("Loaded optee.bin (size %u) to 0x%p\n", size, optee);
+		pr_debug("Loaded optee.bin (size %u) to 0x%p\n", size, BL32_ADDRESS);
 	}
 
-	size = read_file_into_buf("/boot/barebox.bin", barebox, optee - barebox);
+	size = read_file_into_buf("/boot/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
 	if (size < 0) {
 		pr_err("Cannot load barebox.bin: %pe\n", ERR_PTR(size));
 		return size;
 	}
-	pr_debug("Loaded barebox.bin (size %u) to 0x%p\n", size, barebox);
+	pr_debug("Loaded barebox.bin (size %u) to 0x%p\n", size, BAREBOX_ADDRESS);
 
-	size = read_file_into_buf("/boot/bl31.bin", bl31, barebox - optee);
+	size = read_file_into_buf("/boot/bl31.bin", BL31_ADDRESS, SZ_32M);
 	if (size < 0) {
 		pr_err("Cannot load bl31.bin: %pe\n", ERR_PTR(size));
 		return size;
 	}
-	pr_debug("Loaded bl31.bin (size %u) to 0x%p\n", size, bl31);
+	pr_debug("Loaded bl31.bin (size %u) to 0x%p\n", size, BL31_ADDRESS);
 
-	err = read_file_2("/boot/ti-dm.bin", &size, &ti_dm_buf, FILESIZE_MAX);
+	err = read_file_2("/boot/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
 	if (err) {
 		pr_err("Cannot load ti-dm.bin: %pe\n", ERR_PTR(err));
 		return err;
 	}
 	pr_debug("Loaded ti-dm.bin (size %u)\n", size);
 
-	elf = elf_open_binary(ti_dm_buf);
+	return 0;
+}
+
+static int load_fip_emmc(void)
+{
+	int bootpart;
+	struct mci *mci;
+	char *fname;
+	const char *mmcdev = "mmc0";
+
+	device_detect_by_name(mmcdev);
+
+	mci = mci_get_device_by_name(mmcdev);
+	if (!mci)
+		return -EINVAL;
+
+	bootpart = mci->bootpart;
+
+	if (bootpart != 1 && bootpart != 2) {
+		pr_err("Unexpected bootpart value %d\n", bootpart);
+		bootpart = 1;
+	}
+
+	fname = xasprintf("/dev/%s.boot%d", mmcdev, bootpart - 1);
+
+	load_fip(fname, K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE);
+
+	free(fname);
+
+	return 0;
+}
+
+static int k3_r5_start_image(void)
+{
+	int err;
+	struct firmware fw;
+	const struct ti_sci_handle *ti_sci;
+	struct elf_image *elf;
+	void __noreturn (*ti_dm)(void);
+	struct rproc *arm64_rproc;
+
+	if (IS_ENABLED(CONFIG_USB_GADGET_DFU) && bootsource_get() == BOOTSOURCE_SERIAL)
+		do_dfu();
+	else if (k3_boot_is_emmc())
+		load_fip_emmc();
+	else
+		load_images();
+
+	ti_sci = ti_sci_get_handle(NULL);
+	if (IS_ERR(ti_sci))
+		return -EINVAL;
+
+	arm64_rproc = ti_k3_am64_get_handle();
+	if (!arm64_rproc) {
+		pr_err("Cannot get rproc handle\n");
+		return -EINVAL;
+	}
+
+	elf = elf_open_binary(k3_ti_dm);
 	if (IS_ERR(elf)) {
 		pr_err("Cannot open ELF image %pe\n", elf);
 		return PTR_ERR(elf);
@@ -292,9 +596,9 @@ static int k3_r5_start_image(void)
 		elf_close(elf);
 	}
 
-	free(ti_dm_buf);
+	free(k3_ti_dm);
 
-	fw.data = bl31;
+	fw.data = BL31_ADDRESS;
 
 	/* Release all the exclusive devices held by SPL before starting ATF */
 	pr_info("Starting TF-A on A53 core\n");
@@ -324,3 +628,4 @@ static int xload(void)
 	hang();
 }
 postenvironment_initcall(xload);
+#endif /* IN_PROPER */
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index 7f0796f7f4..14dfc4a28a 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -2,6 +2,11 @@
 #define __MACH_K3_COMMON_H
 
 #include <bootsource.h>
+#include <linux/sizes.h>
+#include <linux/uuid.h>
+
+#define UUID_TI_DM_FW \
+        UUID_INIT(0x9e8c2017, 0x8b94, 0x4e2b, 0xa7, 0xb3, 0xa0, 0xf8, 0x8e, 0xab, 0xb8, 0xae)
 
 void am625_get_bootsource(enum bootsource *src, int *instance);
 bool k3_boot_is_emmc(void);
@@ -9,4 +14,6 @@ u64 am625_sdram_size(void);
 void am625_register_dram(void);
 void am625_enable_32k_crystal(void);
 
+#define K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE	SZ_1M
+
 #endif /* __MACH_K3_COMMON_H */

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb  5 01:48:32 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed,  5 Feb 2025 10:48:32 +0100
Subject: [PATCH] environment: fix free() of unitialized variable
Message-ID: <20250205094832.3576556-1-s.hauer@pengutronix.de>

of_find_path() doesn't initialize the outpath on error. In order to
free() it in the error path we have to initialize devpath.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/of/barebox.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/of/barebox.c b/drivers/of/barebox.c
index 9b8da679e2..e6bcff7116 100644
--- a/drivers/of/barebox.c
+++ b/drivers/of/barebox.c
@@ -34,7 +34,7 @@ static char *environment_probe_1node_binding(struct device *dev)
 static char *environment_probe_2node_binding(struct device *dev)
 {
 	const char *filepath;
-	char *devpath;
+	char *devpath = NULL;
 	int ret;
 
 	ret = of_find_path(dev->of_node, "device-path", &devpath,
-- 
2.39.5



From jmaselbas at zdiv.net  Wed Feb  5 02:25:49 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed,  5 Feb 2025 11:25:49 +0100
Subject: [PATCH] scripts: include: rename printk.h to printf.h
Message-ID: <20250205102549.27015-1-jmaselbas@zdiv.net>

The include scripts/include/asm-generic/bug.h relied on a printk.h
compatible header which is located in the scripts/include/ and was
not updated when printk.h was renamed to printf.h.

Fixes: d8ea946bcf ("include: rename printk.h to printf.h")
Signed-off-by: Jules Maselbas <jmaselbas at zdiv.net>
---
 scripts/include/{printk.h => printf.h} | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
 rename scripts/include/{printk.h => printf.h} (54%)

diff --git a/scripts/include/printk.h b/scripts/include/printf.h
similarity index 54%
rename from scripts/include/printk.h
rename to scripts/include/printf.h
index 363d32f2e5..2ce99c2fa8 100644
--- a/scripts/include/printk.h
+++ b/scripts/include/printf.h
@@ -1,9 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef __PRINTK_H
-#define __PRINTK_H
+#ifndef __PRINTF_H
+#define __PRINTF_H
 
 #include <stdio.h>
 
-#define printk printf
-
 #endif
-- 
2.48.1



From jmaselbas at zdiv.net  Wed Feb  5 02:31:29 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 05 Feb 2025 11:31:29 +0100
Subject: [PATCH RFT v3] scripts: define _GNU_SOURCE for all source files
In-Reply-To: <20250127195109.3928003-1-a.fatoum@pengutronix.de>
References: <20250127195109.3928003-1-a.fatoum@pengutronix.de>
Message-ID: <D7KFYN803WNQ.BOAE8FUKU416@zdiv.net>

Tested on alpine linux with musl 1.2.5, and it compiled without issue

On Mon Jan 27, 2025 at 8:51 PM CET, Ahmad Fatoum wrote:
> musl doesn't define loff_t, unless _GNU_SOURCE is defined, which
> we don't do everywhere and glibc didn't mind.
>
> This led to build errors with musl when code makes it into
> scripts/ that uses loff_t. This was already fixed once e.g. in commit
> c0d065fb0aa0 ("scripts: bareboximd: remove usage of loff_t").
>
> To fix this issue for good, let's define _GNU_SOURCE globally for all files.
>
> Link: https://lore.kernel.org/all/CAMKF1sqX7gFCEH78fHS+jkUSieL5crAU_RwAUO-daJL0u+fj0g at mail.gmail.com/
> Fixes: 5171f4d0696f ("scripts: implement read_fd and pread_full for tools")
> Suggested-by: Khem Raj <raj.khem at gmail.com>
> Reported-by: Enrico J?rns <ejo at pengutronix.de>
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> @Enrico, please give this a test. I only tested against glibc.
>
> v2 -> v3:
>   - set _GNU_SOURCE instead of defining loff_t (Khem)
> v1 -> v2:
>   - include <linux/types.h> from scripts/common.h (Enrico)
> v2 was here:
>   https://lore.barebox.org/barebox/20250127143146.2965544-1-a.fatoum at pengutronix.de/T/#u
> ---


From s.hauer at pengutronix.de  Thu Feb  6 23:20:13 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri,  7 Feb 2025 08:20:13 +0100
Subject: [PATCH] soc: k3: Add support for Texas Instruments K3 ESM driver
Message-ID: <20250207072013.226803-1-s.hauer@pengutronix.de>

The ESM (Error Signaling Module) is used to route error signals within
the K3 SoCs somewhat similar to interrupts. The handling for these is
different though, and can be routed for hardware error handling, to
be handled by safety processor or just as error interrupts handled
by the main processor. The u-boot level ESM driver is just used to
configure the ESM signals so that they get routed to proper destination.

The code and the commit message is based on the corresponding U-Boot
driver as of U-Boot-2025.01.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/common.c |  13 ++++
 drivers/soc/Kconfig       |   1 +
 drivers/soc/ti/Kconfig    |   4 ++
 drivers/soc/ti/Makefile   |   1 +
 drivers/soc/ti/k3-esm.c   | 136 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 155 insertions(+)
 create mode 100644 drivers/soc/ti/Kconfig
 create mode 100644 drivers/soc/ti/k3-esm.c

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 9e3dab5b8e..c2a774ea67 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -242,6 +242,17 @@ static int am625_of_fixup(struct device_node *root, void *unused)
 	return 0;
 }
 
+#define CTRLMMR_MCU_RST_CTRL	IOMEM(0x04518170)
+#define RST_CTRL_ESM_ERROR_RST_EN_Z_MASK BIT(17)
+
+static void am625_enable_mcu_esm_reset(void)
+{
+	/* activate reset of main by ESMO */
+	u32 stat = readl(CTRLMMR_MCU_RST_CTRL);
+	stat &= ~RST_CTRL_ESM_ERROR_RST_EN_Z_MASK;
+	writel(stat, CTRLMMR_MCU_RST_CTRL);
+}
+
 static int am625_init(void)
 {
 	enum bootsource src = BOOTSOURCE_UNKNOWN;
@@ -264,6 +275,8 @@ static int am625_init(void)
 
 	of_register_fixup(am625_of_fixup, NULL);
 
+	am625_enable_mcu_esm_reset();
+
 	return 0;
 }
 postcore_initcall(am625_init);
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index c0fe214429..cbde3c35a4 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -3,5 +3,6 @@ menu "SoC drivers"
 source "drivers/soc/imx/Kconfig"
 source "drivers/soc/kvx/Kconfig"
 source "drivers/soc/rockchip/Kconfig"
+source "drivers/soc/ti/Kconfig"
 
 endmenu
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
new file mode 100644
index 0000000000..8d2dd86f3f
--- /dev/null
+++ b/drivers/soc/ti/Kconfig
@@ -0,0 +1,4 @@
+config K3_ESM
+	bool
+	depends on ARCH_K3 && MACH_K3_CORTEX_R5
+	default y
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 56f6653882..3109a4e967 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -1 +1,2 @@
 obj-y += k3-navss-ringacc.o
+obj-$(CONFIG_K3_ESM) += k3-esm.o
diff --git a/drivers/soc/ti/k3-esm.c b/drivers/soc/ti/k3-esm.c
new file mode 100644
index 0000000000..3f51b757c9
--- /dev/null
+++ b/drivers/soc/ti/k3-esm.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 Error Signalling Module driver
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com/
+ *      Tero Kristo <t-kristo at ti.com>
+ *
+ */
+
+#include <driver.h>
+#include <malloc.h>
+#include <xfuncs.h>
+#include <io.h>
+
+#define ESM_SFT_RST			0x0c
+#define ESM_SFT_RST_KEY			0x0f
+#define ESM_EN				0x08
+#define ESM_EN_KEY			0x0f
+
+#define ESM_STS(i)			(0x404 + (i) / 32 * 0x20)
+#define ESM_STS_MASK(i)			(1 << ((i) % 32))
+#define ESM_PIN_EN_SET_OFFSET(i)	(0x414 + (i) / 32 * 0x20)
+#define ESM_PIN_MASK(i)			(1 << ((i) % 32))
+#define ESM_INTR_EN_SET_OFFSET(i)	(0x408 + (i) / 32 * 0x20)
+#define ESM_INTR_MASK(i)		(1 << ((i) % 32))
+#define ESM_INTR_PRIO_SET_OFFSET(i)	(0x410 + (i) / 32 * 0x20)
+#define ESM_INTR_PRIO_MASK(i)		(1 << ((i) % 32))
+
+static void esm_pin_enable(void __iomem *base, int pin)
+{
+	u32 value;
+
+	value = readl(base + ESM_PIN_EN_SET_OFFSET(pin));
+	value |= ESM_PIN_MASK(pin);
+	/* Enable event */
+	writel(value, base + ESM_PIN_EN_SET_OFFSET(pin));
+}
+
+static void esm_intr_enable(void __iomem *base, int pin)
+{
+	u32 value;
+
+	value = readl(base + ESM_INTR_EN_SET_OFFSET(pin));
+	value |= ESM_INTR_MASK(pin);
+	/* Enable Interrupt event */
+	writel(value, base + ESM_INTR_EN_SET_OFFSET(pin));
+}
+
+static void esm_intr_prio_set(void __iomem *base, int pin)
+{
+	u32 value;
+
+	value = readl(base + ESM_INTR_PRIO_SET_OFFSET(pin));
+	value |= ESM_INTR_PRIO_MASK(pin);
+	/* Set to priority */
+	writel(value, base + ESM_INTR_PRIO_SET_OFFSET(pin));
+}
+
+static void esm_clear_raw_status(void __iomem *base, int pin)
+{
+	u32 value;
+
+	value = readl(base + ESM_STS(pin));
+	value |= ESM_STS_MASK(pin);
+	/* Clear Event status */
+	writel(value, base + ESM_STS(pin));
+}
+/**
+ * k3_esm_probe: configures ESM based on DT data
+ *
+ * Parses ESM info from device tree, and configures the module accordingly.
+ */
+static int k3_esm_probe(struct device *dev)
+{
+	int ret;
+	void __iomem *base;
+	int num_pins;
+	u32 *pins;
+	int i;
+	struct device_node *np = dev->of_node;
+
+	base = dev_request_mem_region(dev, 0);
+	if (IS_ERR(base))
+		return -ENODEV;
+
+	num_pins = of_property_count_elems_of_size(np, "ti,esm-pins", sizeof(u32));
+	if (num_pins < 0) {
+		dev_err(dev, "ti,esm-pins property missing or invalid: %d\n",
+			num_pins);
+		return num_pins;
+	}
+
+	pins = xzalloc(num_pins * sizeof(u32));
+	if (!pins)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, "ti,esm-pins", pins, num_pins);
+	if (ret < 0) {
+		dev_err(dev, "failed to read ti,esm-pins property: %d\n",
+			ret);
+		goto free_pins;
+	}
+
+	/* Clear any pending events */
+	writel(ESM_SFT_RST_KEY, base + ESM_SFT_RST);
+
+	for (i = 0; i < num_pins; i++) {
+		esm_intr_prio_set(base, pins[i]);
+		esm_clear_raw_status(base, pins[i]);
+		esm_pin_enable(base, pins[i]);
+		esm_intr_enable(base, pins[i]);
+	}
+
+	/* Enable ESM */
+	writel(ESM_EN_KEY, base + ESM_EN);
+
+free_pins:
+	free(pins);
+	return ret;
+}
+
+static const struct of_device_id k3_esm_ids[] = {
+	{
+		.compatible = "ti,j721e-esm",
+	}, {
+		/* sentinel */
+	},
+};
+
+static struct driver k3_esm = {
+	.probe  = k3_esm_probe,
+	.name   = "k3-esm",
+	.of_compatible = k3_esm_ids,
+};
+
+core_platform_driver(k3_esm);
-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb  6 23:20:26 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri,  7 Feb 2025 08:20:26 +0100
Subject: [PATCH] mfd: tps65219: register regmap cdev
Message-ID: <20250207072026.226822-1-s.hauer@pengutronix.de>

Expose the tps65219 regmap as cdev for debugging purposes.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/mfd/tps65219.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/mfd/tps65219.c b/drivers/mfd/tps65219.c
index 11f2e1798b..854210537f 100644
--- a/drivers/mfd/tps65219.c
+++ b/drivers/mfd/tps65219.c
@@ -65,6 +65,10 @@ static int tps65219_probe(struct device *dev)
 			return dev_err_probe(tps->dev, ret, "Failed to add power-button\n");
 	}
 
+	ret = regmap_register_cdev(tps->regmap, NULL);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
2.39.5



From s.hauer at pengutronix.de  Fri Feb  7 00:11:41 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 07 Feb 2025 09:11:41 +0100
Subject: [PATCH] i2c: Remove dead link to struct i2c_algorithm
In-Reply-To: <20250204073151.16501-1-eagle.alexander923@gmail.com>
References: <20250204073151.16501-1-eagle.alexander923@gmail.com>
Message-ID: <173891590172.233955.5964457075081214823.b4-ty@pengutronix.de>


On Tue, 04 Feb 2025 10:31:50 +0300, Alexander Shiyan wrote:
> struct i2c_algorithm is not defined anywhere.
> 
> 

Applied, thanks!

[1/1] i2c: Remove dead link to struct i2c_algorithm
      https://git.pengutronix.de/cgit/barebox/commit/?id=d4cc0225555c (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb  7 00:25:16 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 07 Feb 2025 09:25:16 +0100
Subject: [PATCH] i2c: rockchip: Replace driver from kernel repository
In-Reply-To: <20250204132207.332918-1-eagle.alexander923@gmail.com>
References: <20250204132207.332918-1-eagle.alexander923@gmail.com>
Message-ID: <173891671690.239230.12036155929737942355.b4-ty@pengutronix.de>


On Tue, 04 Feb 2025 16:22:07 +0300, Alexander Shiyan wrote:
> The current Rockchip i2c driver was taken from the u-boot repository,
> so it has minimal functionality and is designed to be the simplest.
> Development with the Rockchip SOC led to the idea that it is not
> sufficient to handle some i2c devices (in my case, this i2c EEPROMs
> and i2c MUXes).
> This patch replaces the driver code from the Linux kernel repository
> to make the driver more flexible with SDA/SCL setup/hold settings and
> as a result, more stable across boards.
> Tested with cusom rk3568-based board.
> 
> [...]

Applied, thanks!

[1/1] i2c: rockchip: Replace driver from kernel repository
      https://git.pengutronix.de/cgit/barebox/commit/?id=840b074cdab9 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb  7 00:27:16 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 7 Feb 2025 09:27:16 +0100
Subject: [PATCH] i2c: rockchip: Replace driver from kernel repository
In-Reply-To: <20250204132207.332918-1-eagle.alexander923@gmail.com>
References: <20250204132207.332918-1-eagle.alexander923@gmail.com>
Message-ID: <Z6XD5KGrSWnYBBXL@pengutronix.de>

Hi Alexander,

On Tue, Feb 04, 2025 at 04:22:07PM +0300, Alexander Shiyan wrote:
> +
> +static int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c)
> +{
> +	uint64_t start = get_time_ns();
> +
> +	while (!is_timeout(start, WAIT_TIMEOUT)) {
> +		rk3x_i2c_irq(i2c);
> +		if (i2c->state == STATE_IDLE)
> +			return 0;
> +		udelay(5);

While it doesn't really hurt, this delay is unnecessary. We're busy
waiting anyway.

> +	}
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int rk3x_i2c_probe(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct rk3x_i2c_soc_data *data;
> +	struct resource *iores;
> +	unsigned long clk_rate;
> +	struct rk3x_i2c *i2c;
> +	int ret;
> +
> +	i2c = xzalloc(sizeof(*i2c));
> +	i2c->dev = dev;
> +
> +	ret = dev_get_drvdata(dev, (const void **)&data);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to retrieve driver data\n");

This function is deprecated:

 * DEPRECATED: use device_get_match_data instead, which avoids
 * common pitfalls due to explicit pointer casts

I fixed these two things while applying.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Fri Feb  7 00:27:48 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 07 Feb 2025 09:27:48 +0100
Subject: [PATCH] scripts: include: rename printk.h to printf.h
In-Reply-To: <20250205102549.27015-1-jmaselbas@zdiv.net>
References: <20250205102549.27015-1-jmaselbas@zdiv.net>
Message-ID: <173891686844.239361.18192152268825416500.b4-ty@pengutronix.de>


On Wed, 05 Feb 2025 11:25:49 +0100, Jules Maselbas wrote:
> The include scripts/include/asm-generic/bug.h relied on a printk.h
> compatible header which is located in the scripts/include/ and was
> not updated when printk.h was renamed to printf.h.
> 
> 

Applied, thanks!

[1/1] scripts: include: rename printk.h to printf.h
      https://git.pengutronix.de/cgit/barebox/commit/?id=f7a4435177aa (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From jonathanbaror at gmail.com  Sun Feb  9 18:39:14 2025
From: jonathanbaror at gmail.com (Jonathan Bar Or)
Date: Sun, 9 Feb 2025 18:39:14 -0800
Subject: Reporting security issues preferred method?
Message-ID: <CABMsoEEwH4Nch6bVqd+8QSMOCzMTN9LVZcSe6yJ=+Rf54sAVDg@mail.gmail.com>

Hi Barebox mailing list!

What's the best way to report security issues?

Best regards,
       Jonathan


From s.hauer at pengutronix.de  Mon Feb 10 01:03:49 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 10 Feb 2025 10:03:49 +0100
Subject: Reporting security issues preferred method?
In-Reply-To: <CABMsoEEwH4Nch6bVqd+8QSMOCzMTN9LVZcSe6yJ=+Rf54sAVDg@mail.gmail.com>
References: <CABMsoEEwH4Nch6bVqd+8QSMOCzMTN9LVZcSe6yJ=+Rf54sAVDg@mail.gmail.com>
Message-ID: <Z6nA9ce6j7wMCJJv@pengutronix.de>

Hi Jonathan,

On Sun, Feb 09, 2025 at 06:39:14PM -0800, Jonathan Bar Or wrote:
> Hi Barebox mailing list!
> 
> What's the best way to report security issues?

This question comes up from time to time. We don't have an official
answer yet, but I see we should work on one.

For now you can write to me and Ahmad afa at pengutronix.de

Regards,
 Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Feb 10 04:17:26 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 10 Feb 2025 13:17:26 +0100
Subject: [PATCH master] SECURITY.md: add security policy
Message-ID: <20250210121726.376306-1-a.fatoum@pengutronix.de>

We prefer coordinated vulnerability disclosures, so users can be provided
patch instructions for security issues alongside the vulnerabilities report.

Github handles a top-level SECURITY.md file specially and shows it in
the security tab. Unlike other documentation, this can't be written
in reST, so write it in markdown and adopt this convention.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 SECURITY.md | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
 create mode 100644 SECURITY.md

diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000000..476ab3186e04
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,14 @@
+# Security Policy
+
+## Supported Versions
+
+The barebox project does not, at the moment, maintain any longer term
+support branches.
+Please update to new [barebox releases](https://github.com/barebox/barebox/releases)
+as they become available.
+Compatibility with old kernels is maintained over barebox releases.
+
+## Reporting a Vulnerability
+
+Please report security vulnerabilities to security at barebox.org.
+We will work with the reporter to create a fix and to coordinate the disclosure.
-- 
2.39.5



From s.hauer at pengutronix.de  Tue Feb 11 01:34:08 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 11 Feb 2025 10:34:08 +0100
Subject: [PATCH] partitions: efi: Fix position of alternate gpt when writing
Message-ID: <20250211093408.1701730-1-s.hauer@pengutronix.de>

The primary GPT has a pointer to the alternate GPT. Set this pointer
correctly when writing the partition table.

When the GPT originally has been created on the device, the alternate GPT
should be at the end of the device already. However, when the GPT was
created on an image which was then written to the disk, the alternate GPT
might be at the end of the image instead of the device. In this case
the alternate GPT changes its position during a partition write, so we
have to adjust the pointer from the primary to the alternate GPT
accordingly.

Reported-by: Ulrich ?lmann <u.oelmann at pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 common/partitions/efi.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/common/partitions/efi.c b/common/partitions/efi.c
index 6caa391983..5736b6033b 100644
--- a/common/partitions/efi.c
+++ b/common/partitions/efi.c
@@ -758,6 +758,7 @@ static __maybe_unused int efi_partition_write(struct partition_desc *pd)
 		le32_to_cpu(gpt->sizeof_partition_entry);
 
 	gpt->my_lba = cpu_to_le64(1);
+	gpt->alternate_lba = cpu_to_le64(last_lba(blk));
 	gpt->partition_entry_array_crc32 = cpu_to_le32(efi_crc32(
 			(const unsigned char *)epd->ptes, count));
 	gpt->header_crc32 = 0;
-- 
2.39.5



From u.oelmann at pengutronix.de  Tue Feb 11 01:34:49 2025
From: u.oelmann at pengutronix.de (=?UTF-8?q?Ulrich=20=C3=96lmann?=)
Date: Tue, 11 Feb 2025 10:34:49 +0100
Subject: [PATCH] partitions: efi: fix error message in mkpart
Message-ID: <20250211093449.2226799-1-u.oelmann@pengutronix.de>

Provided the condition in the if-clause is correct fix the off-by-one in
calculating the maximum. Additionally print end_lba instead of start_lba.

Signed-off-by: Ulrich ?lmann <u.oelmann at pengutronix.de>
---
 common/partitions/efi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/common/partitions/efi.c b/common/partitions/efi.c
index 6caa3919832c..b5b4d378e69b 100644
--- a/common/partitions/efi.c
+++ b/common/partitions/efi.c
@@ -651,8 +651,8 @@ static __maybe_unused int efi_partition_mkpart(struct partition_desc *pd,
 	}
 
 	if (end_lba >= last_lba(pd->blk) - 33) {
-		pr_err("invalid end LBA %lld, maximum is %lld\n", start_lba,
-		       last_lba(pd->blk) - 33);
+		pr_err("invalid end LBA %lld, maximum is %lld\n", end_lba,
+		       last_lba(pd->blk) - 34);
 		return -EINVAL;
 	}
 
-- 
2.39.5



From martin.l.wege at gmail.com  Tue Feb 11 04:56:58 2025
From: martin.l.wege at gmail.com (Martin Wege)
Date: Tue, 11 Feb 2025 13:56:58 +0100
Subject: Mount NFSv4.2 filesystem in barebox?
Message-ID: <CANH4o6Njc3uHE=NbasRJrRr0W5B89R8MTM_BwGwab7t5fNWuaA@mail.gmail.com>

Hello!

Does barebox have support to mount a NFSv.2 filesystem?

Thanks,
Martin


From jmaselbas at zdiv.net  Wed Feb 12 02:48:37 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 12 Feb 2025 11:48:37 +0100
Subject: [PATCH v3 1/6] clk: divider: add error code propagation
In-Reply-To: <20250212104842.504-1-jmaselbas@zdiv.net>
References: <20250212104842.504-1-jmaselbas@zdiv.net>
Message-ID: <20250212104842.504-2-jmaselbas@zdiv.net>

divider_get_val can return a negative error code and should not be used
as a valid divider.

Signed-off-by: Jules Maselbas <jmaselbas at zdiv.net>
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1->v2:
  - changed value to int and removed ret variable (Ahmad)
v2->v3: no change

 drivers/clk/clk-divider.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index ccab70aecc..b0df34e858 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -307,7 +307,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 {
 	struct clk *clk = clk_hw_to_clk(hw);
 	struct clk_divider *divider = to_clk_divider(hw);
-	unsigned int value;
+	int value;
 	u32 val;
 
 	if (divider->flags & CLK_DIVIDER_READ_ONLY)
@@ -322,6 +322,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 
 	value = divider_get_val(rate, parent_rate, divider->table,
 				divider->width, divider->flags);
+	if (value < 0)
+		return value;
 
 	val = readl(divider->reg);
 	val &= ~(clk_div_mask(divider->width) << divider->shift);
-- 
2.48.1



From jmaselbas at zdiv.net  Wed Feb 12 02:48:39 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 12 Feb 2025 11:48:39 +0100
Subject: [PATCH v3 3/6] pinctrl: Add sun50i-a64 pinctrl driver
In-Reply-To: <20250212104842.504-1-jmaselbas@zdiv.net>
References: <20250212104842.504-1-jmaselbas@zdiv.net>
Message-ID: <20250212104842.504-4-jmaselbas@zdiv.net>

sunxi pinctrl driver, adapted from Linux, is split in two parts:
 - pinctrl-sunxi.c that implements gpio, pinctrl and pinmux functions
 - pinctrl-sun50i-a64.c that declare sun50i pins and their functions.
   This file only require minor adaptations and be easily copied from Linux.

The pin functions are needed for uart, SD/MMC, and likely for other
controllers too.

Signed-off-by: Jules Maselbas <jmaselbas at zdiv.net>
---
v1->v2:
 - removed `!IS_ENABLED(CONFIG_PINCTRL)` (Sacha)
v2->v3:
 - use `%pOF` to print device-tree node full_name (Ahmad)

 drivers/pinctrl/Kconfig                    |   2 +
 drivers/pinctrl/Makefile                   |   1 +
 drivers/pinctrl/sunxi/Kconfig              |  13 +
 drivers/pinctrl/sunxi/Makefile             |   3 +
 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 594 +++++++++++++++++++++
 drivers/pinctrl/sunxi/pinctrl-sunxi.c      | 369 +++++++++++++
 drivers/pinctrl/sunxi/pinctrl-sunxi.h      | 224 ++++++++
 7 files changed, 1206 insertions(+)
 create mode 100644 drivers/pinctrl/sunxi/Kconfig
 create mode 100644 drivers/pinctrl/sunxi/Makefile
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.h

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index ee15acdcdb..72ca79aa98 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -106,6 +106,8 @@ config PINCTRL_STM32
 	select HAVE_GPIO_PINCONF
 	help
 	  Pinmux and GPIO controller found on STM32 family
+
+source "drivers/pinctrl/sunxi/Kconfig"
 endif
 
 endmenu
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f1a5fa5715..3bc718d355 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
 obj-$(CONFIG_PINCTRL_STM32) += pinctrl-stm32.o
 
 obj-$(CONFIG_ARCH_MVEBU) += mvebu/
+obj-$(CONFIG_ARCH_SUNXI) += sunxi/
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
new file mode 100644
index 0000000000..38d8894a7e
--- /dev/null
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+if ARCH_SUNXI
+
+config PINCTRL_SUNXI
+	bool
+	select GPIOLIB
+
+config PINCTRL_SUN50I_A64
+	bool "Support for Allwinner A64 PIO"
+	default ARCH_SUNXI
+	select PINCTRL_SUNXI
+
+endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
new file mode 100644
index 0000000000..db0ff5b50b
--- /dev/null
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_ARCH_SUNXI)		+= pinctrl-sunxi.o
+obj-$(CONFIG_PINCTRL_SUN50I_A64)	+= pinctrl-sun50i-a64.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
new file mode 100644
index 0000000000..db96cb52b9
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
@@ -0,0 +1,594 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Allwinner A64 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2016 - ARM Ltd.
+ * Author: Andre Przywara <andre.przywara at arm.com>
+ *
+ * Based on pinctrl-sun7i-a20.c, which is:
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard at free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <common.h>
+#include <init.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin a64_pins[] = {
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "jtag"),		/* MS0 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),	/* EINT0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "jtag"),		/* CK0 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* VCCEN */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),		/* EINT1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* RTS */
+		  SUNXI_FUNCTION(0x4, "jtag"),		/* DO0 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* VPPEN */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),		/* EINT2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart2"),		/* CTS */
+		  SUNXI_FUNCTION(0x3, "i2s0"),		/* MCLK */
+		  SUNXI_FUNCTION(0x4, "jtag"),		/* DI0 */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* VPPPP */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)),		/* EINT3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif2"),		/* SYNC */
+		  SUNXI_FUNCTION(0x3, "i2s0"),		/* SYNC */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)),		/* EINT4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif2"),		/* BCLK */
+		  SUNXI_FUNCTION(0x3, "i2s0"),		/* BCLK */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* DATA */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)),		/* EINT5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif2"),		/* DOUT */
+		  SUNXI_FUNCTION(0x3, "i2s0"),		/* DOUT */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* RST */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)),		/* EINT6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif2"),		/* DIN */
+		  SUNXI_FUNCTION(0x3, "i2s0"),		/* DIN */
+		  SUNXI_FUNCTION(0x5, "sim"),		/* DET */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)),		/* EINT7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 8),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x4, "uart0"),		/* TX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)),		/* EINT8 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 9),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x4, "uart0"),		/* RX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)),		/* EINT9 */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NWE */
+		  SUNXI_FUNCTION(0x4, "spi0")),		/* MOSI */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NALE */
+		  SUNXI_FUNCTION(0x3, "mmc2"),		/* DS */
+		  SUNXI_FUNCTION(0x4, "spi0")),		/* MISO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NCLE */
+		  SUNXI_FUNCTION(0x4, "spi0")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NCE1 */
+		  SUNXI_FUNCTION(0x4, "spi0")),		/* CS */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NCE0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NRE# */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NRB0 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* CMD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0")),	/* NRB1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ0 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ1 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ2 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ3 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ4 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ5 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ6 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQ7 */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* D7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "nand0"),		/* NDQS */
+		  SUNXI_FUNCTION(0x3, "mmc2")),		/* RST */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "uart3"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "spi1"),		/* CS */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "uart3"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "spi1"),		/* CLK */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* DE */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D4 */
+		  SUNXI_FUNCTION(0x3, "uart4"),		/* TX */
+		  SUNXI_FUNCTION(0x4, "spi1"),		/* MOSI */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* HSYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D5 */
+		  SUNXI_FUNCTION(0x3, "uart4"),		/* RX */
+		  SUNXI_FUNCTION(0x4, "spi1"),		/* MISO */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* VSYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D6 */
+		  SUNXI_FUNCTION(0x3, "uart4"),		/* RTS */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D7 */
+		  SUNXI_FUNCTION(0x3, "uart4"),		/* CTS */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D10 */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D11 */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D12 */
+		  SUNXI_FUNCTION(0x4, "emac"),		/* ERXD3 */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D13 */
+		  SUNXI_FUNCTION(0x4, "emac"),		/* ERXD2 */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D14 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ERXD1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D15 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ERXD0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D18 */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VP0 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ERXCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D19 */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VN0 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ERXCTL */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D20 */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VP1 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ENULL */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D21 */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VN1 */
+		  SUNXI_FUNCTION(0x4, "emac"),		/* ETXD3 */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D22 */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VP2 */
+		  SUNXI_FUNCTION(0x4, "emac"),		/* ETXD2 */
+		  SUNXI_FUNCTION(0x5, "ccir")),		/* D7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* D23 */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VN2 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ETXD1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VPC */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ETXD0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* DE */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VNC */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ETXCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* HSYNC */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VP3 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ETXCTL */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "lcd0"),		/* VSYNC */
+		  SUNXI_FUNCTION(0x3, "lvds0"),		/* VN3 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* ECLKIN */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "pwm"),		/* PWM0 */
+		  SUNXI_FUNCTION(0x4, "emac")),		/* EMDC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x4, "emac")),		/* EMDIO */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* PCK */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* CLK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* CK */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* ERR */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* HSYNC */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* SYNC */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* VSYNC */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* DVLD */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D0 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D1 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D2 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D3 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D4 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D5 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D6 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi"),		/* D7 */
+		  SUNXI_FUNCTION(0x4, "ts")),		/* D7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "csi")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "pll"),		/* LOCK_DBG */
+		  SUNXI_FUNCTION(0x3, "i2c2")),		/* SCK */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x3, "i2c2")),		/* SDA */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D1 */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* MSI */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D0 */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* DI1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CLK */
+		  SUNXI_FUNCTION(0x3, "uart0")),	/* TX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* CMD */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* DO1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D3 */
+		  SUNXI_FUNCTION(0x3, "uart0")),	/* RX */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc0"),		/* D2 */
+		  SUNXI_FUNCTION(0x3, "jtag")),		/* CK1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out")),
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)),	/* EINT0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* CMD */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)),	/* EINT1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D0 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)),	/* EINT2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D1 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)),	/* EINT3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D2 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)),	/* EINT4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mmc1"),		/* D3 */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)),	/* EINT5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* TX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)),	/* EINT6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* RX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)),	/* EINT7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)),	/* EINT8 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart1"),		/* CTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)),	/* EINT9 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif3"),		/* SYNC */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* SYNC */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 10)),	/* EINT10 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif3"),		/* BCLK */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* BCLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 11)),	/* EINT11 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif3"),		/* DOUT */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* DOUT */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 12)),	/* EINT12 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "aif3"),		/* DIN */
+		  SUNXI_FUNCTION(0x3, "i2s1"),		/* DIN */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 13)),	/* EINT13 */
+	/* Hole */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c0"),		/* SCK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)),	/* EINT0 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c0"),		/* SDA */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)),	/* EINT1 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c1"),		/* SCK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)),	/* EINT2 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "i2c1"),		/* SDA */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)),	/* EINT3 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart3"),		/* TX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)),	/* EINT4 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart3"),		/* RX */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)),	/* EINT5 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart3"),		/* RTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)),	/* EINT6 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 7),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "uart3"),		/* CTS */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)),	/* EINT7 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "spdif"),		/* OUT */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)),	/* EINT8 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)),	/* EINT9 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mic"),		/* CLK */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)),	/* EINT10 */
+	SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
+		  SUNXI_FUNCTION(0x0, "gpio_in"),
+		  SUNXI_FUNCTION(0x1, "gpio_out"),
+		  SUNXI_FUNCTION(0x2, "mic"),		/* DATA */
+		  SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)),	/* EINT11 */
+};
+
+static const struct sunxi_pinctrl_desc a64_pinctrl_data = {
+	.pins = a64_pins,
+	.npins = ARRAY_SIZE(a64_pins),
+};
+
+static const struct of_device_id a64_pinctrl_dt_match[] = {
+	{
+		.compatible = "allwinner,sun50i-a64-pinctrl",
+		.data = &a64_pinctrl_data
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver a64_pinctrl_driver = {
+	.name		= "sun50i-a64-pinctrl",
+	.probe		= sunxi_pinctrl_probe,
+	.of_compatible	= DRV_OF_COMPAT(a64_pinctrl_dt_match),
+};
+core_platform_driver(a64_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
new file mode 100644
index 0000000000..dc33276c56
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -0,0 +1,369 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "pinctrl-sunxi: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <of.h>
+#include <of_address.h>
+#include <malloc.h>
+#include <linux/clk.h>
+
+#include "pinctrl-sunxi.h"
+
+/* This driver assumes the gpio function mux value will not change */
+#define FUNC_GPIO_IN	0
+#define FUNC_GPIO_OUT	1
+
+static struct sunxi_pinctrl *to_sunxi_pinctrl(struct pinctrl_device *pdev)
+{
+	return container_of(pdev, struct sunxi_pinctrl, pdev);
+}
+
+static void sunxi_pinctrl_set_pull(struct sunxi_pinctrl *pinctrl,
+				   u16 pin, u32 pull)
+{
+	u32 reg = sunxi_pull_reg(pin);
+	u32 off = sunxi_pull_offset(pin);
+	u32 msk = MUX_PINS_MASK << off;
+	u32 val = readl(pinctrl->base + reg);
+
+	val &= ~msk;
+	val |= (pull << off) & msk;
+	writel(val, pinctrl->base + reg);
+}
+
+static void sunxi_pinctrl_set_dlevel(struct sunxi_pinctrl *pinctrl,
+				   u16 pin, u32 lvl)
+{
+	u32 reg = sunxi_dlevel_reg(pin);
+	u32 off = sunxi_dlevel_offset(pin);
+	u32 msk = MUX_PINS_MASK << off;
+	u32 val = readl(pinctrl->base + reg);
+
+	val &= ~msk;
+	val |= (lvl << off) & msk;
+	writel(val, pinctrl->base + reg);
+}
+
+static void sunxi_pinctrl_set_mux(struct sunxi_pinctrl *pinctrl,
+				  u16 pin, u8 mux)
+{
+	u32 reg = sunxi_mux_reg(pin);
+	u32 off = sunxi_mux_offset(pin);
+	u32 msk = MUX_PINS_MASK << off;
+	u32 val = readl(pinctrl->base + reg);
+
+	val &= ~msk;
+	val |= (mux << off) & msk;
+	writel(val, pinctrl->base + reg);
+}
+
+static u8 sunxi_pinctrl_get_mux(struct sunxi_pinctrl *pinctrl, u16 pin)
+{
+	u32 reg = sunxi_mux_reg(pin);
+	u32 off = sunxi_mux_offset(pin);
+	u32 val = readl(pinctrl->base + reg);
+
+	return (val >> off) & MUX_PINS_MASK;
+}
+
+static void sunxi_pinctrl_set_conf(struct sunxi_pinctrl *pinctrl,
+				  u16 pin, struct device_node *node)
+{
+	u32 val;
+
+	if (of_find_property(node, "bias-pull-up", NULL))
+		sunxi_pinctrl_set_pull(pinctrl, pin, 1);
+	if (of_find_property(node, "bias-pull-down", NULL))
+		sunxi_pinctrl_set_pull(pinctrl, pin, 2);
+	if (of_find_property(node, "bias-disable", NULL))
+		sunxi_pinctrl_set_pull(pinctrl, pin, 0);
+
+	if (!of_property_read_u32(node, "drive-strength", &val)) {
+		val = rounddown(val, 10) / 10 - 1;
+		sunxi_pinctrl_set_dlevel(pinctrl, pin, val);
+	}
+}
+
+static const char *sunxi_pinctrl_parse_function_prop(struct device_node *node)
+{
+	const char *function;
+	int ret;
+
+	/* Try the generic binding */
+	ret = of_property_read_string(node, "function", &function);
+	if (!ret)
+		return function;
+
+	/* And fall back to our legacy one */
+	ret = of_property_read_string(node, "allwinner,function", &function);
+	if (!ret)
+		return function;
+
+	return NULL;
+}
+
+static struct property *sunxi_pinctrl_find_pins_prop(struct device_node *node)
+{
+	struct property *prop;
+
+	/* Try the generic binding */
+	prop = of_find_property(node, "pins", NULL);
+	if (prop)
+		return prop;
+
+	/* And fall back to our legacy one */
+	prop = of_find_property(node, "allwinner,pins", NULL);
+	if (prop)
+		return prop;
+
+	return NULL;
+}
+
+#define sunxi_pinctrl_of_pins_for_each_string(np, prop, s)	\
+	for (prop = sunxi_pinctrl_find_pins_prop(np),		\
+		s = of_prop_next_string(prop, NULL);		\
+		s;						\
+		s = of_prop_next_string(prop, s))
+
+
+static const struct sunxi_desc_pin *
+sunxi_pinctrl_find_pin(struct sunxi_pinctrl *pinctrl, const char *pin_name)
+{
+	const struct sunxi_desc_pin *pin;
+	int i;
+
+	for (i = 0; i < pinctrl->desc->npins; i++) {
+		pin = &pinctrl->desc->pins[i];
+		if (!strcmp(pin->pin.name, pin_name))
+			return pin;
+	}
+
+	return NULL;
+}
+
+static const struct sunxi_desc_function *
+sunxi_pinctrl_find_func(struct sunxi_pinctrl *pinctrl,
+			const char *pin_name, const char *func_name)
+{
+	const struct sunxi_desc_pin *pin;
+	const struct sunxi_desc_function *func;
+
+	pin = sunxi_pinctrl_find_pin(pinctrl, pin_name);
+	if (!pin)
+		return NULL;
+
+	for (func = pin->functions; func->name; func++)
+		if (!strcmp(func->name, func_name))
+			return func;
+
+	return NULL;
+}
+
+static int sunxi_pinctrl_set_func(struct sunxi_pinctrl *pinctrl,
+				  struct device_node *np,
+				  const char *pin_name, const char *func_name)
+{
+	struct device *dev = pinctrl->pdev.dev;
+	const struct sunxi_desc_pin *pin;
+	const struct sunxi_desc_function *func;
+
+	dev_dbg(dev, "setfunc %s @ %s\n", func_name, pin_name);
+
+	pin = sunxi_pinctrl_find_pin(pinctrl, pin_name);
+	if (!pin) {
+		dev_err(dev, "pin %s not found\n", pin_name);
+		return -EINVAL;
+	}
+
+	func = sunxi_pinctrl_find_func(pinctrl, pin_name, func_name);
+	if (!func) {
+		dev_err(dev, "func %s not found\n", func_name);
+		return -EINVAL;
+	}
+
+	sunxi_pinctrl_set_mux(pinctrl, pin->pin.number, func->muxval);
+	sunxi_pinctrl_set_conf(pinctrl, pin->pin.number, np);
+
+	return 0;
+}
+
+static int sunxi_pinctrl_set_state(struct pinctrl_device *pdev, struct device_node *np)
+{
+	struct sunxi_pinctrl *pinctrl = to_sunxi_pinctrl(pdev);
+	struct device *dev = pinctrl->pdev.dev;
+	struct property *prop;
+	const char *func_name;
+	const char *pin_name;
+
+	func_name = sunxi_pinctrl_parse_function_prop(np);
+	if (!func_name) {
+		dev_err(dev, "%pOF: missing 'function' property\n", np);
+		return -EINVAL;
+	}
+
+	sunxi_pinctrl_of_pins_for_each_string(np, prop, pin_name) {
+		sunxi_pinctrl_set_func(pinctrl, np, pin_name, func_name);
+	}
+
+	return 0;
+}
+
+static int sunxi_pinctrl_set_direction(struct pinctrl_device *pdev, unsigned int gpio, bool in)
+{
+	struct sunxi_pinctrl *pinctrl = to_sunxi_pinctrl(pdev);
+	u32 func = in ? FUNC_GPIO_IN : FUNC_GPIO_OUT;
+
+	sunxi_pinctrl_set_mux(pinctrl, gpio, func);
+
+	return 0;
+}
+
+static int sunxi_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+	struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+	u32 reg = sunxi_data_reg(gpio);
+	u32 bit = sunxi_data_offset(gpio);
+	u32 val = readl(pinctrl->base + reg);
+
+	return val & BIT(bit);
+}
+
+static void sunxi_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
+{
+	struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+	u32 reg = sunxi_data_reg(gpio);
+	u32 bit = sunxi_data_offset(gpio);
+	u32 val = readl(pinctrl->base + reg);
+
+	if (value)
+		val |= BIT(bit);
+	else
+		val &= ~BIT(bit);
+	writel(val, pinctrl->base + reg);
+}
+
+static int sunxi_gpio_direction_output(struct gpio_chip *chip,
+				       unsigned gpio, int value)
+{
+	struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+
+	sunxi_gpio_set(chip, gpio, value);
+	sunxi_pinctrl_set_mux(pinctrl, gpio, FUNC_GPIO_OUT);
+
+	return 0;
+}
+
+static int sunxi_gpio_direction_input(struct gpio_chip *chip,
+					unsigned gpio)
+{
+	struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+
+	sunxi_pinctrl_set_mux(pinctrl, gpio, FUNC_GPIO_IN);
+
+	return 0;
+}
+
+static int sunxi_gpio_get_direction(struct gpio_chip *chip, unsigned gpio)
+{
+	struct sunxi_pinctrl *pinctrl = chip->dev->priv;
+	u32 func = sunxi_pinctrl_get_mux(pinctrl, gpio);
+
+	if (func == FUNC_GPIO_IN)
+		return GPIOF_DIR_IN;
+	if (func == FUNC_GPIO_OUT)
+		return GPIOF_DIR_OUT;
+	return -EINVAL;
+}
+
+static int sunxi_gpio_of_xlate(struct gpio_chip *chip,
+			       const struct of_phandle_args *gpiospec,
+			       u32 *flags)
+{
+	int pin, base;
+
+	if (gpiospec->args_count != 3)
+		return -EINVAL;
+
+	base = PINS_PER_BANK * gpiospec->args[0];
+	pin = base + gpiospec->args[1];
+
+	if (pin > chip->ngpio)
+		return -EINVAL;
+
+	if (flags)
+		*flags = gpiospec->args[2];
+
+	return pin;
+}
+
+static struct pinctrl_ops sunxi_pinctrl_ops = {
+	.set_state = sunxi_pinctrl_set_state,
+	.set_direction = sunxi_pinctrl_set_direction,
+};
+
+static struct gpio_ops sunxi_gpio_ops = {
+	.request = sunxi_gpio_direction_input, /* switch to input function */
+	.direction_input = sunxi_gpio_direction_input,
+	.direction_output = sunxi_gpio_direction_output,
+	.get_direction = sunxi_gpio_get_direction,
+	.get = sunxi_gpio_get,
+	.set = sunxi_gpio_set,
+	.of_xlate = sunxi_gpio_of_xlate,
+};
+
+int sunxi_pinctrl_probe(struct device *dev)
+{
+	const struct sunxi_pinctrl_desc *desc;
+	struct sunxi_pinctrl *pinctrl;
+	struct resource *iores;
+	int ret;
+
+	desc = device_get_match_data(dev);
+	if (!desc)
+                return -EINVAL;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	pinctrl = xzalloc(sizeof(*pinctrl));
+	dev->priv = pinctrl;
+	pinctrl->base = IOMEM(iores->start);
+
+	pinctrl->desc = desc;
+	pinctrl->pdev.dev = dev;
+	pinctrl->pdev.ops = &sunxi_pinctrl_ops;
+
+	ret = pinctrl_register(&pinctrl->pdev);
+	if (ret) {
+		dev_err(dev, "couldn't register %s driver\n", "pinctrl");
+		goto err;
+	}
+	dev_dbg(dev, "sunxi %s registered\n", "pinctrl");
+
+	pinctrl->chip.dev = dev;
+	pinctrl->chip.ops = &sunxi_gpio_ops;
+	/* only the first 8 bank are supported */
+	pinctrl->chip.base = 0;
+	pinctrl->chip.ngpio = 8 * PINS_PER_BANK;
+	pinctrl->chip.of_gpio_n_cells = 3;
+
+	if (of_property_read_bool(dev->of_node, "gpio-controller")) {
+		ret = gpiochip_add(&pinctrl->chip);
+		if (ret) {
+			dev_err(dev, "couldn't register %s driver\n", "gpio-chip");
+			goto pinctrl_unregister;
+		}
+		dev_dbg(dev, "sunxi %s registered\n", "gpio-chip");
+	}
+	return 0;
+
+pinctrl_unregister:
+	pinctrl_unregister(&pinctrl->pdev);
+err:
+	release_region(iores);
+	free(pinctrl);
+	return ret;
+}
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
new file mode 100644
index 0000000000..630f1ef98e
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -0,0 +1,224 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Allwinner A1X SoCs pinctrl driver.
+ *
+ * Copyright (C) 2012 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard at free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PINCTRL_SUNXI_H
+#define __PINCTRL_SUNXI_H
+
+#include <pinctrl.h>
+#include <gpio.h>
+
+#define PA_BASE	0
+#define PB_BASE	32
+#define PC_BASE	64
+#define PD_BASE	96
+#define PE_BASE	128
+#define PF_BASE	160
+#define PG_BASE	192
+#define PH_BASE	224
+#define PI_BASE	256
+#define PL_BASE	352
+#define PM_BASE	384
+#define PN_BASE	416
+
+#define SUNXI_PIN_NAME_MAX_LEN	5
+
+#define BANK_MEM_SIZE		0x24
+#define MUX_REGS_OFFSET		0x0
+#define DATA_REGS_OFFSET	0x10
+#define DLEVEL_REGS_OFFSET	0x14
+#define PULL_REGS_OFFSET	0x1c
+
+#define PINS_PER_BANK		32
+#define MUX_PINS_PER_REG	8
+#define MUX_PINS_BITS		4
+#define MUX_PINS_MASK		0x0f
+#define DATA_PINS_PER_REG	32
+#define DATA_PINS_BITS		1
+#define DATA_PINS_MASK		0x01
+#define DLEVEL_PINS_PER_REG	16
+#define DLEVEL_PINS_BITS	2
+#define DLEVEL_PINS_MASK	0x03
+#define PULL_PINS_PER_REG	16
+#define PULL_PINS_BITS		2
+#define PULL_PINS_MASK		0x03
+
+#define GRP_CFG_REG		0x300
+
+#define IO_BIAS_MASK		GENMASK(3, 0)
+
+#define SUN4I_FUNC_INPUT	0
+#define SUN4I_FUNC_IRQ		6
+
+#define PINCTRL_SUN5I_A10S	BIT(1)
+#define PINCTRL_SUN5I_A13	BIT(2)
+#define PINCTRL_SUN5I_GR8	BIT(3)
+#define PINCTRL_SUN6I_A31	BIT(4)
+#define PINCTRL_SUN6I_A31S	BIT(5)
+#define PINCTRL_SUN4I_A10	BIT(6)
+#define PINCTRL_SUN7I_A20	BIT(7)
+#define PINCTRL_SUN8I_R40	BIT(8)
+#define PINCTRL_SUN8I_V3	BIT(9)
+#define PINCTRL_SUN8I_V3S	BIT(10)
+
+#define PIO_POW_MOD_SEL_REG	0x340
+
+enum sunxi_desc_bias_voltage {
+	BIAS_VOLTAGE_NONE,
+	/*
+	 * Bias voltage configuration is done through
+	 * Pn_GRP_CONFIG registers, as seen on A80 SoC.
+	 */
+	BIAS_VOLTAGE_GRP_CONFIG,
+	/*
+	 * Bias voltage is set through PIO_POW_MOD_SEL_REG
+	 * register, as seen on H6 SoC, for example.
+	 */
+	BIAS_VOLTAGE_PIO_POW_MODE_SEL,
+};
+
+struct sunxi_desc_function {
+	const char	*name;
+	u8		muxval;
+};
+
+struct sunxi_desc_pin {
+	struct {
+		const char		name[6];
+		u16			number;
+	} pin;
+	const struct sunxi_desc_function	*functions;
+};
+
+struct sunxi_pinctrl_desc {
+	const struct sunxi_desc_pin	*pins;
+	size_t				npins;
+	unsigned			pin_base;
+	bool				disable_strict_mode;
+	enum sunxi_desc_bias_voltage	io_bias_cfg_variant;
+};
+
+struct sunxi_pinctrl {
+	void __iomem			*base;
+	struct gpio_chip		chip;
+	struct pinctrl_device		pdev;
+	const struct sunxi_pinctrl_desc	*desc;
+};
+
+#define SUNXI_PIN(_pin, ...)					\
+	{							\
+		.pin = _pin,					\
+		.functions = (struct sunxi_desc_function[]){	\
+			__VA_ARGS__, { } },			\
+	}
+
+#define SUNXI_PINCTRL_PIN(bank, pin)				\
+	{							\
+		.name = "P" #bank #pin,				\
+		.number = P ## bank ## _BASE + (pin)		\
+	}
+
+#define SUNXI_FUNCTION(_val, _name)				\
+	{							\
+		.name = _name,					\
+		.muxval = _val,					\
+	}
+
+#define SUNXI_FUNCTION_IRQ_BANK(...)  {}
+
+/*
+ * The sunXi PIO registers are organized as is:
+ * 0x00 - 0x0c	Muxing values.
+ *		8 pins per register, each pin having a 4bits value
+ * 0x10		Pin values
+ *		32 bits per register, each pin corresponding to one bit
+ * 0x14 - 0x18	Drive level
+ *		16 pins per register, each pin having a 2bits value
+ * 0x1c - 0x20	Pull-Up values
+ *		16 pins per register, each pin having a 2bits value
+ *
+ * This is for the first bank. Each bank will have the same layout,
+ * with an offset being a multiple of 0x24.
+ *
+ * The following functions calculate from the pin number the register
+ * and the bit offset that we should access.
+ */
+static inline u32 sunxi_mux_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += MUX_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_mux_offset(u16 pin)
+{
+	u32 pin_num = pin % MUX_PINS_PER_REG;
+	return pin_num * MUX_PINS_BITS;
+}
+
+static inline u32 sunxi_data_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += DATA_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_data_offset(u16 pin)
+{
+	u32 pin_num = pin % DATA_PINS_PER_REG;
+	return pin_num * DATA_PINS_BITS;
+}
+
+static inline u32 sunxi_dlevel_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += DLEVEL_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_dlevel_offset(u16 pin)
+{
+	u32 pin_num = pin % DLEVEL_PINS_PER_REG;
+	return pin_num * DLEVEL_PINS_BITS;
+}
+
+static inline u32 sunxi_pull_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+	u32 offset = bank * BANK_MEM_SIZE;
+	offset += PULL_REGS_OFFSET;
+	offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04;
+	return round_down(offset, 4);
+}
+
+static inline u32 sunxi_pull_offset(u16 pin)
+{
+	u32 pin_num = pin % PULL_PINS_PER_REG;
+	return pin_num * PULL_PINS_BITS;
+}
+
+static inline u32 sunxi_grp_config_reg(u16 pin)
+{
+	u8 bank = pin / PINS_PER_BANK;
+
+	return GRP_CFG_REG + bank * 0x4;
+}
+
+int sunxi_pinctrl_probe(struct device *dev);
+
+#endif /* __PINCTRL_SUNXI_H */
-- 
2.48.1



From jmaselbas at zdiv.net  Wed Feb 12 02:48:40 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 12 Feb 2025 11:48:40 +0100
Subject: [PATCH v3 4/6] mci: Add sunxi-mmc driver
In-Reply-To: <20250212104842.504-1-jmaselbas@zdiv.net>
References: <20250212104842.504-1-jmaselbas@zdiv.net>
Message-ID: <20250212104842.504-5-jmaselbas@zdiv.net>

This driver is adapted from different sources: Linux, u-boot and p-boot.
The latter, p-boot (forked from u-boot), is a bootloader for pinephones.

It currently only support PIO xfer but could be further improved to also
support DMA xfer. This driver is split in three files so it can be used
by the PBL and barebox proper.

Signed-off-by: Jules Maselbas <jmaselbas at zdiv.net>
---
v1->v2:
 - removed the /2 on the clk source (this is in fact done by the clk source)
 - convert to gpiod (Ahmad)
v2->v3:
 - reduced all the timeouts to 1000ms max
 - make used of mci_cmd::busy_timeout (Ahmad)
 - removed a duplicated wait on card busy stat

 drivers/mci/Kconfig            |   6 +
 drivers/mci/Makefile           |   2 +
 drivers/mci/sunxi-mmc-common.c | 238 +++++++++++++++++++++++++++++++++
 drivers/mci/sunxi-mmc-pbl.c    |  81 +++++++++++
 drivers/mci/sunxi-mmc.c        | 176 ++++++++++++++++++++++++
 drivers/mci/sunxi-mmc.h        | 222 ++++++++++++++++++++++++++++++
 include/mach/sunxi/xload.h     |  12 ++
 7 files changed, 737 insertions(+)
 create mode 100644 drivers/mci/sunxi-mmc-common.c
 create mode 100644 drivers/mci/sunxi-mmc-pbl.c
 create mode 100644 drivers/mci/sunxi-mmc.c
 create mode 100644 drivers/mci/sunxi-mmc.h
 create mode 100644 include/mach/sunxi/xload.h

diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index f760614725..4641e9cdcd 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -92,6 +92,12 @@ config MCI_DW_PIO
 	help
 	  Use PIO mode (instead of IDMAC) in DW MMC driver.
 
+config MCI_SUNXI_SMHC
+	bool "Allwinner SD-MMC Memory Card Host Controller"
+	help
+	  Enable support for the Allwinner SD-MMC Memory Card Host Controller,
+	  this provides host support for SD and MMC interfaces, in PIO mode.
+
 config MCI_MXS
 	bool "i.MX23/i.MX28"
 	depends on ARCH_MXS
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index d8d7818a48..5e951d695f 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -22,4 +22,6 @@ obj-$(CONFIG_MCI_DW)		+= dw_mmc.o
 obj-$(CONFIG_MCI_DWC_MSHC)	+= dwcmshc-sdhci.o
 obj-$(CONFIG_MCI_MMCI)		+= mmci.o
 obj-$(CONFIG_MCI_STM32_SDMMC2)	+= stm32_sdmmc2.o
+obj-$(CONFIG_MCI_SUNXI_SMHC)	+= sunxi-mmc.o
+pbl-$(CONFIG_MCI_SUNXI_SMHC)	+= sunxi-mmc-pbl.o
 obj-pbl-$(CONFIG_MCI_SDHCI)	+= sdhci.o
diff --git a/drivers/mci/sunxi-mmc-common.c b/drivers/mci/sunxi-mmc-common.c
new file mode 100644
index 0000000000..4bca6c2e7f
--- /dev/null
+++ b/drivers/mci/sunxi-mmc-common.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2024 Jules Maselbas
+#include "sunxi-mmc.h"
+
+static int sdxc_read_data_pio(struct sunxi_mmc_host *host, struct mci_data *data)
+{
+	size_t i, len = (data->blocks * data->blocksize) / sizeof(u32);
+	u32 *dst = (u32 *)data->dest;
+
+	sdxc_writel(host, SDXC_REG_GCTRL, SDXC_GCTRL_ACCESS_BY_AHB);
+
+	for (i = 0; i < len; i++) {
+		if (wait_on_timeout(1000 * MSECOND, !sdxc_is_fifo_empty(host)))
+			return -ETIMEDOUT;
+		dst[i] = sdxc_readl(host, SDXC_REG_FIFO);
+	}
+
+	return 0;
+}
+
+static int sdxc_write_data_pio(struct sunxi_mmc_host *host, struct mci_data *data)
+{
+	size_t i, len = (data->blocks * data->blocksize) / sizeof(u32);
+	u32 *src = (u32 *)data->src;
+
+	sdxc_writel(host, SDXC_REG_GCTRL, SDXC_GCTRL_ACCESS_BY_AHB);
+
+	for (i = 0; i < len; i++) {
+		if (wait_on_timeout(1000 * MSECOND, !sdxc_is_fifo_full(host)))
+			return -ETIMEDOUT;
+		sdxc_writel(host, SDXC_REG_FIFO, src[i]);
+	}
+
+	return 0;
+}
+
+static int sunxi_mmc_send_cmd(struct sunxi_mmc_host *host, struct mci_cmd *cmd,
+			      struct mci_data *data, const char **why)
+{
+	const char *err_why = "";
+	u32 cmdval = SDXC_CMD_START;
+	uint64_t busy_timeout = 1000 * MSECOND;
+	int ret;
+
+	if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY))
+		return -EINVAL;
+
+	if (cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION)
+		return 0; /* using ACMD12 */
+	if (cmd->cmdidx == MMC_CMD_GO_IDLE_STATE)
+		cmdval |= SDXC_CMD_SEND_INIT_SEQ;
+
+	if (cmd->resp_type & MMC_RSP_PRESENT)
+		cmdval |= SDXC_CMD_RESP_EXPIRE;
+	if (cmd->resp_type & MMC_RSP_136)
+		cmdval |= SDXC_CMD_LONG_RESPONSE;
+	if (cmd->resp_type & MMC_RSP_CRC)
+		cmdval |= SDXC_CMD_CHK_RESPONSE_CRC;
+
+	if (cmd->busy_timeout > 0)
+		busy_timeout = cmd->busy_timeout * MSECOND;
+
+	/* clear interrupts */
+	sdxc_writel(host, SDXC_REG_RINTR, 0xffffffff);
+
+	if (data) {
+		u32 blksiz = data->blocksize;
+		u32 bytcnt = data->blocks * data->blocksize;
+
+		cmdval |= SDXC_CMD_DATA_EXPIRE;
+		cmdval |= SDXC_CMD_WAIT_PRE_OVER;
+		if (data->flags & MMC_DATA_WRITE)
+			cmdval |= SDXC_CMD_WRITE;
+		if (data->blocks > 1)
+			cmdval |= SDXC_CMD_AUTO_STOP;
+
+		sdxc_writel(host, SDXC_REG_TMOUT, 0xFFFFFF40);
+		sdxc_writel(host, SDXC_REG_BLKSZ, blksiz);
+		sdxc_writel(host, SDXC_REG_BCNTR, bytcnt);
+	}
+
+	sdxc_writel(host, SDXC_REG_CARG, cmd->cmdarg);
+	sdxc_writel(host, SDXC_REG_CMDR, cmdval | cmd->cmdidx);
+	if (data) {
+		if (data->flags & MMC_DATA_WRITE)
+			ret = sdxc_write_data_pio(host, data);
+		else
+			ret = sdxc_read_data_pio(host, data);
+		if (ret < 0) {
+			err_why = "pio error";
+			goto err;
+		}
+	}
+
+	ret = sdxc_xfer_complete(host, 1000 * MSECOND, SDXC_INT_COMMAND_DONE);
+	if (ret) {
+		err_why = "cmd timeout";
+		goto err;
+	}
+
+	if (data) {
+		ret = sdxc_xfer_complete(host, 1000 * MSECOND, data->blocks > 1 ?
+					 SDXC_INT_AUTO_COMMAND_DONE :
+					 SDXC_INT_DATA_OVER);
+		if (ret) {
+			err_why = "data timeout";
+			goto err;
+		}
+	}
+
+	if (cmd->resp_type & MMC_RSP_BUSY) {
+		if (wait_on_timeout(busy_timeout, !sdxc_is_card_busy(host))) {
+			err_why = "card busy timeout";
+			ret = -ETIMEDOUT;
+			goto err;
+		}
+	}
+
+	if (cmd->resp_type & MMC_RSP_136) {
+		cmd->response[0] = sdxc_readl(host, SDXC_REG_RESP3);
+		cmd->response[1] = sdxc_readl(host, SDXC_REG_RESP2);
+		cmd->response[2] = sdxc_readl(host, SDXC_REG_RESP1);
+		cmd->response[3] = sdxc_readl(host, SDXC_REG_RESP0);
+	} else if (cmd->resp_type & MMC_RSP_PRESENT) {
+		cmd->response[0] = sdxc_readl(host, SDXC_REG_RESP0);
+	}
+
+err:
+	if (why)
+		*why = err_why;
+	sdxc_writel(host, SDXC_REG_GCTRL, SDXC_GCTRL_FIFO_RESET);
+	return ret;
+}
+
+static int sunxi_mmc_update_clk(struct sunxi_mmc_host *host)
+{
+	u32 cmdval;
+
+	cmdval = SDXC_CMD_START |
+	         SDXC_CMD_UPCLK_ONLY |
+	         SDXC_CMD_WAIT_PRE_OVER;
+
+	sdxc_writel(host, SDXC_REG_CARG, 0);
+	sdxc_writel(host, SDXC_REG_CMDR, cmdval);
+
+	if (wait_on_timeout(1000 * MSECOND, !(sdxc_readl(host, SDXC_REG_CMDR) & SDXC_CMD_START)))
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int sunxi_mmc_setup_clk(struct sunxi_mmc_host *host, u32 freq)
+{
+	u32 val, div, sclk;
+	int ret;
+
+	sclk = host->clkrate;
+	if (sclk == 0)
+		return -EINVAL;
+
+	/* disable card clock */
+	val = sdxc_readl(host, SDXC_REG_CLKCR);
+	val &= ~(SDXC_CLK_ENABLE | SDXC_CLK_LOW_POWER_ON);
+	val |= SDXC_CLK_MASK_DATA0;
+	sdxc_writel(host, SDXC_REG_CLKCR, val);
+
+	ret = sunxi_mmc_update_clk(host);
+	if (ret)
+		return ret;
+
+	/*
+	 * Configure the controller to use the new timing mode if needed.
+	 * On controllers that only support the new timing mode, such as
+	 * the eMMC controller on the A64, this register does not exist,
+	 * and any writes to it are ignored.
+	 */
+	if (host->cfg->needs_new_timings) {
+		/* Don't touch the delay bits */
+		val = sdxc_readl(host, SDXC_REG_NTSR);
+		val |= SDXC_NTSR_2X_TIMING_MODE;
+		sdxc_writel(host, SDXC_REG_NTSR, val);
+	}
+
+	/* setup clock rate */
+	div = DIV_ROUND_UP(sclk, freq);
+	div /= 2; /* divisor is multiplied by 2 */
+	if (div > 255)
+		div = 255;
+
+	/* set internal divider */
+	val = sdxc_readl(host, SDXC_REG_CLKCR);
+	val &= ~SDXC_CLK_DIVIDER_MASK;
+	val |= div;
+	sdxc_writel(host, SDXC_REG_CLKCR, val);
+
+	/* enable card clock */
+	val = sdxc_readl(host, SDXC_REG_CLKCR);
+	val |= SDXC_CLK_ENABLE;
+	val &= ~SDXC_CLK_MASK_DATA0;
+	sdxc_writel(host, SDXC_REG_CLKCR, val);
+
+	return sunxi_mmc_update_clk(host);
+}
+
+static int sunxi_mmc_set_ios(struct sunxi_mmc_host *host, struct mci_ios *ios)
+{
+	int ret = 0;
+	u32 width;
+
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_8:
+		width = SDXC_WIDTH_8BIT;
+		break;
+	case MMC_BUS_WIDTH_4:
+		width = SDXC_WIDTH_4BIT;
+		break;
+	default:
+		width = SDXC_WIDTH_1BIT;
+		break;
+	}
+	sdxc_writel(host, SDXC_REG_WIDTH, width);
+
+	if (ios->clock)
+		ret = sunxi_mmc_setup_clk(host, ios->clock);
+	return ret;
+}
+
+static void sunxi_mmc_init(struct sunxi_mmc_host *host)
+{
+	/* Reset controller */
+	sdxc_writel(host, SDXC_REG_GCTRL, SDXC_GCTRL_RESET);
+	udelay(1000);
+
+	sdxc_writel(host, SDXC_REG_RINTR, 0xffffffff);
+	sdxc_writel(host, SDXC_REG_IMASK, 0);
+
+	sdxc_writel(host, SDXC_REG_TMOUT, 0xffffff40);
+}
diff --git a/drivers/mci/sunxi-mmc-pbl.c b/drivers/mci/sunxi-mmc-pbl.c
new file mode 100644
index 0000000000..09044bb2df
--- /dev/null
+++ b/drivers/mci/sunxi-mmc-pbl.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2024 Jules Maselbas
+#include <common.h>
+
+#include <mach/sunxi/xload.h>
+#include "sunxi-mmc.h"
+#include "sunxi-mmc-common.c"
+
+#define SECTOR_SIZE			512
+#define SUPPORT_MAX_BLOCKS		16U
+
+static int sunxi_mmc_read_block(struct sunxi_mmc_host *host,
+				void *dst, unsigned int blocknum,
+				unsigned int blocks)
+{
+	struct mci_data data;
+	struct mci_cmd cmd = {
+		.cmdidx = (blocks > 1) ? MMC_CMD_READ_MULTIPLE_BLOCK : MMC_CMD_READ_SINGLE_BLOCK,
+		 /* mci->high_capacity ? blocknum : blocknum * mci->read_bl_len, */
+		 /* TODO: detect if card is high-capacity */
+		.cmdarg = blocknum,
+		.resp_type = MMC_RSP_R1,
+	};
+	int ret;
+
+	data.dest = dst;
+	data.blocks = blocks;
+	data.blocksize = SECTOR_SIZE; /* compat with MMC/SD */
+	data.flags = MMC_DATA_READ;
+
+	ret = sunxi_mmc_send_cmd(host, &cmd, &data, NULL);
+
+	if (ret || blocks > 1) {
+		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
+		cmd.cmdarg = 0;
+		cmd.resp_type = MMC_RSP_R1b;
+		sunxi_mmc_send_cmd(host, &cmd, NULL, NULL);
+	}
+
+	return ret;
+}
+
+static int sunxi_mmc_bio_read(struct pbl_bio *bio, off_t start,
+				void *buf, unsigned int nblocks)
+{
+	struct sunxi_mmc_host *host = bio->priv;
+	unsigned int count = 0;
+	unsigned int block_len = SECTOR_SIZE;
+	int ret;
+
+	while (count < nblocks) {
+		unsigned int n = min_t(unsigned int, nblocks - count, SUPPORT_MAX_BLOCKS);
+
+		ret = sunxi_mmc_read_block(host, buf, start, n);
+		if (ret < 0)
+			return ret;
+
+		count += n;
+		start += n;
+		buf += n * block_len;
+	}
+
+	return count;
+}
+
+int sunxi_mmc_bio_init(struct pbl_bio *bio, void __iomem *base,
+		       unsigned int clock, unsigned int slot)
+{
+	static struct sunxi_mmc_host host;
+	struct mci_ios ios = { .bus_width = MMC_BUS_WIDTH_4, .clock = 400000 };
+
+	host.base = base;
+	host.clkrate = clock;
+	bio->priv = &host;
+	bio->read = sunxi_mmc_bio_read;
+
+	sunxi_mmc_init(&host);
+	sunxi_mmc_set_ios(&host, &ios);
+
+	return 0;
+}
diff --git a/drivers/mci/sunxi-mmc.c b/drivers/mci/sunxi-mmc.c
new file mode 100644
index 0000000000..a19abbe55d
--- /dev/null
+++ b/drivers/mci/sunxi-mmc.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2024 Jules Maselbas
+// derived from: linux/drivers/mmc/host/sunxi-mmc.c
+#define pr_fmt(fmt) "sunxi-mmc: " fmt
+
+#include <common.h>
+#include <driver.h>
+#include <malloc.h>
+#include <init.h>
+#include <mci.h>
+
+#include <gpio.h>
+#include <of_gpio.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <errno.h>
+#include <dma.h>
+
+#include "sunxi-mmc.h"
+#include "sunxi-mmc-common.c"
+
+static int sdxc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
+{
+	struct sunxi_mmc_host *host = to_sunxi_mmc_host(mci);
+	struct device *dev = mci->hw_dev;
+	const char *why;
+	int ret;
+
+	ret = sunxi_mmc_send_cmd(host, cmd, data, &why);
+	if (ret && ret != -ETIMEDOUT)
+		dev_err(dev, "error %s CMD%d (%d)\n", why, cmd->cmdidx, ret);
+	if (ret == -ETIMEDOUT)
+		mdelay(1);
+
+	return ret;
+}
+
+static void sdxc_set_ios(struct mci_host *mci, struct mci_ios *ios)
+{
+	struct sunxi_mmc_host *host = to_sunxi_mmc_host(mci);
+	struct device *dev = mci->hw_dev;
+
+	dev_dbg(dev, "buswidth: %d clock: %d\n", 1 << ios->bus_width, ios->clock);
+	sunxi_mmc_set_ios(host, ios);
+}
+
+static int sdxc_card_present(struct mci_host *mci)
+{
+	struct sunxi_mmc_host *host = to_sunxi_mmc_host(mci);
+
+	/* No gpio, assume card is present */
+	if (IS_ERR_OR_NULL(host->gpio_cd))
+		return 1;
+
+	return gpiod_get_value(host->gpio_cd);
+}
+
+static int sdxc_init(struct mci_host *mci, struct device *dev)
+{
+	struct sunxi_mmc_host *host = to_sunxi_mmc_host(mci);
+
+	sunxi_mmc_init(host);
+
+	return 0;
+}
+
+static const struct mci_ops sdxc_mmc_ops = {
+	.send_cmd = sdxc_send_cmd,
+	.set_ios = sdxc_set_ios,
+	.init = sdxc_init,
+	.card_present = sdxc_card_present,
+};
+
+static int sunxi_mmc_probe(struct device *dev)
+{
+	struct resource *iores;
+	struct sunxi_mmc_host *host;
+	unsigned int f_min, f_max;
+	int ret;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+	host = xzalloc(sizeof(*host));
+	host->base = IOMEM(iores->start);
+	dma_set_mask(dev, DMA_BIT_MASK(32));
+	host->cfg = device_get_match_data(dev);
+
+	host->gpio_cd = gpiod_get_optional(dev, "cd", GPIOD_IN);
+
+	host->clk_ahb = clk_get(dev, "ahb");
+	if (IS_ERR(host->clk_ahb)) {
+		ret = PTR_ERR(host->clk_ahb);
+		goto err;
+	}
+
+	host->clk_mmc = clk_get(dev, "mmc");
+	if (IS_ERR(host->clk_mmc)) {
+		ret = PTR_ERR(host->clk_mmc);
+		goto err;
+	}
+
+	clk_enable(host->clk_ahb);
+	clk_enable(host->clk_mmc);
+
+	host->mci.hw_dev = dev;
+	host->mci.ops = sdxc_mmc_ops;
+	host->mci.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+	host->mci.host_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA
+		| MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED
+		| MMC_CAP_MMC_HIGHSPEED_52MHZ;
+
+	host->clkrate = clk_get_rate(host->clk_mmc);
+	f_min = host->clkrate / 510;
+	f_max = host->clkrate;
+	/* clock must at least support freq as low as 400K, and reach 52M */
+	if (400000 < f_min || f_max < 52000000) {
+		/* if not, try to get a better clock, clk_set_rate never sets
+		 * a frequence above the requested one, thus we try to set a
+		 * clk rate close or below 2 * 52MHz (260 * 400KHz).
+		 */
+		clk_set_rate(host->clk_mmc, 260 * 400000);
+		host->clkrate = clk_get_rate(host->clk_mmc);
+		f_min = host->clkrate / 510;
+		f_max = host->clkrate;
+	}
+	dev_dbg(dev, "freq: min %d max %d\n", f_min, f_max);
+	mci_of_parse(&host->mci);
+	host->mci.host_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA
+		| MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED
+		| MMC_CAP_MMC_HIGHSPEED_52MHZ;
+
+	f_min = max_t(unsigned int,   400000, f_min);
+	f_max = min_t(unsigned int, 52000000, f_max);
+	host->mci.f_min = max_t(unsigned int, host->mci.f_min, f_min);
+	host->mci.f_max = min_t(unsigned int, host->mci.f_max, f_max);
+
+	return mci_register(&host->mci);
+err:
+	if (host->clk_mmc)
+		clk_put(host->clk_mmc);
+	if (host->clk_ahb)
+		clk_put(host->clk_ahb);
+	free(host);
+	release_region(iores);
+	return ret;
+}
+
+static const struct sunxi_mmc_cfg sun50i_a64_cfg = {
+	.idma_des_size_bits = 16,
+	.clk_delays = NULL,
+	.can_calibrate = true,
+	.mask_data0 = true,
+	.needs_new_timings = true,
+};
+
+static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
+	.idma_des_size_bits = 13,
+	.clk_delays = NULL,
+	.can_calibrate = true,
+	.needs_new_timings = true,
+};
+
+static const struct of_device_id sunxi_mmc_compatible[] = {
+	{ .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },
+	{ .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg },
+	{ /* sentinel */ }
+};
+
+static struct driver sunxi_mmc_driver = {
+	.name  = "sunxi-mmc",
+	.probe = sunxi_mmc_probe,
+	.of_compatible = DRV_OF_COMPAT(sunxi_mmc_compatible),
+};
+device_platform_driver(sunxi_mmc_driver);
diff --git a/drivers/mci/sunxi-mmc.h b/drivers/mci/sunxi-mmc.h
new file mode 100644
index 0000000000..0668aaf334
--- /dev/null
+++ b/drivers/mci/sunxi-mmc.h
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2024 Jules Maselbas */
+/* derived from: linux/drivers/mmc/host/sunxi-mmc.c */
+
+#ifndef SUNXI_MMC_H
+#define SUNXI_MMC_H
+
+#include <io.h>
+#include <linux/bitops.h>
+#include <linux/gpio/consumer.h>
+#include <clock.h>
+#include <mci.h>
+
+#define SDXC_REG_GCTRL	(0x00) /* Global Control */
+#define SDXC_REG_CLKCR	(0x04) /* Clock Control */
+#define SDXC_REG_TMOUT	(0x08) /* Time Out */
+#define SDXC_REG_WIDTH	(0x0C) /* Bus Width */
+#define SDXC_REG_BLKSZ	(0x10) /* Block Size */
+#define SDXC_REG_BCNTR	(0x14) /* Byte Count */
+#define SDXC_REG_CMDR	(0x18) /* Command */
+#define SDXC_REG_CARG	(0x1C) /* Argument */
+#define SDXC_REG_RESP0	(0x20) /* Response 0 */
+#define SDXC_REG_RESP1	(0x24) /* Response 1 */
+#define SDXC_REG_RESP2	(0x28) /* Response 2 */
+#define SDXC_REG_RESP3	(0x2C) /* Response 3 */
+#define SDXC_REG_IMASK	(0x30) /* Interrupt Mask */
+#define SDXC_REG_MISTA	(0x34) /* Masked Interrupt Status */
+#define SDXC_REG_RINTR	(0x38) /* Raw Interrupt Status */
+#define SDXC_REG_STAS	(0x3C) /* Status */
+#define SDXC_REG_FTRGL	(0x40) /* FIFO Threshold Watermark */
+#define SDXC_REG_FUNS	(0x44) /* Function Select */
+#define SDXC_REG_CBCR	(0x48) /* CIU Byte Count */
+#define SDXC_REG_BBCR	(0x4C) /* BIU Byte Count */
+#define SDXC_REG_DBGC	(0x50) /* Debug Enable */
+#define SDXC_REG_A12A	(0x58) /* Auto Command 12 Argument */
+#define SDXC_REG_NTSR	(0x5C) /* SMC New Timing Set Register */
+#define SDXC_REG_HWRST	(0x78) /* Card Hardware Reset */
+#define SDXC_REG_DMAC	(0x80) /* IDMAC Control */
+#define SDXC_REG_DLBA	(0x84) /* IDMAC Descriptor List Base Addresse */
+#define SDXC_REG_IDST	(0x88) /* IDMAC Status */
+#define SDXC_REG_IDIE	(0x8C) /* IDMAC Interrupt Enable */
+#define SDXC_REG_CHDA	(0x90)
+#define SDXC_REG_CBDA	(0x94)
+
+#define SDXC_REG_DRV_DL		0x140 /* Drive Delay Control Register */
+#define SDXC_REG_SAMP_DL_REG	0x144 /* SMC sample delay control */
+#define SDXC_REG_DS_DL_REG	0x148 /* SMC data strobe delay control */
+
+#define SDXC_REG_FIFO	(0x200) /* FIFO */
+
+#define SDXC_GCTRL_SOFT_RESET		BIT(0)
+#define SDXC_GCTRL_FIFO_RESET		BIT(1)
+#define SDXC_GCTRL_DMA_RESET		BIT(2)
+#define SDXC_GCTRL_RESET \
+	(SDXC_GCTRL_SOFT_RESET | SDXC_GCTRL_FIFO_RESET | SDXC_GCTRL_DMA_RESET)
+#define SDXC_GCTRL_DMA_ENABLE		BIT(5)
+#define SDXC_GCTRL_ACCESS_BY_AHB	BIT(31)
+
+#define SDXC_CMD_RESP_EXPIRE		BIT(6)
+#define SDXC_CMD_LONG_RESPONSE		BIT(7)
+#define SDXC_CMD_CHK_RESPONSE_CRC	BIT(8)
+#define SDXC_CMD_DATA_EXPIRE		BIT(9)
+#define SDXC_CMD_WRITE			BIT(10)
+#define SDXC_CMD_AUTO_STOP		BIT(12)
+#define SDXC_CMD_WAIT_PRE_OVER		BIT(13)
+#define SDXC_CMD_ABORT_STOP		BIT(14)
+#define SDXC_CMD_SEND_INIT_SEQ		BIT(15)
+#define SDXC_CMD_UPCLK_ONLY		BIT(21)
+#define SDXC_CMD_START			BIT(31)
+
+#define SDXC_NTSR_2X_TIMING_MODE	BIT(31)
+
+/* clock control bits */
+#define SDXC_CLK_MASK_DATA0	BIT(31)
+#define SDXC_CLK_LOW_POWER_ON	BIT(17)
+#define SDXC_CLK_ENABLE		BIT(16)
+#define SDXC_CLK_DIVIDER_MASK	(0xff)
+
+/* bus width */
+#define SDXC_WIDTH_1BIT	0
+#define SDXC_WIDTH_4BIT	BIT(0)
+#define SDXC_WIDTH_8BIT	BIT(1)
+
+/* interrupt bits */
+#define SDXC_INT_RESP_ERROR		BIT(1)
+#define SDXC_INT_COMMAND_DONE		BIT(2)
+#define SDXC_INT_DATA_OVER		BIT(3)
+#define SDXC_INT_TX_DATA_REQUEST	BIT(4)
+#define SDXC_INT_RX_DATA_REQUEST	BIT(5)
+#define SDXC_INT_RESP_CRC_ERROR		BIT(6)
+#define SDXC_INT_DATA_CRC_ERROR		BIT(7)
+#define SDXC_INT_RESP_TIMEOUT		BIT(8)
+#define SDXC_INT_DATA_TIMEOUT		BIT(9)
+#define SDXC_INT_VOLTAGE_CHANGE_DONE	BIT(10)
+#define SDXC_INT_FIFO_RUN_ERROR		BIT(11)
+#define SDXC_INT_HARD_WARE_LOCKED	BIT(12)
+#define SDXC_INT_START_BIT_ERROR	BIT(13)
+#define SDXC_INT_AUTO_COMMAND_DONE	BIT(14)
+#define SDXC_INT_END_BIT_ERROR		BIT(15)
+#define SDXC_INT_SDIO_INTERRUPT		BIT(16)
+#define SDXC_INT_CARD_INSERT		BIT(30)
+#define SDXC_INT_CARD_REMOVE		BIT(31)
+#define SDXC_INTERRUPT_ERROR_BIT	\
+	(SDXC_INT_RESP_ERROR |		\
+	 SDXC_INT_RESP_CRC_ERROR |	\
+	 SDXC_INT_DATA_CRC_ERROR |	\
+	 SDXC_INT_RESP_TIMEOUT |	\
+	 SDXC_INT_DATA_TIMEOUT |	\
+	 SDXC_INT_HARD_WARE_LOCKED |	\
+	 SDXC_INT_START_BIT_ERROR |	\
+	 SDXC_INT_END_BIT_ERROR)
+
+#define SDXC_INTERRUPT_DONE_BIT		\
+	(SDXC_INT_AUTO_COMMAND_DONE |	\
+	 SDXC_INT_DATA_OVER |		\
+	 SDXC_INT_COMMAND_DONE |	\
+	 SDXC_INT_VOLTAGE_CHANGE_DONE)
+
+/* status */
+#define SDXC_STATUS_FIFO_EMPTY		BIT(2)
+#define SDXC_STATUS_FIFO_FULL		BIT(3)
+#define SDXC_STATUS_CARD_PRESENT	BIT(8)
+#define SDXC_STATUS_BUSY		BIT(9)
+
+struct sunxi_mmc_clk_delay {
+	u32 output;
+	u32 sample;
+};
+
+struct sunxi_mmc_cfg {
+	u32 idma_des_size_bits;
+	u32 idma_des_shift;
+	const struct sunxi_mmc_clk_delay *clk_delays;
+
+	/* does the IP block support autocalibration? */
+	bool can_calibrate;
+
+	/* Does DATA0 needs to be masked while the clock is updated */
+	bool mask_data0;
+
+	/*
+	 * hardware only supports new timing mode, either due to lack of
+	 * a mode switch in the clock controller, or the mmc controller
+	 * is permanently configured in the new timing mode, without the
+	 * NTSR mode switch.
+	 */
+	bool needs_new_timings;
+
+	/* clock hardware can switch between old and new timing modes */
+	bool ccu_has_timings_switch;
+};
+
+struct sunxi_mmc_host {
+	struct mci_host mci;
+	struct device *dev;
+	struct clk *clk_ahb, *clk_mmc;
+	void __iomem *base;
+	struct gpio_desc *gpio_cd;
+
+	const struct sunxi_mmc_cfg *cfg;
+	u32 clkrate;
+};
+
+static inline struct sunxi_mmc_host *to_sunxi_mmc_host(struct mci_host *mci)
+{
+	return container_of(mci, struct sunxi_mmc_host, mci);
+}
+
+static inline u32 sdxc_readl(struct sunxi_mmc_host *host, u32 reg)
+{
+	return readl(host->base + reg);
+}
+
+static inline void sdxc_writel(struct sunxi_mmc_host *host, u32 reg, u32 val)
+{
+	writel(val, host->base + reg);
+}
+
+static inline int sdxc_is_fifo_empty(struct sunxi_mmc_host *host)
+{
+	return sdxc_readl(host, SDXC_REG_STAS) & SDXC_STATUS_FIFO_EMPTY;
+}
+
+static inline int sdxc_is_fifo_full(struct sunxi_mmc_host *host)
+{
+	return sdxc_readl(host, SDXC_REG_STAS) & SDXC_STATUS_FIFO_FULL;
+}
+
+static inline int sdxc_is_card_busy(struct sunxi_mmc_host *host)
+{
+	return sdxc_readl(host, SDXC_REG_STAS) & SDXC_STATUS_BUSY;
+}
+
+#ifdef __PBL__
+/*
+ * Stubs to make timeout logic below work in PBL
+ */
+#define get_time_ns()		0
+/*
+ * Use time in us as a busy counter timeout value
+ */
+#define is_timeout(s, t)	((s)++ > ((t) / 1000))
+#endif
+
+static inline int sdxc_xfer_complete(struct sunxi_mmc_host *host, u64 timeout, u32 flags)
+{
+	u64 start;
+	u32 rint;
+
+	start = get_time_ns();
+	do {
+		rint = sdxc_readl(host, SDXC_REG_RINTR);
+		if (rint & SDXC_INTERRUPT_ERROR_BIT)
+			break;
+		if (rint & flags)
+			return 0;
+	} while (!is_timeout(start, timeout));
+
+	return -ETIMEDOUT;
+}
+
+#endif
diff --git a/include/mach/sunxi/xload.h b/include/mach/sunxi/xload.h
new file mode 100644
index 0000000000..f978db4951
--- /dev/null
+++ b/include/mach/sunxi/xload.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __MACH_XLOAD_H
+#define __MACH_XLOAD_H
+
+#include <linux/compiler.h>
+#include <pbl/bio.h>
+
+int sunxi_mmc_bio_init(struct pbl_bio *bio, void __iomem *base,
+		       unsigned int clock, unsigned int slot);
+
+#endif
-- 
2.48.1



From jmaselbas at zdiv.net  Wed Feb 12 02:48:41 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 12 Feb 2025 11:48:41 +0100
Subject: [PATCH v3 5/6] ARM: sunxi: Introduce mach-sunxi
In-Reply-To: <20250212104842.504-1-jmaselbas@zdiv.net>
References: <20250212104842.504-1-jmaselbas@zdiv.net>
Message-ID: <20250212104842.504-6-jmaselbas@zdiv.net>

Add some boilerplate, Makefiles, Kbuild.
A generic barebox-dt-2nd.img image can be build for A64 SoC using
the multi_v8_defconfig.

This image can be booted from u-boot and has been tested on Pine64+,
it should work on other A64 SoC such as the pinephone, and other Pine64
boards, it might also work on H6 SoC which uses the same sd/mmc controler.

Signed-off-by: Jules Maselbas <jmaselbas at zdiv.net>
---
v1->v2:
 - removed RELOCATABLE and HAVE_PBL_MULTI_IMAGES from Kconfig (Ahmad)
 - used __dummy__.o insead of an empty file (Ahmad)
 - removed include/mach/sunxi/barebox-arm.h (Ahmad)
v2->v3:
 - add arch sun50i-a64 + mci driver to the multi_v8_defconfig (Sascha)
 - remove the sunxi_v8_defconfig

 arch/arm/Kconfig                    | 12 ++++++++++++
 arch/arm/Makefile                   |  1 +
 arch/arm/configs/multi_v8_defconfig |  2 ++
 arch/arm/mach-sunxi/Kconfig         | 13 +++++++++++++
 arch/arm/mach-sunxi/Makefile        |  1 +
 5 files changed, 29 insertions(+)
 create mode 100644 arch/arm/mach-sunxi/Kconfig
 create mode 100644 arch/arm/mach-sunxi/Makefile

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2e52ed7b50..3d8f2eeca7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -173,6 +173,17 @@ config ARCH_K3
 	select COMMON_CLK_OF_PROVIDER
 	select PM_GENERIC_DOMAINS
 
+config ARCH_SUNXI
+	bool "Allwinner (sunxi) SoCs"
+	depends on ARCH_MULTIARCH
+	select CLKDEV_LOOKUP
+	select COMMON_CLK
+	select COMMON_CLK_OF_PROVIDER
+	select GPIOLIB
+	select OFDEVICE
+	select OFTREE
+	select PINCTRL
+
 config ARCH_LAYERSCAPE
 	bool "NXP Layerscape based"
 	depends on ARCH_MULTIARCH
@@ -259,6 +270,7 @@ source "arch/arm/mach-omap/Kconfig"
 source "arch/arm/mach-pxa/Kconfig"
 source "arch/arm/mach-rockchip/Kconfig"
 source "arch/arm/mach-socfpga/Kconfig"
+source "arch/arm/mach-sunxi/Kconfig"
 source "arch/arm/mach-stm32mp/Kconfig"
 source "arch/arm/mach-versatile/Kconfig"
 source "arch/arm/mach-vexpress/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 270f5dfdc1..e4041cf715 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -102,6 +102,7 @@ machine-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip
 machine-$(CONFIG_ARCH_SAMSUNG)		+= samsung
 machine-$(CONFIG_ARCH_SOCFPGA)		+= socfpga
 machine-$(CONFIG_ARCH_STM32MP)		+= stm32mp
+machine-$(CONFIG_ARCH_SUNXI)		+= sunxi
 machine-$(CONFIG_ARCH_VERSATILE)	+= versatile
 machine-$(CONFIG_ARCH_VEXPRESS)		+= vexpress
 machine-$(CONFIG_ARCH_TEGRA)		+= tegra
diff --git a/arch/arm/configs/multi_v8_defconfig b/arch/arm/configs/multi_v8_defconfig
index 20bd0575f5..b1e66e85f4 100644
--- a/arch/arm/configs/multi_v8_defconfig
+++ b/arch/arm/configs/multi_v8_defconfig
@@ -3,6 +3,7 @@ CONFIG_ARCH_IMX=y
 CONFIG_ARCH_K3=y
 CONFIG_ARCH_LAYERSCAPE=y
 CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ARCH_SUN50I_A64=y
 CONFIG_ARCH_ZYNQMP=y
 CONFIG_MACH_KOENIGBAUER_ALPHAJET=y
 CONFIG_MACH_INNOCOMM_WB15=y
@@ -207,6 +208,7 @@ CONFIG_MCI=y
 CONFIG_MCI_MMC_BOOT_PARTITIONS=y
 CONFIG_MCI_DW=y
 CONFIG_MCI_ROCKCHIP_DWCMSHC=y
+CONFIG_MCI_SUNXI_SMHC=y
 CONFIG_MCI_IMX_ESDHC=y
 CONFIG_MCI_ARASAN=y
 CONFIG_COMMON_CLK_SCMI=y
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
new file mode 100644
index 0000000000..4fdd0877bf
--- /dev/null
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -0,0 +1,13 @@
+menu "Allwinner (sunxi) boards"
+        depends on ARCH_SUNXI
+
+config ARCH_SUN50I_A64
+	bool "Allwinner A64 SoC"
+	select CPU_V8
+	select CPU_SUPPORTS_64BIT_KERNEL
+	select CLOCKSOURCE_ARM_ARCHITECTED_TIMER
+	select PINCTRL_SUN50I_A64
+	depends on 64BIT
+	default y
+
+endmenu
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
new file mode 100644
index 0000000000..16a218658a
--- /dev/null
+++ b/arch/arm/mach-sunxi/Makefile
@@ -0,0 +1 @@
+obj- := __dummy__.o
-- 
2.48.1



From jmaselbas at zdiv.net  Wed Feb 12 02:48:42 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 12 Feb 2025 11:48:42 +0100
Subject: [PATCH v3 6/6] Documentation: sunxi: Add some documentation
In-Reply-To: <20250212104842.504-1-jmaselbas@zdiv.net>
References: <20250212104842.504-1-jmaselbas@zdiv.net>
Message-ID: <20250212104842.504-7-jmaselbas@zdiv.net>

Add some user documentation on how to build a second stage barebox image,
and how to boot from u-boot.

Signed-off-by: Jules Maselbas <jmaselbas at zdiv.net>
---
 Documentation/boards/sunxi.rst | 116 +++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 Documentation/boards/sunxi.rst

diff --git a/Documentation/boards/sunxi.rst b/Documentation/boards/sunxi.rst
new file mode 100644
index 0000000000..8d00507434
--- /dev/null
+++ b/Documentation/boards/sunxi.rst
@@ -0,0 +1,116 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Allwinner sunxi
+===============
+
+Boot process
+------------
+
+On power-up Allwinner SoC starts in boot ROM, aka BROM, which will search
+for a bootable image (eGON header): first from the SD card, then from eMMC.
+If no image is found then the boot ROM will enter into FEL mode that can be
+used for programming and recovery through USB.
+
+Some board may have a button to enter FEL mode at startup. If not, another
+way to enter FEL mode is to not have a valid bootable eGON image, this can
+be achieved by erasing existing eGON image headers.
+
+.. note::
+
+   Currently Barebox cannot boot directly on Allwinner sunxi SoC and can
+   only be used as a secondary bootloader, requiring u-boot to initialize
+   the SDRAM controller and starting the TF-A and optionally Crust.
+
+
+Building barebox second stage
+-----------------------------
+
+The generic ``barebox-dt-2nd.img`` armv8 image should enable all the needed
+drivers.
+
+To build the image do:
+
+.. code-block:: sh
+
+  export ARCH=arm CROSS_COMPILE=aarch64-linux-gnu-
+  make multi_v8_defconfig
+  make
+
+Installing barebox second stage
+-------------------------------
+
+Copy the built ``barebox-dt-2nd.img`` image into the first fat partition
+of the boot medium.
+
+.. code-block:: sh
+
+  # mount /dev/sdX1 /mnt/${mount_dir}
+  # cp ${build_dir}/images/barebox-dt-2nd.img /mnt/${mount_dir}
+  # umount /mnt/${mount_dir}
+
+
+Booting barebox from U-Boot
+---------------------------
+
+Currently Barebox can only be started as a second stage, and relies on
+U-Boot for the SDRAM initialisation and to start the TF-A.
+
+.. code-block:: console
+
+  # on u-boot console, `mmc 0:1` is the first partition on the sd card
+  fatload mmc 0:1 0x42000000 barebox-dt-2nd.img
+  fatload mmc 0:1 0x44000000 dtbs-lts/allwinner/sun50i-a64-pine64-plus.dtb
+  booti 0x42000000 - 0x44000000
+
+.. note::
+
+   A FIT image might be built and used instead of directly using the `barebox-dt-2nd.img`,
+   this hasn't been tested yet, but using a FIT image sound like a better option.
+
+See also the general documentation on :ref:`second_stage`.
+
+Building Arm Trusted Firmware (TF-A)
+------------------------------------
+
+.. note::
+
+   This step is currently only needed when building U-Boot.
+   This step is also documented in U-Boot documention.
+
+Boards using a 64-bit Soc (A64, H5, H6, H616, R329) require the BL31 stage of
+the Arm Trusted Firmware-A firmware. This provides the reference
+implementation of secure software for Armv8-A, offering PSCI and SMCCC
+services. Allwinner support is fully mainlined. To build bl31.bin:
+
+.. code-block:: sh
+
+  git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+  cd trusted-firmware-a
+  make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_a64 DEBUG=1
+  cp build/sun50i_a64/debug/bl31.bin ${barebox_dir}/firmware/sun50i-a64-bl31.bin
+
+The target platform (``PLAT=``) for A64 and H5 SoCs is sun50i_a64, for the H6
+sun50i_h6, for the H616 sun50i_h616, and for the R329 sun50i_r329.
+
+Building U-Boot image
+---------------------
+
+Please refere to the relevant U-Boot_ build documentation (or ``/doc/board/allwinner/sunxi.rst`` in u-boot src tree).
+
+.. _U-Boot: https://docs.u-boot.org/en/latest/board/allwinner/sunxi.html#building-the-u-boot-image
+
+
+Installing the first stage bootloader
+-------------------------------------
+
+Installing on a (micro-) SD card
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The bootable image, a eGON header followed by the actual image, must be
+located at the fixed offset of 8192 bytes (8KB) from the start of the
+disk (sector 16).
+
+.. code-block:: sh
+
+  # copy the bootable fsbl image (including eGON header) into disk sdX
+  dd if=${fsbl.img} of=/dev/sdX bs=512 seek=16
-- 
2.48.1



From jmaselbas at zdiv.net  Wed Feb 12 02:48:38 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 12 Feb 2025 11:48:38 +0100
Subject: [PATCH v3 2/6] clk: Add clock driver for sun50i-a64
In-Reply-To: <20250212104842.504-1-jmaselbas@zdiv.net>
References: <20250212104842.504-1-jmaselbas@zdiv.net>
Message-ID: <20250212104842.504-3-jmaselbas@zdiv.net>

Adds a "one size fit all" clock driver to be used for complex
"composite" clock, composed of: a gate, a mux and severals dividers.
This clk driver could be used to make SoC specific drivers easier
to port from linux sources, but this is not the case yet.

The pll-cpux is set to 816MHz and pll-periph0-2x is set to 1.2GHz.

Signed-off-by: Jules Maselbas <jmaselbas at zdiv.net>
---
v1->v2:
 - adds a new "one size fit all" clock driver
v2->v3:
 - add volatile on nop_delay counter (Ahmad)
 - removed trailing comma of clk_div_table div_apb1[] (Ahmad)

 drivers/clk/Makefile               |   1 +
 drivers/clk/sunxi/Makefile         |   3 +
 drivers/clk/sunxi/clk-sun50i-a64.c | 294 ++++++++++++++++++++++++
 drivers/clk/sunxi/clk-sun50i-a64.h |  62 +++++
 drivers/clk/sunxi/clk-sunxi.c      | 348 +++++++++++++++++++++++++++++
 drivers/clk/sunxi/clk-sunxi.h      |  79 +++++++
 6 files changed, 787 insertions(+)
 create mode 100644 drivers/clk/sunxi/Makefile
 create mode 100644 drivers/clk/sunxi/clk-sun50i-a64.c
 create mode 100644 drivers/clk/sunxi/clk-sun50i-a64.h
 create mode 100644 drivers/clk/sunxi/clk-sunxi.c
 create mode 100644 drivers/clk/sunxi/clk-sunxi.h

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 8c3544c750..4fda2c1e0d 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_ARCH_LAYERSCAPE)	+= clk-qoric.o
 obj-y				+= analogbits/
 obj-$(CONFIG_CLK_SIFIVE)	+= sifive/
 obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
+obj-$(CONFIG_ARCH_SUNXI)	+= sunxi/
 obj-$(CONFIG_COMMON_CLK_STM32F)		+= clk-stm32f4.o
 obj-$(CONFIG_MACH_RPI_COMMON)	+= clk-rpi.o
 obj-y				+= bcm/
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
new file mode 100644
index 0000000000..1c2214a2bc
--- /dev/null
+++ b/drivers/clk/sunxi/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y += clk-sunxi.o
+obj-$(CONFIG_ARCH_SUN50I_A64) += clk-sun50i-a64.o
diff --git a/drivers/clk/sunxi/clk-sun50i-a64.c b/drivers/clk/sunxi/clk-sun50i-a64.c
new file mode 100644
index 0000000000..864152fdf0
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun50i-a64.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: 2022 Jules Maselbas
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <io.h>
+#include <linux/clkdev.h>
+#include <linux/units.h>
+#include <linux/err.h>
+
+#include "clk-sunxi.h"
+
+#include "clk-sun50i-a64.h"
+
+#define CCU_PLL_CPUX		0x00
+#define CCU_PLL_PERIPH0		0x28
+#define CCU_CPUX_AXI_CFG	0x50
+
+static struct clk *clks[CLK_NUMBER];
+static struct clk_onecell_data clk_data = {
+	.clks = clks,
+	.clk_num = ARRAY_SIZE(clks),
+};
+
+static struct clk_div_table div_apb1[] = {
+	{ .val = 0, .div = 2 },
+	{ .val = 1, .div = 2 },
+	{ .val = 2, .div = 4 },
+	{ .val = 3, .div = 8 },
+	{ /* Sentinel */ }
+};
+
+static const char *sel_cpux[] = {
+	"osc32k",
+	"osc24M",
+	"pll-cpux",
+};
+
+static const char *sel_ahb1[] = {
+	"osc32k",
+	"osc24M",
+	"axi",
+	"pll-periph0",
+};
+
+static const char *sel_apb2[] = {
+	"osc32k",
+	"osc24M",
+	"pll-periph0-2x",
+	"pll-periph0-2x",
+};
+
+static const char *sel_ahb2[] = {
+	"ahb1",
+	"pll-periph0",
+};
+
+static const char *sel_mmc[] = {
+	"osc24M",
+	"pll-periph0-2x",
+	"pll-periph1-2x",
+};
+
+static void sun50i_a64_resets_init(void __iomem *regs)
+{
+	u32 rst;
+
+	rst = 0 |
+		/* RST_USB_PHY0 */ BIT(0) |
+		/* RST_USB_PHY1 */ BIT(1) |
+		/* RST_USB_HSIC */ BIT(2);
+	writel(rst, regs + 0x0cc);
+
+	rst = 0 |
+		/* RST_BUS_MIPI_DSI */ BIT(1) |
+		/* RST_BUS_CE   */ BIT(5) |
+		/* RST_BUS_DMA  */ BIT(6) |
+		/* RST_BUS_MMC0 */ BIT(8) |
+		/* RST_BUS_MMC1 */ BIT(9) |
+		/* RST_BUS_MMC2 */ BIT(10) |
+		/* RST_BUS_NAND */ BIT(13) |
+		/* RST_BUS_DRAM */ BIT(14) |
+		/* RST_BUS_EMAC */ BIT(17) |
+		/* RST_BUS_TS   */ BIT(18) |
+		/* RST_BUS_HSTIMER */ BIT(19) |
+		/* RST_BUS_SPI0  */ BIT(20) |
+		/* RST_BUS_SPI1  */ BIT(21) |
+		/* RST_BUS_OTG   */ BIT(23) |
+		/* RST_BUS_EHCI0 */ BIT(24) |
+		/* RST_BUS_EHCI1 */ BIT(25) |
+		/* RST_BUS_OHCI0 */ BIT(28) |
+		/* RST_BUS_OHCI1 */ BIT(29);
+	writel(rst, regs + 0x2c0);
+
+	rst = 0 |
+		/* RST_BUS_VE    */ BIT(0) |
+		/* RST_BUS_TCON0 */ BIT(3) |
+		/* RST_BUS_TCON1 */ BIT(4) |
+		/* RST_BUS_DEINTERLACE */ BIT(5) |
+		/* RST_BUS_CSI   */ BIT(8) |
+		/* RST_BUS_HDMI0 */ BIT(10) |
+		/* RST_BUS_HDMI1 */ BIT(11) |
+		/* RST_BUS_DE    */ BIT(12) |
+		/* RST_BUS_GPU   */ BIT(20) |
+		/* RST_BUS_MSGBOX   */ BIT(21) |
+		/* RST_BUS_SPINLOCK */ BIT(22) |
+		/* RST_BUS_DBG */ BIT(31);
+	writel(rst, regs + 0x2c4);
+
+	rst = /* RST_BUS_LVDS */ BIT(0);
+	writel(rst, regs + 0x2c8);
+
+	rst = 0 |
+		/* RST_BUS_CODEC */ BIT(0) |
+		/* RST_BUS_SPDIF */ BIT(1) |
+		/* RST_BUS_THS   */ BIT(8) |
+		/* RST_BUS_I2S0  */ BIT(12) |
+		/* RST_BUS_I2S1  */ BIT(13) |
+		/* RST_BUS_I2S2  */ BIT(14);
+	writel(rst, regs + 0x2d0);
+
+	rst = 0 |
+		/* RST_BUS_I2C0 */ BIT(0) |
+		/* RST_BUS_I2C1 */ BIT(1) |
+		/* RST_BUS_I2C2 */ BIT(2) |
+		/* RST_BUS_SCR  */ BIT(5) |
+		/* RST_BUS_UART0 */ BIT(16) |
+		/* RST_BUS_UART1 */ BIT(17) |
+		/* RST_BUS_UART2 */ BIT(18) |
+		/* RST_BUS_UART3 */ BIT(19) |
+		/* RST_BUS_UART4 */ BIT(20);
+	writel(rst, regs + 0x2d8);
+}
+
+static inline void sunxi_clk_set_pll(void __iomem *reg, u32 src, u32 freq)
+{
+	/* NOTE: using u32, max freq is 4GHz
+	 * out freq: src * N * K
+	 * factor N: [1->32]
+	 * factor K: [1->4]
+	 * from the manual: give priority to the choice of K >= 2
+	 */
+	u32 mul = freq / src; /* target multiplier (N * K) */
+	u32 k, n;
+	u32 cfg = BIT(31); /* ENABLE */
+
+	for (k = 4; k > 1; k--) {
+		if ((mul % k) == 0)
+			break;
+	}
+	n = mul / k;
+
+	cfg |= (k - 1) << 4;
+	cfg |= (n - 1) << 8;
+
+	writel(cfg, reg);
+
+	/* wait for pll lock */
+	while (!(readl(reg) & BIT(28)));
+}
+
+static void sun50i_a64_clocks_init(void __iomem *regs)
+{
+	/* switch cpu clock source to osc-24M */
+	writel(0x10000, regs + CCU_CPUX_AXI_CFG);
+	/* wait 8 cycles */
+	nop_delay(8);
+	/* set pll-cpux to 816MHz */
+	sunxi_clk_set_pll(regs + CCU_PLL_CPUX, 24 * HZ_PER_MHZ, 816 * HZ_PER_MHZ);
+	nop_delay(10000); /* HACK: ~1ms delay  */
+	/* switch cpu clock source to pll-cpux*/
+	writel( /* clk_src: 1=24Mhz 2=pll-cpux */ (2 << 16) |
+		/* apb_div: /2 */ (1 << 8) |
+		/* axi_div: /2 */ (1 << 0),
+		regs + CCU_CPUX_AXI_CFG);
+	/* wait 8 cycles */
+	nop_delay(8);
+
+	clks[CLK_PLL_CPUX] = clk_fixed("pll-cpux", 816 * HZ_PER_MHZ);
+	clks[CLK_CPUX] = sunxi_clk_mux("cpux", sel_cpux, ARRAY_SIZE(sel_cpux), regs + CCU_CPUX_AXI_CFG, 16, 2);
+
+	/* set pll-periph0-2x to 1.2GHz, as recommended */
+	sunxi_clk_set_pll(regs + CCU_PLL_PERIPH0, 24 * HZ_PER_MHZ, 1200 * HZ_PER_MHZ);
+
+	clks[CLK_PLL_PERIPH0_2X] = clk_fixed("pll-periph0-2x", 1200 * HZ_PER_MHZ);
+	clks[CLK_PLL_PERIPH0]    = clk_fixed_factor("pll-periph0", "pll-periph0-2x", 1, 2, 0);
+
+	clks[CLK_AXI] = sunxi_clk_div("axi", "cpux", regs + CCU_CPUX_AXI_CFG, 0, 2);
+
+	clks[CLK_AHB1] = sunxi_clk_mux("ahb1", sel_ahb1, ARRAY_SIZE(sel_ahb1), regs + 0x054, 12, 2);
+	clks[CLK_AHB2] = sunxi_clk_mux("ahb2", sel_ahb2, ARRAY_SIZE(sel_ahb2), regs + 0x05c, 0, 1);
+
+	clks[CLK_APB1] = sunxi_clk_div_table("apb1", "ahb1", div_apb1, regs + 0x054, 8, 2);
+	clks[CLK_APB2] = sunxi_clk_mux("apb2", sel_apb2, ARRAY_SIZE(sel_apb2), regs + 0x058, 24, 2);
+
+	clks[CLK_BUS_MIPI_DSI] = sunxi_clk_gate("bus-mipi-dsi", "ahb1", regs + 0x060, 1);
+	clks[CLK_BUS_CE]    = sunxi_clk_gate("bus-ce",    "ahb1", regs + 0x060, 5);
+	clks[CLK_BUS_DMA]   = sunxi_clk_gate("bus-dma",   "ahb1", regs + 0x060, 6);
+	clks[CLK_BUS_MMC0]  = sunxi_clk_gate("bus-mmc0",  "ahb1", regs + 0x060, 8);
+	clks[CLK_BUS_MMC1]  = sunxi_clk_gate("bus-mmc1",  "ahb1", regs + 0x060, 9);
+	clks[CLK_BUS_MMC2]  = sunxi_clk_gate("bus-mmc2",  "ahb1", regs + 0x060, 10);
+	clks[CLK_BUS_NAND]  = sunxi_clk_gate("bus-nand",  "ahb1", regs + 0x060, 13);
+	clks[CLK_BUS_DRAM]  = sunxi_clk_gate("bus-dram",  "ahb1", regs + 0x060, 14);
+	clks[CLK_BUS_EMAC]  = sunxi_clk_gate("bus-emac",  "ahb2", regs + 0x060, 17);
+	clks[CLK_BUS_TS]    = sunxi_clk_gate("bus-ts",    "ahb1", regs + 0x060, 18);
+	clks[CLK_BUS_HSTIMER] = sunxi_clk_gate("bus-hstimer", "ahb1", regs + 0x060, 19);
+	clks[CLK_BUS_SPI0]  = sunxi_clk_gate("bus-spi0",  "ahb1", regs + 0x060,  20);
+	clks[CLK_BUS_SPI1]  = sunxi_clk_gate("bus-spi1",  "ahb1", regs + 0x060,  21);
+	clks[CLK_BUS_OTG]   = sunxi_clk_gate("bus-otg",   "ahb1", regs + 0x060,  23);
+	clks[CLK_BUS_EHCI0] = sunxi_clk_gate("bus-ehci0", "ahb1", regs + 0x060, 24);
+	clks[CLK_BUS_EHCI1] = sunxi_clk_gate("bus-ehci1", "ahb2", regs + 0x060, 25);
+	clks[CLK_BUS_OHCI0] = sunxi_clk_gate("bus-ohci0", "ahb1", regs + 0x060, 28);
+	clks[CLK_BUS_OHCI1] = sunxi_clk_gate("bus-ohci1", "ahb2", regs + 0x060, 29);
+
+	clks[CLK_BUS_CODEC] = sunxi_clk_gate("bus-codec", "apb1", regs + 0x068, 0);
+	clks[CLK_BUS_SPDIF] = sunxi_clk_gate("bus-spdif", "apb1", regs + 0x068, 1);
+	clks[CLK_BUS_PIO]   = sunxi_clk_gate("bus-pio",   "apb1", regs + 0x068, 5);
+	clks[CLK_BUS_THS]   = sunxi_clk_gate("bus-ths",   "apb1", regs + 0x068, 8);
+	clks[CLK_BUS_I2S0]  = sunxi_clk_gate("bus-i2s0",  "apb1", regs + 0x068, 12);
+	clks[CLK_BUS_I2S1]  = sunxi_clk_gate("bus-i2s1",  "apb1", regs + 0x068, 13);
+	clks[CLK_BUS_I2S2]  = sunxi_clk_gate("bus-i2s2",  "apb1", regs + 0x068, 14);
+
+	clks[CLK_BUS_UART0] = sunxi_clk_gate("bus-uart0", "apb2", regs + 0x06c, 16);
+	clks[CLK_BUS_UART1] = sunxi_clk_gate("bus-uart1", "apb2", regs + 0x06c, 17);
+	clks[CLK_BUS_UART2] = sunxi_clk_gate("bus-uart2", "apb2", regs + 0x06c, 18);
+	clks[CLK_BUS_UART3] = sunxi_clk_gate("bus-uart3", "apb2", regs + 0x06c, 19);
+	clks[CLK_BUS_UART4] = sunxi_clk_gate("bus-uart4", "apb2", regs + 0x06c, 20);
+
+	clks[CLK_MMC0] = sunxi_ccu_clk(
+		"mmc0", sel_mmc, ARRAY_SIZE(sel_mmc),
+		regs, 0x088,
+		(struct ccu_clk_mux) { .shift = 24, .width = 2 },
+		(const struct ccu_clk_div[4]) {
+			{ .type = CCU_CLK_DIV_P,     .shift = 16, .width = 2, .off = 0 },
+			{ .type = CCU_CLK_DIV_M,     .shift =  0, .width = 4, .off = 0 },
+			{ .type = CCU_CLK_DIV_FIXED, .shift =  0, .width = 0, .off = 2 },
+		},
+		3,
+		BIT(31),
+		0);
+
+	clks[CLK_MMC1] = sunxi_ccu_clk(
+		"mmc1", sel_mmc, ARRAY_SIZE(sel_mmc),
+		regs, 0x08c,
+		(struct ccu_clk_mux) { .shift = 24, .width = 2 },
+		(const struct ccu_clk_div[4]) {
+			{ .type = CCU_CLK_DIV_P,     .shift = 16, .width = 2, .off = 0 },
+			{ .type = CCU_CLK_DIV_M,     .shift =  0, .width = 4, .off = 0 },
+			{ .type = CCU_CLK_DIV_FIXED, .shift =  0, .width = 0, .off = 2 },
+		},
+		3,
+		BIT(31),
+		0);
+
+	clks[CLK_MMC2] = sunxi_ccu_clk(
+		"mmc2", sel_mmc, ARRAY_SIZE(sel_mmc),
+		regs, 0x090,
+		(struct ccu_clk_mux) { .shift = 24, .width = 2 },
+		(const struct ccu_clk_div[4]) {
+			{ .type = CCU_CLK_DIV_P,     .shift = 16, .width = 2, .off = 0 },
+			{ .type = CCU_CLK_DIV_M,     .shift =  0, .width = 4, .off = 0 },
+			{ .type = CCU_CLK_DIV_FIXED, .shift =  0, .width = 0, .off = 2 },
+		},
+		3,
+		BIT(31),
+		0);
+}
+
+static int sun50i_a64_ccu_probe(struct device *dev)
+{
+	struct resource *iores;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	sun50i_a64_resets_init(IOMEM(iores->start));
+	sun50i_a64_clocks_init(IOMEM(iores->start));
+
+	return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, &clk_data);
+}
+
+static __maybe_unused struct of_device_id sun50i_a64_ccu_dt_ids[] = {
+	{ .compatible = "allwinner,sun50i-a64-ccu" },
+	{ }
+};
+
+static struct driver sun50i_a64_ccu_driver = {
+	.probe	= sun50i_a64_ccu_probe,
+	.name	= "sun50i-a64-ccu",
+	.of_compatible = DRV_OF_COMPAT(sun50i_a64_ccu_dt_ids),
+};
+core_platform_driver(sun50i_a64_ccu_driver);
diff --git a/drivers/clk/sunxi/clk-sun50i-a64.h b/drivers/clk/sunxi/clk-sun50i-a64.h
new file mode 100644
index 0000000000..a4ddc39eb8
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun50i-a64.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright 2016 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard at free-electrons.com>
+ */
+
+#include <dt-bindings/clock/sun50i-a64-ccu.h>
+
+#ifndef _CLK_SUN50I_A64_H_
+#define _CLK_SUN50I_A64_H_
+
+#include <dt-bindings/clock/sun50i-a64-ccu.h>
+#include <dt-bindings/reset/sun50i-a64-ccu.h>
+
+#define CLK_OSC_12M			0
+#define CLK_PLL_CPUX			1
+#define CLK_PLL_AUDIO_BASE		2
+#define CLK_PLL_AUDIO			3
+#define CLK_PLL_AUDIO_2X		4
+#define CLK_PLL_AUDIO_4X		5
+#define CLK_PLL_AUDIO_8X		6
+
+/* PLL_VIDEO0 exported for HDMI PHY */
+
+#define CLK_PLL_VIDEO0_2X		8
+#define CLK_PLL_VE			9
+#define CLK_PLL_DDR0			10
+
+/* PLL_PERIPH0 exported for PRCM */
+
+#define CLK_PLL_PERIPH0_2X		12
+#define CLK_PLL_PERIPH1			13
+#define CLK_PLL_PERIPH1_2X		14
+#define CLK_PLL_VIDEO1			15
+#define CLK_PLL_GPU			16
+#define CLK_PLL_MIPI			17
+#define CLK_PLL_HSIC			18
+#define CLK_PLL_DE			19
+#define CLK_PLL_DDR1			20
+#define CLK_AXI				22
+#define CLK_APB				23
+#define CLK_AHB1			24
+#define CLK_APB1			25
+#define CLK_APB2			26
+#define CLK_AHB2			27
+
+/* All the bus gates are exported */
+
+/* The first bunch of module clocks are exported */
+
+#define CLK_USB_OHCI0_12M		90
+
+#define CLK_USB_OHCI1_12M		92
+
+/* All the DRAM gates are exported */
+
+/* And the DSI and GPU module clock is exported */
+
+#define CLK_NUMBER			(CLK_GPU + 1)
+
+#endif /* _CLK_SUN50I_A64_H_ */
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
new file mode 100644
index 0000000000..ae96d1939e
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2024 Jules Maselbas
+#include <common.h>
+#include <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include "clk-sunxi.h"
+
+/* clk_hw to ccu_clk */
+#define to_ccu_clk(_hw) container_of(_hw, struct ccu_clk, hw)
+
+static void ccu_clk_gate(struct ccu_clk *clk, int enable)
+{
+	u32 val, old;
+
+	if (!clk->gate)
+		return;
+
+	old = val = readl(clk->base + clk->reg);
+	if (enable)
+		val |= clk->gate;
+	else
+		val &= ~clk->gate;
+	writel(val, clk->base + clk->reg);
+}
+
+static int ccu_clk_enable(struct clk_hw *hw)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+
+	ccu_clk_gate(clk, 1);
+
+	return 0;
+}
+
+static void ccu_clk_disable(struct clk_hw *hw)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+
+	ccu_clk_gate(clk, 0);
+}
+
+static int ccu_clk_is_enabled(struct clk_hw *hw)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+
+	if (clk->gate)
+		return readl(clk->base + clk->reg) & clk->gate;
+
+	return 1;
+}
+
+static int ccu_clk_get_parent(struct clk_hw *hw)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+	u32 reg, val;
+
+	if (!clk->mux.width)
+		return 0;
+
+	reg = readl(clk->base + clk->reg);
+	val = reg >> clk->mux.shift;
+	val &= (1 << clk->mux.width) - 1;
+
+	return clk_mux_val_to_index(hw, (u32 *)clk->mux.table, 0, val);
+}
+
+static int ccu_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+	u32 reg, val;
+
+	if (!clk->mux.width)
+		return 0;
+
+	/* index to val */
+	val = clk->mux.table ? clk->mux.table[index] : index;
+
+	reg = readl(clk->base + clk->reg);
+	reg &= ~(((1 << clk->mux.width) - 1) << clk->mux.shift);
+	reg |= val << clk->mux.shift;
+
+	writel(reg, clk->base + clk->reg);
+
+	return 0;
+}
+
+static u32 ccu_clk_get_div(struct ccu_clk_div *div, u32 val)
+{
+	u32 d;
+
+	switch (div->type) {
+	case CCU_CLK_DIV_FIXED:
+		d = div->off;
+		break;
+	case CCU_CLK_DIV_M:
+		d = val + 1 + div->off;
+		break;
+	case CCU_CLK_DIV_P:
+		d = (1 << val) + div->off;
+		break;
+	default:
+		d = 1;
+		break;
+	}
+
+	return d;
+}
+
+static u32 ccu_clk_min_div(struct ccu_clk *clk)
+{
+	u32 d = 1;
+	size_t i;
+
+	for (i = 0; i < 4; i++)
+		d *= ccu_clk_get_div(&clk->div[i], 0);
+
+	return d;
+}
+
+static u32 ccu_clk_max_div(struct ccu_clk *clk)
+{
+	u32 d = 1;
+	size_t i;
+
+	for (i = 0; i < 4; i++)
+		d *= ccu_clk_get_div(&clk->div[i], (1 << clk->div[i].width) - 1);
+
+	return d;
+}
+
+static unsigned long ccu_clk_find_best_div(struct ccu_clk *clk,
+				       unsigned long rate, unsigned long prate,
+				       u32 best_div[4])
+{
+	unsigned long r, best_rate = 0;
+	u32 i0, i1, i2, i3;
+	u32 m0, m1, m2, m3;
+	u32 d0, d1, d2, d3;
+
+	m0 = (1 << clk->div[0].width);
+	m1 = (1 << clk->div[1].width);
+	m2 = (1 << clk->div[2].width);
+	m3 = (1 << clk->div[3].width);
+
+	for (i3 = 0; i3 < m3; i3++) {
+		d3 = ccu_clk_get_div(&clk->div[3], i3);
+		for (i2 = 0; i2 < m2; i2++) {
+			d2 = d3 * ccu_clk_get_div(&clk->div[2], i2);
+			for (i1 = 0; i1 < m1; i1++) {
+				d1 = d2 * ccu_clk_get_div(&clk->div[1], i1);
+				for (i0 = 0; i0  < m0; i0++) {
+					d0 = d1 * ccu_clk_get_div(&clk->div[0], i0);
+					r = prate / d0;
+					if (r > rate)
+						continue;
+					if ((rate - r) < (rate - best_rate)) {
+						best_rate = r;
+						if (best_div) {
+							best_div[0] = i0;
+							best_div[1] = i1;
+							best_div[2] = i2;
+							best_div[3] = i3;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return best_rate;
+}
+
+static struct clk *clk_get_parent_index(struct clk *clk, int num)
+{
+	if (num >= clk->num_parents)
+		return NULL;
+
+	if (clk->parents[num])
+		return clk->parents[num];
+
+	clk->parents[num] = clk_lookup(clk->parent_names[num]);
+
+	return clk->parents[num];
+}
+
+static unsigned long ccu_clk_find_best_parent(struct ccu_clk *clk, unsigned long rate, int *idx)
+{
+	u32 min_div, max_div;
+	unsigned long min_rate, max_rate;
+	size_t i;
+
+	min_div = ccu_clk_min_div(clk);
+	max_div = ccu_clk_max_div(clk);
+
+	min_rate = rate * min_div;
+	max_rate = rate * max_div;
+
+	for (i = 0; i < clk->hw.clk.num_parents; i++) {
+		struct clk *parent = clk_get_parent_index(&clk->hw.clk, i);
+		unsigned long pr;
+
+		if (IS_ERR_OR_NULL(parent))
+			continue;
+
+		pr = clk_get_rate(parent);
+		if (min_rate <= pr && pr <= max_rate) {
+			if (idx)
+				*idx = i;
+			return pr;
+		}
+	}
+
+	return 0;
+}
+
+static int ccu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+			    unsigned long prate)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+	unsigned long rrate;
+	size_t i;
+	u32 dval[4] = {};
+	u32 reg, val, msk;
+	int idx;
+
+	prate = ccu_clk_find_best_parent(clk, rate, &idx);
+	ccu_clk_set_parent(hw, idx);
+
+	rrate = ccu_clk_find_best_div(clk, rate, prate, dval);
+	val = 0;
+	msk = 0;
+	for (i = 0; i < 4; i++) {
+		val |= dval[i] << clk->div[i].shift;
+		msk |= ((1 << clk->div[i].width) - 1) << clk->div[i].shift;
+	}
+
+	reg = readl(clk->base + clk->reg);
+	reg &= ~msk;
+	reg |= val & msk;
+	writel(reg, clk->base + clk->reg);
+
+	return 0;
+}
+
+static long ccu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long *prate)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+
+	if (clk->mux.width)
+		*prate = ccu_clk_find_best_parent(clk, rate, NULL);
+
+	return ccu_clk_find_best_div(clk, rate, *prate, NULL);
+}
+
+static unsigned long ccu_clk_recalc_rate(struct clk_hw *hw,
+					unsigned long prate)
+{
+	struct ccu_clk *clk = to_ccu_clk(hw);
+	unsigned long rate = prate;
+	size_t i;
+	u32 reg, val, div;
+
+	div = 1;
+	reg = readl(clk->base + clk->reg);
+	for (i = 0; i < clk->num_div; i++) {
+		val = reg >> clk->div[i].shift;
+		val &= (1 << clk->div[i].width) - 1;
+		div *= ccu_clk_get_div(&clk->div[i], val);
+	}
+	rate = prate / div;
+
+	return rate;
+}
+
+const struct clk_ops ccu_clk_ops = {
+	/* gate */
+	.disable        = ccu_clk_disable,
+	.enable         = ccu_clk_enable,
+	.is_enabled     = ccu_clk_is_enabled,
+	/* mux */
+	.get_parent	= ccu_clk_get_parent,
+	.set_parent	= ccu_clk_set_parent,
+	/* rate */
+	.round_rate     = ccu_clk_round_rate,
+	.set_rate       = ccu_clk_set_rate,
+	.recalc_rate    = ccu_clk_recalc_rate,
+};
+
+static struct clk *sunxi_ccu_clk_alloc(const char *name,
+				   const char * const *parents, u8 num_parents,
+				   void __iomem *base, u32 reg,
+				   struct ccu_clk_mux mux,
+				   const struct ccu_clk_div *div, u8 num_div,
+				   u32 gate,
+				   int flags)
+{
+	struct ccu_clk *clk;
+	size_t i;
+
+	clk = xzalloc(sizeof(*clk));
+	clk->base = base;
+	clk->reg = reg;
+
+	clk->mux = mux;
+	clk->num_div = num_div > 4 ? 4 : num_div;
+	for (i = 0; i < clk->num_div; i++)
+		clk->div[i] = div[i];
+	clk->gate = gate;
+
+	clk->hw.clk.ops = &ccu_clk_ops;
+	clk->hw.clk.name = name;
+	clk->hw.clk.flags = flags;
+	clk->hw.clk.parent_names = parents;
+	clk->hw.clk.num_parents = num_parents;
+
+	return &clk->hw.clk;
+}
+
+struct clk *sunxi_ccu_clk(const char *name,
+			  const char * const *parents, u8 num_parents,
+			  void __iomem *base, u32 reg,
+			  struct ccu_clk_mux mux,
+			  const struct ccu_clk_div *div, u8 num_div,
+			  u32 gate,
+			  int flags)
+{
+	struct clk *c;
+	int ret;
+
+	c = sunxi_ccu_clk_alloc(name, parents, num_parents,
+				base, reg,
+				mux,
+				div, num_div,
+				gate,
+				flags);
+
+	ret = bclk_register(c);
+	if (ret) {
+		struct clk_hw *hw = clk_to_clk_hw(c);
+		free(to_ccu_clk(hw));
+		return ERR_PTR(ret);
+	}
+
+	return c;
+}
diff --git a/drivers/clk/sunxi/clk-sunxi.h b/drivers/clk/sunxi/clk-sunxi.h
new file mode 100644
index 0000000000..2fd7f4bb30
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sunxi.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2024 Jules Maselbas */
+#include <linux/clk.h>
+
+static inline struct clk *
+sunxi_clk_gate(const char *name, const char *parent, void __iomem *reg, u8 shift)
+{
+	return clk_gate(name, parent, reg, shift, 0, 0);
+}
+
+static inline struct clk *
+sunxi_clk_mux(const char *name, const char * const *parents, u8 num_parents,
+	      void __iomem *reg, u8 shift, u8 width)
+{
+	return clk_mux(name, 0, reg, shift, width, parents, num_parents, 0);
+}
+
+static inline struct clk *
+sunxi_clk_div_table(const char *name, const char *parent, struct clk_div_table *table,
+	      void __iomem *reg, u8 shift, u8 width)
+{
+	return clk_divider_table(name, parent, CLK_SET_RATE_PARENT, reg, shift,
+				 width, table, 0);
+}
+
+static inline struct clk *
+sunxi_clk_div(const char *name, const char *parent,
+		void __iomem *reg, u8 shift, u8 width)
+{
+	return clk_divider(name, parent, CLK_SET_RATE_PARENT, reg, shift,
+				 width, 0);
+}
+
+static inline void nop_delay(volatile u32 cnt)
+{
+	while (cnt--)
+		barrier();
+}
+
+/* a "one size fit all" clk for barebox */
+
+struct ccu_clk {
+	struct clk_hw	hw;
+	u32 reg;
+	void __iomem	*base;
+
+	u32 gate;
+
+	struct ccu_clk_mux {
+		u8		shift;
+		u8		width;
+		const u32	*table;
+	} mux;
+
+	u8 num_div;
+	struct ccu_clk_div {
+		u8		shift;
+		u8		width;
+		u8		type;
+		u16		max;
+		u16		off;
+	} div[4];
+};
+
+enum ccu_clk_div_type {
+	CCU_CLK_DIV_FIXED = 1,
+	CCU_CLK_DIV_M,
+	CCU_CLK_DIV_P,
+};
+
+extern const struct clk_ops ccu_clk_ops;
+
+struct clk *sunxi_ccu_clk(const char *name,
+			  const char * const *parents, u8 num_parents,
+			  void __iomem *base, u32 reg,
+			  struct ccu_clk_mux mux,
+			  const struct ccu_clk_div *div, u8 num_div,
+			  u32 gate,
+			  int flags);
-- 
2.48.1



From jmaselbas at zdiv.net  Wed Feb 12 02:48:36 2025
From: jmaselbas at zdiv.net (Jules Maselbas)
Date: Wed, 12 Feb 2025 11:48:36 +0100
Subject: [PATCH v3 0/6] Initial support for Allwinner A64 SoC
Message-ID: <20250212104842.504-1-jmaselbas@zdiv.net>

This series adds an initial support for Allwinner, currently only
targetting the Pine64+ board, based on the A64 SoC.

This first series is intented as a second boot image only, that can
be started from u-boot. This series provides the bare minimal for
barebox to load the next OS from sd/mmc.

v2 highlights:
The main change in the V2 series is the new "one-size fit all"
clk driver only used right for the mmc0/mmc1/mmc2 clock source
(composite with a gate, a mux, two divs plus a fixed post-div).

v3 highlights:
Rework of the timeouts in the mci driver.
Split the lowlevel documentation out of this serie and added a
user documentation instead.
Replaced the sunxi_v8_defconfig with the multi_v8_defconfig

Jules Maselbas (6):
  clk: divider: add error code propagation
  clk: Add clock driver for sun50i-a64
  pinctrl: Add sun50i-a64 pinctrl driver
  mci: Add sunxi-mmc driver
  ARM: sunxi: Introduce mach-sunxi
  Documentation: sunxi: Add some documentation

 Documentation/boards/sunxi.rst             | 116 ++++
 arch/arm/Kconfig                           |  12 +
 arch/arm/Makefile                          |   1 +
 arch/arm/configs/multi_v8_defconfig        |   2 +
 arch/arm/mach-sunxi/Kconfig                |  13 +
 arch/arm/mach-sunxi/Makefile               |   1 +
 drivers/clk/Makefile                       |   1 +
 drivers/clk/clk-divider.c                  |   4 +-
 drivers/clk/sunxi/Makefile                 |   3 +
 drivers/clk/sunxi/clk-sun50i-a64.c         | 294 ++++++++++
 drivers/clk/sunxi/clk-sun50i-a64.h         |  62 +++
 drivers/clk/sunxi/clk-sunxi.c              | 348 ++++++++++++
 drivers/clk/sunxi/clk-sunxi.h              |  79 +++
 drivers/mci/Kconfig                        |   6 +
 drivers/mci/Makefile                       |   2 +
 drivers/mci/sunxi-mmc-common.c             | 238 +++++++++
 drivers/mci/sunxi-mmc-pbl.c                |  81 +++
 drivers/mci/sunxi-mmc.c                    | 176 ++++++
 drivers/mci/sunxi-mmc.h                    | 222 ++++++++
 drivers/pinctrl/Kconfig                    |   2 +
 drivers/pinctrl/Makefile                   |   1 +
 drivers/pinctrl/sunxi/Kconfig              |  13 +
 drivers/pinctrl/sunxi/Makefile             |   3 +
 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 594 +++++++++++++++++++++
 drivers/pinctrl/sunxi/pinctrl-sunxi.c      | 369 +++++++++++++
 drivers/pinctrl/sunxi/pinctrl-sunxi.h      | 224 ++++++++
 include/mach/sunxi/xload.h                 |  12 +
 27 files changed, 2878 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/boards/sunxi.rst
 create mode 100644 arch/arm/mach-sunxi/Kconfig
 create mode 100644 arch/arm/mach-sunxi/Makefile
 create mode 100644 drivers/clk/sunxi/Makefile
 create mode 100644 drivers/clk/sunxi/clk-sun50i-a64.c
 create mode 100644 drivers/clk/sunxi/clk-sun50i-a64.h
 create mode 100644 drivers/clk/sunxi/clk-sunxi.c
 create mode 100644 drivers/clk/sunxi/clk-sunxi.h
 create mode 100644 drivers/mci/sunxi-mmc-common.c
 create mode 100644 drivers/mci/sunxi-mmc-pbl.c
 create mode 100644 drivers/mci/sunxi-mmc.c
 create mode 100644 drivers/mci/sunxi-mmc.h
 create mode 100644 drivers/pinctrl/sunxi/Kconfig
 create mode 100644 drivers/pinctrl/sunxi/Makefile
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.c
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sunxi.h
 create mode 100644 include/mach/sunxi/xload.h

-- 
2.48.1



From s.hauer at pengutronix.de  Wed Feb 12 06:04:08 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:04:08 +0100
Subject: [PATCH] soc: k3: Add support for Texas Instruments K3 ESM
 driver
In-Reply-To: <20250207072013.226803-1-s.hauer@pengutronix.de>
References: <20250207072013.226803-1-s.hauer@pengutronix.de>
Message-ID: <173936904856.2535388.12714236788748890360.b4-ty@pengutronix.de>


On Fri, 07 Feb 2025 08:20:13 +0100, Sascha Hauer wrote:
> The ESM (Error Signaling Module) is used to route error signals within
> the K3 SoCs somewhat similar to interrupts. The handling for these is
> different though, and can be routed for hardware error handling, to
> be handled by safety processor or just as error interrupts handled
> by the main processor. The u-boot level ESM driver is just used to
> configure the ESM signals so that they get routed to proper destination.
> 
> [...]

Applied, thanks!

[1/1] soc: k3: Add support for Texas Instruments K3 ESM driver
      https://git.pengutronix.de/cgit/barebox/commit/?id=5ab2acff066c (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb 12 06:04:19 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:04:19 +0100
Subject: [PATCH] mfd: tps65219: register regmap cdev
In-Reply-To: <20250207072026.226822-1-s.hauer@pengutronix.de>
References: <20250207072026.226822-1-s.hauer@pengutronix.de>
Message-ID: <173936905916.2535557.1976255146060375794.b4-ty@pengutronix.de>


On Fri, 07 Feb 2025 08:20:26 +0100, Sascha Hauer wrote:
> Expose the tps65219 regmap as cdev for debugging purposes.
> 
> 

Applied, thanks!

[1/1] mfd: tps65219: register regmap cdev
      https://git.pengutronix.de/cgit/barebox/commit/?id=ac5024cc8730 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb 12 06:04:34 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:04:34 +0100
Subject: [PATCH master] SECURITY.md: add security policy
In-Reply-To: <20250210121726.376306-1-a.fatoum@pengutronix.de>
References: <20250210121726.376306-1-a.fatoum@pengutronix.de>
Message-ID: <173936907420.2535717.10825431585212081852.b4-ty@pengutronix.de>


On Mon, 10 Feb 2025 13:17:26 +0100, Ahmad Fatoum wrote:
> We prefer coordinated vulnerability disclosures, so users can be provided
> patch instructions for security issues alongside the vulnerabilities report.
> 
> Github handles a top-level SECURITY.md file specially and shows it in
> the security tab. Unlike other documentation, this can't be written
> in reST, so write it in markdown and adopt this convention.
> 
> [...]

Applied, thanks!

[1/1] SECURITY.md: add security policy
      https://git.pengutronix.de/cgit/barebox/commit/?id=65a107b2e066 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb 12 06:05:12 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:05:12 +0100
Subject: [PATCH] partitions: efi: Fix position of alternate gpt when
 writing
In-Reply-To: <20250211093408.1701730-1-s.hauer@pengutronix.de>
References: <20250211093408.1701730-1-s.hauer@pengutronix.de>
Message-ID: <173936911273.2535993.5473671541796254120.b4-ty@pengutronix.de>


On Tue, 11 Feb 2025 10:34:08 +0100, Sascha Hauer wrote:
> The primary GPT has a pointer to the alternate GPT. Set this pointer
> correctly when writing the partition table.
> 
> When the GPT originally has been created on the device, the alternate GPT
> should be at the end of the device already. However, when the GPT was
> created on an image which was then written to the disk, the alternate GPT
> might be at the end of the image instead of the device. In this case
> the alternate GPT changes its position during a partition write, so we
> have to adjust the pointer from the primary to the alternate GPT
> accordingly.
> 
> [...]

Applied, thanks!

[1/1] partitions: efi: Fix position of alternate gpt when writing
      https://git.pengutronix.de/cgit/barebox/commit/?id=d35dd0ae3e0a (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb 12 06:05:23 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:05:23 +0100
Subject: [PATCH] partitions: efi: fix error message in mkpart
In-Reply-To: <20250211093449.2226799-1-u.oelmann@pengutronix.de>
References: <20250211093449.2226799-1-u.oelmann@pengutronix.de>
Message-ID: <173936912313.2536082.13010924208181434978.b4-ty@pengutronix.de>


On Tue, 11 Feb 2025 10:34:49 +0100, Ulrich ?lmann wrote:
> Provided the condition in the if-clause is correct fix the off-by-one in
> calculating the maximum. Additionally print end_lba instead of start_lba.
> 
> 

Applied, thanks!

[1/1] partitions: efi: fix error message in mkpart
      https://git.pengutronix.de/cgit/barebox/commit/?id=cec0fae9d2c6 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb 12 06:05:53 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:05:53 +0100
Subject: [PATCH] ARM: i.MX93: allow board code to configure the bl33
 loadaddr
In-Reply-To: <20250128152211.1146024-1-m.grzeschik@pengutronix.de>
References: <20250128152211.1146024-1-m.grzeschik@pengutronix.de>
Message-ID: <173936915349.2536344.7904597867573674112.b4-ty@pengutronix.de>


On Tue, 28 Jan 2025 16:22:11 +0100, Michael Grzeschik wrote:
> Add parameterized __imx93_load_and_start_image_via_tfa function to
> load_and_start the image on arbitrary load addresses. This should be
> taken with caution since it requires to configure the TF-A correctly as
> well, therefore the function is prefixt with '__'.
> 
> One use case of the new helper is to place OP-TEE at the very beginning
> of the DRAM and barebox afterwards.
> 
> [...]

Applied, thanks!

[1/1] ARM: i.MX93: allow board code to configure the bl33 loadaddr
      https://git.pengutronix.de/cgit/barebox/commit/?id=93788c1b4d41 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb 12 06:09:14 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:14 +0100
Subject: [PATCH v2 01/20] ARM: k3: Add function to enable 32k crystal
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-1-8dd1bb0ce60a@pengutronix.de>

The external 32k crystal is optional and by default LFOSC0 is sourced
by a RC oscillator. This adds a function to be called by board code
when the 32k crystal is present and shall be used to source LFOSC0
from the crystal.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/common.c | 20 ++++++++++++++++++++
 include/mach/k3/common.h  |  1 +
 2 files changed, 21 insertions(+)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 3922a0ff19..c779e873c9 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -170,6 +170,26 @@ static void of_delete_node_path(struct device_node *root, const char *path)
 	of_delete_node(np);
 }
 
+#define MCU_CTRL_MMR0_BASE			0x04500000
+#define MCU_CTRL_LFXOSC_CTRL			(MCU_CTRL_MMR0_BASE + 0x8038)
+#define MCU_CTRL_LFXOSC_32K_DISABLE_VAL		BIT(7)
+#define MCU_CTRL_DEVICE_CLKOUT_LFOSC_SELECT_VAL	(0x3)
+#define MCU_CTRL_DEVICE_CLKOUT_32K_CTRL		(MCU_CTRL_MMR0_BASE + 0x8058)
+
+void am625_enable_32k_crystal(void)
+{
+	u32 val;
+
+	/* Enable 32k crystal */
+	val = readl(MCU_CTRL_LFXOSC_CTRL);
+	val &= ~(MCU_CTRL_LFXOSC_32K_DISABLE_VAL);
+	writel(val, MCU_CTRL_LFXOSC_CTRL);
+
+	/* select 32k clock from LFOSC0 */
+	writel(MCU_CTRL_DEVICE_CLKOUT_LFOSC_SELECT_VAL,
+	       MCU_CTRL_DEVICE_CLKOUT_32K_CTRL);
+}
+
 #define CTRLMMR_WKUP_JTAG_DEVICE_ID	(AM625_WKUP_CTRL_MMR0_BASE + 0x18)
 
 #define JTAG_DEV_CORE_NR		GENMASK(21, 19)
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index d7ceea51d7..3377dc8895 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -6,5 +6,6 @@
 void am625_get_bootsource(enum bootsource *src, int *instance);
 u64 am625_sdram_size(void);
 void am625_register_dram(void);
+void am625_enable_32k_crystal(void);
 
 #endif /* __MACH_K3_COMMON_H */

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:16 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:16 +0100
Subject: [PATCH v2 03/20] ARM: k3: do not mount /boot when booting from
 eMMC
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-3-8dd1bb0ce60a@pengutronix.de>

When booting from eMMC we load the subsequent stages from eMMC boot
partitions, so we do not need a boot FAT partition on eMMC. We can
use an unpartitioned area in the eMMC user area in this case, so
bail out from mounting /boot when eMMC boot is detected.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/common.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 7ded1f3f04..97cb46d58e 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -275,6 +275,9 @@ static int omap_env_init(void)
 	if (bootsource_get() != BOOTSOURCE_MMC)
 		return 0;
 
+	if (k3_boot_is_emmc())
+		return 0;
+
 	instance = bootsource_get_instance();
 
 	cdevname = xasprintf("mmc%d", instance);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:20 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:20 +0100
Subject: [PATCH v2 07/20] fiptool: do not typedef structs
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-7-8dd1bb0ce60a@pengutronix.de>

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 commands/fiptool.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/commands/fiptool.c b/commands/fiptool.c
index b917c62a97..eb7d9b5ac7 100644
--- a/commands/fiptool.c
+++ b/commands/fiptool.c
@@ -24,11 +24,11 @@
 #include <fip.h>
 #include <fiptool.h>
 
-typedef struct cmd {
+struct cmd {
 	char              *name;
 	int              (*handler)(struct fip_state *fip, int, char **);
 	void             (*usage)(int);
-} cmd_t;
+};
 
 
 static int write_image_to_file(const struct fip_image *image, const char *filename)
@@ -532,7 +532,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 }
 
 /* Available subcommands. */
-static cmd_t cmds[] = {
+static struct cmd cmds[] = {
 	{ .name = "info",    .handler = info_cmd,    },
 	{ .name = "uuid",    .handler = uuid_cmd,    },
 	{ .name = "unpack",  .handler = unpack_cmd,  },

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:17 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:17 +0100
Subject: [PATCH v2 04/20] fip: drop typedefs
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-4-8dd1bb0ce60a@pengutronix.de>

Do not typedef struct types.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 commands/fiptool.c | 28 ++++++++++++++--------------
 include/fiptool.h  | 26 +++++++++++++-------------
 lib/fip.c          | 44 ++++++++++++++++++++++----------------------
 3 files changed, 49 insertions(+), 49 deletions(-)

diff --git a/commands/fiptool.c b/commands/fiptool.c
index 2d766f895b..a4370c9eef 100644
--- a/commands/fiptool.c
+++ b/commands/fiptool.c
@@ -31,7 +31,7 @@ typedef struct cmd {
 } cmd_t;
 
 
-static int write_image_to_file(const image_t *image, const char *filename)
+static int write_image_to_file(const struct fip_image *image, const char *filename)
 {
 	int fd;
 
@@ -53,7 +53,7 @@ static int write_image_to_file(const image_t *image, const char *filename)
 
 static int info_cmd(struct fip_state *fip, int argc, char *argv[])
 {
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 	fip_toc_header_t toc_header;
 	int ret;
 
@@ -74,7 +74,7 @@ static int info_cmd(struct fip_state *fip, int argc, char *argv[])
 	    (unsigned long long)toc_header.flags);
 
 	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
-		image_t *image = desc->image;
+		struct fip_image *image = desc->image;
 
 		if (image == NULL)
 			continue;
@@ -193,7 +193,7 @@ static __maybe_unused int create_cmd(struct fip_state *fip, int argc, char *argv
 	while ((opt = getopt(argc, argv, "e:p:a:b:")) > 0) {
 		switch (opt) {
 		case 'e': {
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			desc = lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
@@ -214,7 +214,7 @@ static __maybe_unused int create_cmd(struct fip_state *fip, int argc, char *argv
 			char name[UUID_STRING_LEN + 1];
 			char filename[PATH_MAX] = { 0 };
 			uuid_t uuid = uuid_null;
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
@@ -264,7 +264,7 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 	while ((opt = getopt(argc, argv, "e:p:b:a:o:")) > 0) {
 		switch (opt) {
 		case 'e': {
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			desc = lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
@@ -281,7 +281,7 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 			char name[UUID_STRING_LEN + 1];
 			char filename[PATH_MAX] = { 0 };
 			uuid_t uuid = uuid_null;
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
@@ -339,7 +339,7 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 {
 	char outdir[PATH_MAX] = { 0 };
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 	int fflag = 0;
 	int unpack_all = 1;
 	int ret, opt;
@@ -350,7 +350,7 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 	while ((opt = getopt(argc, argv, "e:b:fo:")) > 0) {
 		switch (opt) {
 		case 'e': {
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			desc = lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
@@ -363,7 +363,7 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 			char name[UUID_STRING_LEN + 1];
 			char filename[PATH_MAX] = { 0 };
 			uuid_t uuid = uuid_null;
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
@@ -411,7 +411,7 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 	/* Unpack all specified images. */
 	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
 		char file[PATH_MAX];
-		image_t *image = desc->image;
+		struct fip_image *image = desc->image;
 
 		if (!unpack_all && desc->action != DO_UNPACK)
 			continue;
@@ -447,7 +447,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 {
 	char outfile[PATH_MAX] = { 0 };
 	fip_toc_header_t toc_header;
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 	long align = 1;
 	int ret, opt, fflag = 0;
 
@@ -457,7 +457,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 	while ((opt = getopt(argc, argv, "e:a:b:fo:")) > 0) {
 		switch (opt) {
 		case 'e': {
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			desc = lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
@@ -473,7 +473,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 		case 'b': {
 			char name[UUID_STRING_LEN + 1], filename[PATH_MAX];
 			uuid_t uuid = uuid_null;
-			image_desc_t *desc;
+			struct fip_image_desc *desc;
 
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
diff --git a/include/fiptool.h b/include/fiptool.h
index 704845f456..6f1d69d178 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -16,23 +16,23 @@ enum {
 	DO_REMOVE = 3
 };
 
-typedef struct image_desc {
+struct fip_image_desc {
 	uuid_t             uuid;
 	char              *name;
 	char              *cmdline_name;
 	int                action;
 	char              *action_arg;
-	struct image      *image;
-	struct image_desc *next;
-} image_desc_t;
+	struct fip_image  *image;
+	struct fip_image_desc *next;
+};
 
-typedef struct image {
+struct fip_image {
 	struct fip_toc_entry toc_e;
 	void                *buffer;
-} image_t;
+};
 
 struct fip_state {
-	image_desc_t *image_desc_head;
+	struct fip_image_desc *image_desc_head;
 	size_t nr_image_descs;
 	int verbose;
 };
@@ -45,24 +45,24 @@ struct fip_state {
 	} \
 } while (0)
 
-image_desc_t *new_image_desc(const uuid_t *uuid,
+struct fip_image_desc *new_image_desc(const uuid_t *uuid,
 			     const char *name, const char *cmdline_name);
 
-void set_image_desc_action(image_desc_t *desc, int action,
+void set_image_desc_action(struct fip_image_desc *desc, int action,
     const char *arg);
 
-void free_image_desc(image_desc_t *desc);
+void free_image_desc(struct fip_image_desc *desc);
 
-void add_image_desc(struct fip_state *fip, image_desc_t *desc);
+void add_image_desc(struct fip_state *fip, struct fip_image_desc *desc);
 
 void free_image_descs(struct fip_state *fip);
 
 void fill_image_descs(struct fip_state *fip);
 
-image_desc_t *lookup_image_desc_from_uuid(struct fip_state *fip,
+struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
 						 const uuid_t *uuid);
 
-image_desc_t *lookup_image_desc_from_opt(struct fip_state *fip, char **arg);
+struct fip_image_desc *lookup_image_desc_from_opt(struct fip_state *fip, char **arg);
 
 int parse_fip(struct fip_state *fip,
 		     const char *filename, fip_toc_header_t *toc_header_out);
diff --git a/lib/fip.c b/lib/fip.c
index ae7ff8b3ad..e7589ff4c2 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -26,10 +26,10 @@
 #include <fip.h>
 #include <fiptool.h>
 
-image_desc_t *new_image_desc(const uuid_t *uuid,
+struct fip_image_desc *new_image_desc(const uuid_t *uuid,
 			     const char *name, const char *cmdline_name)
 {
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 
 	desc = xzalloc(sizeof(*desc));
 	memcpy(&desc->uuid, uuid, sizeof(uuid_t));
@@ -39,7 +39,7 @@ image_desc_t *new_image_desc(const uuid_t *uuid,
 	return desc;
 }
 
-void set_image_desc_action(image_desc_t *desc, int action,
+void set_image_desc_action(struct fip_image_desc *desc, int action,
     const char *arg)
 {
 	ASSERT(desc != NULL);
@@ -52,7 +52,7 @@ void set_image_desc_action(image_desc_t *desc, int action,
 		desc->action_arg = xstrdup(arg);
 }
 
-void free_image_desc(image_desc_t *desc)
+void free_image_desc(struct fip_image_desc *desc)
 {
 	free(desc->name);
 	free(desc->cmdline_name);
@@ -64,9 +64,9 @@ void free_image_desc(image_desc_t *desc)
 	free(desc);
 }
 
-void add_image_desc(struct fip_state *fip, image_desc_t *desc)
+void add_image_desc(struct fip_state *fip, struct fip_image_desc *desc)
 {
-	image_desc_t **p = &fip->image_desc_head;
+	struct fip_image_desc **p = &fip->image_desc_head;
 
 	while (*p)
 		p = &(*p)->next;
@@ -78,7 +78,7 @@ void add_image_desc(struct fip_state *fip, image_desc_t *desc)
 
 void free_image_descs(struct fip_state *fip)
 {
-	image_desc_t *desc = fip->image_desc_head, *tmp;
+	struct fip_image_desc *desc = fip->image_desc_head, *tmp;
 
 	while (desc != NULL) {
 		tmp = desc->next;
@@ -96,7 +96,7 @@ void fill_image_descs(struct fip_state *fip)
 	for (toc_entry = toc_entries;
 	     toc_entry->cmdline_name != NULL;
 	     toc_entry++) {
-		image_desc_t *desc;
+		struct fip_image_desc *desc;
 
 		desc = new_image_desc(&toc_entry->uuid,
 		    toc_entry->name,
@@ -106,7 +106,7 @@ void fill_image_descs(struct fip_state *fip)
 	for (toc_entry = plat_def_toc_entries;
 	     toc_entry->cmdline_name != NULL;
 	     toc_entry++) {
-		image_desc_t *desc;
+		struct fip_image_desc *desc;
 
 		desc = new_image_desc(&toc_entry->uuid,
 		    toc_entry->name,
@@ -115,10 +115,10 @@ void fill_image_descs(struct fip_state *fip)
 	}
 }
 
-image_desc_t *lookup_image_desc_from_uuid(struct fip_state *fip,
+struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
 						 const uuid_t *uuid)
 {
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 
 	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next)
 		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
@@ -126,10 +126,10 @@ image_desc_t *lookup_image_desc_from_uuid(struct fip_state *fip,
 	return NULL;
 }
 
-image_desc_t *lookup_image_desc_from_opt(struct fip_state *fip, char **arg)
+struct fip_image_desc *lookup_image_desc_from_opt(struct fip_state *fip, char **arg)
 {
 	int len = 0;
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 	char *eq;
 
 	eq = strchrnul(*arg, '=');
@@ -200,8 +200,8 @@ int parse_fip(struct fip_state *fip,
 
 	/* Walk through each ToC entry in the file. */
 	while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
-		image_t *image;
-		image_desc_t *desc;
+		struct fip_image *image;
+		struct fip_image_desc *desc;
 
 		/* Found the ToC terminator, we are done. */
 		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
@@ -260,10 +260,10 @@ int parse_fip(struct fip_state *fip,
 	return 0;
 }
 
-static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
+static struct fip_image *read_image_from_file(const uuid_t *uuid, const char *filename)
 {
 	struct stat st;
-	image_t *image;
+	struct fip_image *image;
 	int fd;
 
 	ASSERT(uuid != NULL);
@@ -298,7 +298,7 @@ int pack_images(struct fip_state *fip,
 		uint64_t toc_flags, unsigned long align)
 {
 	int fd;
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 	fip_toc_header_t *toc_header;
 	fip_toc_entry_t *toc_entry;
 	char *buf;
@@ -325,7 +325,7 @@ int pack_images(struct fip_state *fip,
 
 	entry_offset = buf_size;
 	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
-		image_t *image = desc->image;
+		struct fip_image *image = desc->image;
 
 		if (image == NULL || (image->toc_e.size == 0ULL))
 			continue;
@@ -361,7 +361,7 @@ int pack_images(struct fip_state *fip,
 	pr_verbose("Payload size: %llu bytes\n", payload_size);
 
 	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
-		image_t *image = desc->image;
+		struct fip_image *image = desc->image;
 
 		if (image == NULL)
 			continue;
@@ -396,11 +396,11 @@ int pack_images(struct fip_state *fip,
  */
 int update_fip(struct fip_state *fip)
 {
-	image_desc_t *desc;
+	struct fip_image_desc *desc;
 
 	/* Add or replace images in the FIP file. */
 	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
-		image_t *image;
+		struct fip_image *image;
 
 		if (desc->action != DO_PACK)
 			continue;

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:13 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:13 +0100
Subject: [PATCH v2 00/20] ARM: K3 updates
Message-ID: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>

This series has some updates for the TI K3 architecture.

We add support for bootstrapping boards via USB DFU. This has been sent
earlier, this time booting from eMMC is added as well.

On K3 SoCs we need a bunch of images after the first stage has been
loaded: OP-TEE, ti-dm firmware, TF-A binary and finally a barebox
binary. Until now these are expected as distinct images on the SD cards
FAT partition. This is impractical for booting from eMMC boot partitions
and also DFU boot, so this series adds support for handling a FIP image
containing these binaries.

Also some misc patches like enabling the 32k crystal needed for accurate
RTC frequency

Sascha

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
Changes in v2:
- Improve existing FIP code and use it instead of open coding parsing the
  FIP image
- add defconfig file for k3-r5
- Cleanup the board entry functions for the K3 Boards
- Link to v1: https://lore.kernel.org/r/20250205-k3-emmc-v1-0-06679246be41 at pengutronix.de

---
Sascha Hauer (20):
      ARM: k3: Add function to enable 32k crystal
      ARM: k3: add function to detect eMMC boot
      ARM: k3: do not mount /boot when booting from eMMC
      fip: drop typedefs
      fip: use linux list implementation
      fip: use uuid_equal() and uuid_is_null()
      fiptool: do not typedef structs
      fip: add fip_ prefix
      fip: add fip_image_open()
      ARM: k3: r5: add USB DFU and eMMC boot support
      ARM: am625-sk: enable 32k crystal
      mci: am654: parse generic mmc node properties
      ARM: k3: limit eMMC frequency to 26MHz
      ARM: k3: add eMMC barebox update handler
      ARM: am625-sk: put environment on eMMC when booting from it
      serial: omap: Use ttyS as Linux console name
      ARM: k3: remove beagleplay FIT image
      ARM: am625-sk: cleanup board entry
      ARM: beagleplay: cleanup board entry
      ARM: k3: Add k3-r5_defconfig

 Documentation/boards/ti-k3.rst        |  47 +++++++
 arch/arm/boards/am625-sk/Makefile     |   2 +-
 arch/arm/boards/am625-sk/board.c      |  35 +++++
 arch/arm/boards/am625-sk/entry.S      |  29 ----
 arch/arm/boards/am625-sk/lowlevel.c   |  13 +-
 arch/arm/boards/beagleplay/Makefile   |   1 -
 arch/arm/boards/beagleplay/entry.S    |  29 ----
 arch/arm/boards/beagleplay/lowlevel.c |  18 +--
 arch/arm/configs/k3-r5_defconfig      |  43 ++++++
 arch/arm/dts/k3-am625-beagleplay.dts  |   4 +
 arch/arm/dts/k3-am625-sk.dts          |  19 +++
 arch/arm/mach-k3/Kconfig              |   1 +
 arch/arm/mach-k3/Makefile             |   1 +
 arch/arm/mach-k3/bbu.c                |  77 +++++++++++
 arch/arm/mach-k3/common.c             |  36 +++++
 arch/arm/mach-k3/r5.c                 | 232 +++++++++++++++++++++++++++-----
 commands/fiptool.c                    | 126 +++++++++---------
 drivers/mci/am654-sdhci.c             |   1 +
 drivers/serial/serial_ns16550.c       |   4 +-
 images/Makefile.k3                    |   4 -
 images/k3-am625-beagleplay.its        |  29 ----
 include/fiptool.h                     |  50 ++++---
 include/mach/k3/common.h              |  22 ++++
 lib/fip.c                             | 242 ++++++++++++++++++++++++++--------
 24 files changed, 781 insertions(+), 284 deletions(-)
---
base-commit: ac5af75a4067dd3f795ca982c3edeb75012f7a98
change-id: 20250205-k3-emmc-eaa3df9f3ffd

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Wed Feb 12 06:09:22 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:22 +0100
Subject: [PATCH v2 09/20] fip: add fip_image_open()
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-9-8dd1bb0ce60a@pengutronix.de>

This adds a fip_image_open() function as an alternative to fip_parse().
Unline fip_parse() the new function:

- Allows to specify an offset with the file for reading a FIP image from
  partitions
- Does not read past the image when the FIP image is on a partition
  which is bigger than the FIP image
- less memory consumption

fip_image_open() is mainly useful for reading a FIP image without the
intent of modifying it.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 include/fiptool.h |   4 ++
 lib/fip.c         | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 135 insertions(+), 1 deletion(-)

diff --git a/include/fiptool.h b/include/fiptool.h
index 6a12466c29..bc42f7edd6 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -30,12 +30,14 @@ struct fip_image_desc {
 struct fip_image {
 	struct fip_toc_entry toc_e;
 	void                *buffer;
+	bool                 buf_no_free;
 };
 
 struct fip_state {
 	struct list_head descs;
 	size_t nr_image_descs;
 	int verbose;
+	void *buffer;
 };
 
 #define pr_verbose(...) do { \
@@ -92,4 +94,6 @@ extern toc_entry_t plat_def_toc_entries[];
 #define fip_for_each_desc_safe(fip, e, tmp) \
         list_for_each_entry_safe(e, tmp, &(fip)->descs, list)
 
+struct fip_state *fip_image_open(const char *filename, size_t offset);
+
 #endif /* FIPTOOL_H */
diff --git a/lib/fip.c b/lib/fip.c
index 075cd0e1e6..39b0fd20aa 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -58,7 +58,8 @@ void fip_free_image_desc(struct fip_image_desc *desc)
 	free(desc->cmdline_name);
 	free(desc->action_arg);
 	if (desc->image) {
-		free(desc->image->buffer);
+		if (!desc->image->buf_no_free)
+			free(desc->image->buffer);
 		free(desc->image);
 	}
 	free(desc);
@@ -92,6 +93,7 @@ void fip_free(struct fip_state *fip)
 
 	ASSERT(fip->nr_image_descs == 0);
 
+	free(fip->buffer);
 	free(fip);
 }
 
@@ -430,3 +432,131 @@ int fip_update(struct fip_state *fip)
 
 	return 0;
 }
+
+/*
+ * fip_image_open - open a FIP image for readonly access
+ * @filename: The filename of the FIP image
+ * @offset: The offset of the FIP image in the file
+ *
+ * This opens a FIP image for readonly access. This is an alternative
+ * implementation for fip_parse() with these differences:
+ * - suitable for reading FIP images from raw partitions. This function
+ *   only reads the FIP image, even when the partition is bigger than the
+ *   image
+ * - Allows to specify an offset within the partition where the FIP image
+ *   starts
+ * - Do not memdup the images from the full FIP image
+ *
+ * This function is for easy readonly access to the images within the FIP
+ * image. Do not call any of the above FIP manipulation functions other than
+ * fip_free() on an image opened with this function.
+ */
+struct fip_state *fip_image_open(const char *filename, size_t offset)
+{
+	fip_toc_header_t toc_header;
+	int ret;
+	int fd;
+	struct fip_state *fip_state;
+	LIST_HEAD(entries);
+	size_t fip_headers_size, total = 0;
+	struct fip_image_desc *desc;
+	off_t pos;
+	int n_entries = 0;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return ERR_PTR(fd);
+
+	fip_state = fip_new();
+
+	pos = lseek(fd, offset, SEEK_SET);
+	if (pos != offset) {
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = read_full(fd, &toc_header, sizeof(toc_header));
+	if (ret < 0)
+		goto err;
+
+	if (ret < sizeof(toc_header)) {
+		ret = -ENODATA;
+		goto err;
+	}
+
+	if (toc_header.name != TOC_HEADER_NAME) {
+		pr_err("%s is not a FIP file: unknown magic = 0x%08x\n",
+		       filename, toc_header.name);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* read all toc entries */
+	while (1) {
+		struct fip_image_desc *desc = xzalloc(sizeof(*desc));
+		struct fip_image *image = xzalloc(sizeof(*image));
+		struct fip_toc_entry *toc_entry = &image->toc_e;
+
+		desc->image = image;
+
+		ret = read_full(fd, toc_entry, sizeof(*toc_entry));
+		if (ret < 0)
+			goto err;
+		if (ret < sizeof(*toc_entry)) {
+			ret = -ENODATA;
+			goto err;
+		}
+
+		list_add_tail(&desc->list, &fip_state->descs);
+
+		pr_debug("Read TOC entry %pU %llu %llu\n", &toc_entry->uuid,
+			 toc_entry->offset_address, toc_entry->size);
+
+		/* Found the ToC terminator, we are done. */
+		if (uuid_is_null(&toc_entry->uuid))
+			break;
+	}
+
+	/* determine buffer size */
+	fip_for_each_desc(fip_state, desc) {
+		uint64_t this_end = desc->image->toc_e.offset_address + desc->image->toc_e.size;
+
+		if (this_end > total)
+			total = this_end;
+		n_entries++;
+	}
+
+	fip_headers_size = n_entries * sizeof(struct fip_toc_entry) + sizeof(fip_toc_header_t);
+
+	total -= fip_headers_size;
+
+	fip_state->buffer = malloc(total);
+	if (!fip_state->buffer) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = read_full(fd, fip_state->buffer, total);
+	if (ret < 0)
+		goto err;
+
+	if (ret < total) {
+		ret = -ENODATA;
+		goto err;
+	}
+
+	close(fd);
+
+	fip_for_each_desc(fip_state, desc) {
+		desc->image->buffer = fip_state->buffer +
+			desc->image->toc_e.offset_address - fip_headers_size;
+		desc->image->buf_no_free = true;
+	}
+
+	return fip_state;
+err:
+	close(fd);
+	fip_free(fip_state);
+
+	return ERR_PTR(ret);
+}

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:21 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:21 +0100
Subject: [PATCH v2 08/20] fip: add fip_ prefix
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-8-8dd1bb0ce60a@pengutronix.de>

Many functions of the FIP library do not have an indication what
they are about. Add a fip_ prefix to all FIP related functions.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 commands/fiptool.c | 68 +++++++++++++++++++++++++++---------------------------
 include/fiptool.h  | 20 ++++++++--------
 lib/fip.c          | 40 ++++++++++++++++----------------
 3 files changed, 64 insertions(+), 64 deletions(-)

diff --git a/commands/fiptool.c b/commands/fiptool.c
index eb7d9b5ac7..46b5ed29c3 100644
--- a/commands/fiptool.c
+++ b/commands/fiptool.c
@@ -62,7 +62,7 @@ static int info_cmd(struct fip_state *fip, int argc, char *argv[])
 
 	argc--, argv++;
 
-	ret = parse_fip(fip, argv[0], &toc_header);
+	ret = fip_parse(fip, argv[0], &toc_header);
 	if (ret)
 		return ret;
 
@@ -195,10 +195,10 @@ static __maybe_unused int create_cmd(struct fip_state *fip, int argc, char *argv
 		case 'e': {
 			struct fip_image_desc *desc;
 
-			desc = lookup_image_desc_from_opt(fip, &optarg);
+			desc = fip_lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
 				return COMMAND_ERROR;
-			set_image_desc_action(desc, DO_PACK, optarg);
+			fip_set_image_desc_action(desc, DO_PACK, optarg);
 			break;
 		}
 		case 'p':
@@ -222,13 +222,13 @@ static __maybe_unused int create_cmd(struct fip_state *fip, int argc, char *argv
 			if (uuid_is_null(&uuid) || filename[0] == '\0')
 				return COMMAND_ERROR_USAGE;
 
-			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			desc = fip_lookup_image_desc_from_uuid(fip, &uuid);
 			if (desc == NULL) {
 				snprintf(name, sizeof(name), "%pU", &uuid);
-				desc = new_image_desc(&uuid, name, "blob");
-				add_image_desc(fip, desc);
+				desc = fip_new_image_desc(&uuid, name, "blob");
+				fip_add_image_desc(fip, desc);
 			}
-			set_image_desc_action(desc, DO_PACK, filename);
+			fip_set_image_desc_action(desc, DO_PACK, filename);
 			break;
 		}
 		default:
@@ -241,10 +241,10 @@ static __maybe_unused int create_cmd(struct fip_state *fip, int argc, char *argv
 	if (argc == 0)
 		return COMMAND_ERROR_USAGE;
 
-	if (update_fip(fip))
+	if (fip_update(fip))
 		return COMMAND_ERROR;
 
-	return pack_images(fip, argv[0], toc_flags, align);
+	return fip_pack_images(fip, argv[0], toc_flags, align);
 }
 
 
@@ -265,10 +265,10 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 		case 'e': {
 			struct fip_image_desc *desc;
 
-			desc = lookup_image_desc_from_opt(fip, &optarg);
+			desc = fip_lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
 				return COMMAND_ERROR;
-			set_image_desc_action(desc, DO_PACK, optarg);
+			fip_set_image_desc_action(desc, DO_PACK, optarg);
 			break;
 		}
 		case 'p':
@@ -289,13 +289,13 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 			    filename[0] == '\0')
 				return COMMAND_ERROR_USAGE;
 
-			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			desc = fip_lookup_image_desc_from_uuid(fip, &uuid);
 			if (desc == NULL) {
 				snprintf(name, sizeof(name), "%pU", &uuid);
-				desc = new_image_desc(&uuid, name, "blob");
-				add_image_desc(fip, desc);
+				desc = fip_new_image_desc(&uuid, name, "blob");
+				fip_add_image_desc(fip, desc);
 			}
-			set_image_desc_action(desc, DO_PACK, filename);
+			fip_set_image_desc_action(desc, DO_PACK, filename);
 			break;
 		}
 		case 'a':
@@ -320,7 +320,7 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
 
 	if (file_exists(argv[0])) {
-		ret = parse_fip(fip, argv[0], &toc_header);
+		ret = fip_parse(fip, argv[0], &toc_header);
 		if (ret)
 			return ret;
 	}
@@ -329,10 +329,10 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 		toc_header.flags &= ~(0xffffULL << 32);
 	toc_flags = (toc_header.flags |= toc_flags);
 
-	if (update_fip(fip))
+	if (fip_update(fip))
 		return COMMAND_ERROR;
 
-	return pack_images(fip, outfile, toc_flags, align);
+	return fip_pack_images(fip, outfile, toc_flags, align);
 }
 
 static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
@@ -351,10 +351,10 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 		case 'e': {
 			struct fip_image_desc *desc;
 
-			desc = lookup_image_desc_from_opt(fip, &optarg);
+			desc = fip_lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
 				return COMMAND_ERROR;
-			set_image_desc_action(desc, DO_UNPACK, optarg);
+			fip_set_image_desc_action(desc, DO_UNPACK, optarg);
 			unpack_all = 0;
 			break;
 		}
@@ -370,13 +370,13 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 			if (uuid_is_null(&uuid) || filename[0] == '\0')
 				return COMMAND_ERROR_USAGE;
 
-			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			desc = fip_lookup_image_desc_from_uuid(fip, &uuid);
 			if (desc == NULL) {
 				snprintf(name, sizeof(name), "%pU", &uuid);
-				desc = new_image_desc(&uuid, name, "blob");
-				add_image_desc(fip, desc);
+				desc = fip_new_image_desc(&uuid, name, "blob");
+				fip_add_image_desc(fip, desc);
 			}
-			set_image_desc_action(desc, DO_UNPACK, filename);
+			fip_set_image_desc_action(desc, DO_UNPACK, filename);
 			unpack_all = 0;
 			break;
 		}
@@ -396,7 +396,7 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 	if (argc == 0)
 		return COMMAND_ERROR_USAGE;
 
-	ret = parse_fip(fip, argv[0], NULL);
+	ret = fip_parse(fip, argv[0], NULL);
 	if (ret)
 		return ret;
 
@@ -457,10 +457,10 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 		case 'e': {
 			struct fip_image_desc *desc;
 
-			desc = lookup_image_desc_from_opt(fip, &optarg);
+			desc = fip_lookup_image_desc_from_opt(fip, &optarg);
 			if (!desc)
 				return COMMAND_ERROR;
-			set_image_desc_action(desc, DO_REMOVE, NULL);
+			fip_set_image_desc_action(desc, DO_REMOVE, NULL);
 			break;
 		}
 		case 'a':
@@ -479,13 +479,13 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 			if (uuid_is_null(&uuid))
 				return COMMAND_ERROR_USAGE;
 
-			desc = lookup_image_desc_from_uuid(fip, &uuid);
+			desc = fip_lookup_image_desc_from_uuid(fip, &uuid);
 			if (desc == NULL) {
 				snprintf(name, sizeof(name), "%pU", &uuid);
-				desc = new_image_desc(&uuid, name, "blob");
-				add_image_desc(fip, desc);
+				desc = fip_new_image_desc(&uuid, name, "blob");
+				fip_add_image_desc(fip, desc);
 			}
-			set_image_desc_action(desc, DO_REMOVE, NULL);
+			fip_set_image_desc_action(desc, DO_REMOVE, NULL);
 			break;
 		}
 		case 'f':
@@ -511,7 +511,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 	if (outfile[0] == '\0')
 		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
 
-	ret = parse_fip(fip, argv[0], &toc_header);
+	ret = fip_parse(fip, argv[0], &toc_header);
 	if (ret)
 		return ret;
 
@@ -528,7 +528,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 		}
 	}
 
-	return pack_images(fip, outfile, toc_header.flags, align);
+	return fip_pack_images(fip, outfile, toc_header.flags, align);
 }
 
 /* Available subcommands. */
@@ -567,7 +567,7 @@ static int do_fiptool(int argc, char *argv[])
 	if (argc == 0)
 		return COMMAND_ERROR_USAGE;
 
-	fill_image_descs(fip);
+	fip_fill_image_descs(fip);
 	for (i = 0; i < ARRAY_SIZE(cmds); i++) {
 		if (strcmp(cmds[i].name, argv[0]) == 0) {
 			struct getopt_context gc;
diff --git a/include/fiptool.h b/include/fiptool.h
index 5a3fdee6e0..6a12466c29 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -49,31 +49,31 @@ struct fip_state {
 struct fip_state *fip_new(void);
 void fip_free(struct fip_state *fip);
 
-struct fip_image_desc *new_image_desc(const uuid_t *uuid,
+struct fip_image_desc *fip_new_image_desc(const uuid_t *uuid,
 			     const char *name, const char *cmdline_name);
 
-void set_image_desc_action(struct fip_image_desc *desc, int action,
+void fip_set_image_desc_action(struct fip_image_desc *desc, int action,
     const char *arg);
 
-void free_image_desc(struct fip_image_desc *desc);
+void fip_free_image_desc(struct fip_image_desc *desc);
 
-void add_image_desc(struct fip_state *fip, struct fip_image_desc *desc);
+void fip_add_image_desc(struct fip_state *fip, struct fip_image_desc *desc);
 
-void fill_image_descs(struct fip_state *fip);
+void fip_fill_image_descs(struct fip_state *fip);
 
-struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
+struct fip_image_desc *fip_lookup_image_desc_from_uuid(struct fip_state *fip,
 						 const uuid_t *uuid);
 
-struct fip_image_desc *lookup_image_desc_from_opt(struct fip_state *fip, char **arg);
+struct fip_image_desc *fip_lookup_image_desc_from_opt(struct fip_state *fip, char **arg);
 
-int parse_fip(struct fip_state *fip,
+int fip_parse(struct fip_state *fip,
 		     const char *filename, fip_toc_header_t *toc_header_out);
 
-int pack_images(struct fip_state *fip,
+int fip_pack_images(struct fip_state *fip,
 		const char *filename,
 		uint64_t toc_flags, unsigned long align);
 
-int update_fip(struct fip_state *fip);
+int fip_update(struct fip_state *fip);
 
 #define TOC_HEADER_SERIAL_NUMBER 0x12345678
 
diff --git a/lib/fip.c b/lib/fip.c
index 774de2ad1d..075cd0e1e6 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -26,7 +26,7 @@
 #include <fip.h>
 #include <fiptool.h>
 
-struct fip_image_desc *new_image_desc(const uuid_t *uuid,
+struct fip_image_desc *fip_new_image_desc(const uuid_t *uuid,
 			     const char *name, const char *cmdline_name)
 {
 	struct fip_image_desc *desc;
@@ -39,7 +39,7 @@ struct fip_image_desc *new_image_desc(const uuid_t *uuid,
 	return desc;
 }
 
-void set_image_desc_action(struct fip_image_desc *desc, int action,
+void fip_set_image_desc_action(struct fip_image_desc *desc, int action,
     const char *arg)
 {
 	ASSERT(desc != NULL);
@@ -52,7 +52,7 @@ void set_image_desc_action(struct fip_image_desc *desc, int action,
 		desc->action_arg = xstrdup(arg);
 }
 
-void free_image_desc(struct fip_image_desc *desc)
+void fip_free_image_desc(struct fip_image_desc *desc)
 {
 	free(desc->name);
 	free(desc->cmdline_name);
@@ -64,7 +64,7 @@ void free_image_desc(struct fip_image_desc *desc)
 	free(desc);
 }
 
-void add_image_desc(struct fip_state *fip, struct fip_image_desc *desc)
+void fip_add_image_desc(struct fip_state *fip, struct fip_image_desc *desc)
 {
 	list_add_tail(&desc->list, &fip->descs);
 	fip->nr_image_descs++;
@@ -86,7 +86,7 @@ void fip_free(struct fip_state *fip)
 	struct fip_image_desc *desc, *tmp;
 
 	fip_for_each_desc_safe(fip, desc, tmp) {
-		free_image_desc(desc);
+		fip_free_image_desc(desc);
 		fip->nr_image_descs--;
 	}
 
@@ -95,7 +95,7 @@ void fip_free(struct fip_state *fip)
 	free(fip);
 }
 
-void fill_image_descs(struct fip_state *fip)
+void fip_fill_image_descs(struct fip_state *fip)
 {
 	toc_entry_t *toc_entry;
 
@@ -104,24 +104,24 @@ void fill_image_descs(struct fip_state *fip)
 	     toc_entry++) {
 		struct fip_image_desc *desc;
 
-		desc = new_image_desc(&toc_entry->uuid,
+		desc = fip_new_image_desc(&toc_entry->uuid,
 		    toc_entry->name,
 		    toc_entry->cmdline_name);
-		add_image_desc(fip, desc);
+		fip_add_image_desc(fip, desc);
 	}
 	for (toc_entry = plat_def_toc_entries;
 	     toc_entry->cmdline_name != NULL;
 	     toc_entry++) {
 		struct fip_image_desc *desc;
 
-		desc = new_image_desc(&toc_entry->uuid,
+		desc = fip_new_image_desc(&toc_entry->uuid,
 		    toc_entry->name,
 		    toc_entry->cmdline_name);
-		add_image_desc(fip, desc);
+		fip_add_image_desc(fip, desc);
 	}
 }
 
-struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
+struct fip_image_desc *fip_lookup_image_desc_from_uuid(struct fip_state *fip,
 						 const uuid_t *uuid)
 {
 	struct fip_image_desc *desc;
@@ -132,7 +132,7 @@ struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
 	return NULL;
 }
 
-struct fip_image_desc *lookup_image_desc_from_opt(struct fip_state *fip, char **arg)
+struct fip_image_desc *fip_lookup_image_desc_from_opt(struct fip_state *fip, char **arg)
 {
 	int len = 0;
 	struct fip_image_desc *desc;
@@ -153,7 +153,7 @@ struct fip_image_desc *lookup_image_desc_from_opt(struct fip_state *fip, char **
 	return NULL;
 }
 
-int parse_fip(struct fip_state *fip,
+int fip_parse(struct fip_state *fip,
 		     const char *filename, fip_toc_header_t *toc_header_out)
 {
 	struct stat st;
@@ -238,17 +238,17 @@ int parse_fip(struct fip_state *fip,
 		    toc_entry->size);
 
 		/* If this is an unknown image, create a descriptor for it. */
-		desc = lookup_image_desc_from_uuid(fip, &toc_entry->uuid);
+		desc = fip_lookup_image_desc_from_uuid(fip, &toc_entry->uuid);
 		if (desc == NULL) {
 			char name[UUID_STRING_LEN + 1], filename[PATH_MAX];
 
 			snprintf(name, sizeof(name), "%pU", &toc_entry->uuid);
 			snprintf(filename, sizeof(filename), "%s%s",
 			    name, ".bin");
-			desc = new_image_desc(&toc_entry->uuid, name, "blob");
+			desc = fip_new_image_desc(&toc_entry->uuid, name, "blob");
 			desc->action = DO_UNPACK;
 			desc->action_arg = xstrdup(filename);
-			add_image_desc(fip, desc);
+			fip_add_image_desc(fip, desc);
 		}
 
 		ASSERT(desc->image == NULL);
@@ -266,7 +266,7 @@ int parse_fip(struct fip_state *fip,
 	return 0;
 }
 
-static struct fip_image *read_image_from_file(const uuid_t *uuid, const char *filename)
+static struct fip_image *fip_read_image_from_file(const uuid_t *uuid, const char *filename)
 {
 	struct stat st;
 	struct fip_image *image;
@@ -299,7 +299,7 @@ static struct fip_image *read_image_from_file(const uuid_t *uuid, const char *fi
 	return image;
 }
 
-int pack_images(struct fip_state *fip,
+int fip_pack_images(struct fip_state *fip,
 		const char *filename,
 		uint64_t toc_flags, unsigned long align)
 {
@@ -400,7 +400,7 @@ int pack_images(struct fip_state *fip,
  * in update_fip() creating the new FIP file from scratch because the
  * internal image table is not populated.
  */
-int update_fip(struct fip_state *fip)
+int fip_update(struct fip_state *fip)
 {
 	struct fip_image_desc *desc;
 
@@ -411,7 +411,7 @@ int update_fip(struct fip_state *fip)
 		if (desc->action != DO_PACK)
 			continue;
 
-		image = read_image_from_file(&desc->uuid,
+		image = fip_read_image_from_file(&desc->uuid,
 		    desc->action_arg);
 		if (!image)
 			return -1;

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:15 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:15 +0100
Subject: [PATCH v2 02/20] ARM: k3: add function to detect eMMC boot
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-2-8dd1bb0ce60a@pengutronix.de>

Booting from eMMC on K3 SoCs requires some special handling. With SD
card boot we put the environment in the boot FAT partition whereas with
eMMC boot we want to put it into the raw eMMC device. Also with eMMC
boot we have to load the subsequent stages from the eMMC boot partitions
and from the boot FAT otherwise. Add a function to detect eMMC boot
to base these decisions on.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/common.c | 13 +++++++++++++
 include/mach/k3/common.h  |  1 +
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index c779e873c9..7ded1f3f04 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -162,6 +162,19 @@ void am625_get_bootsource(enum bootsource *src, int *instance)
 	k3_get_bootsource(devstat, src, instance);
 }
 
+bool k3_boot_is_emmc(void)
+{
+	u32 bootmode = readl(AM625_BOOT_PARAM_TABLE_INDEX_OCRAM);
+	u32 devstat = readl(AM625_CTRLMMR_MAIN_DEVSTAT);
+
+	if (bootmode != K3_PRIMARY_BOOTMODE)
+		return false;
+	if (FIELD_GET(MAIN_DEVSTAT_PRIMARY_BOOTMODE, devstat) != BOOT_DEVICE_EMMC)
+		return false;
+
+	return true;
+}
+
 static void of_delete_node_path(struct device_node *root, const char *path)
 {
 	struct device_node *np;
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index 3377dc8895..7f0796f7f4 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -4,6 +4,7 @@
 #include <bootsource.h>
 
 void am625_get_bootsource(enum bootsource *src, int *instance);
+bool k3_boot_is_emmc(void);
 u64 am625_sdram_size(void);
 void am625_register_dram(void);
 void am625_enable_32k_crystal(void);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:19 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:19 +0100
Subject: [PATCH v2 06/20] fip: use uuid_equal() and uuid_is_null()
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-6-8dd1bb0ce60a@pengutronix.de>

We have uuid_equal() and uuid_is_null(), use that rather than open coded
memcmp().

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 commands/fiptool.c | 10 ++++------
 lib/fip.c          |  4 ++--
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/commands/fiptool.c b/commands/fiptool.c
index 45d534e470..b917c62a97 100644
--- a/commands/fiptool.c
+++ b/commands/fiptool.c
@@ -219,8 +219,7 @@ static __maybe_unused int create_cmd(struct fip_state *fip, int argc, char *argv
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
 
-			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
-			    filename[0] == '\0')
+			if (uuid_is_null(&uuid) || filename[0] == '\0')
 				return COMMAND_ERROR_USAGE;
 
 			desc = lookup_image_desc_from_uuid(fip, &uuid);
@@ -286,7 +285,7 @@ static __maybe_unused int update_cmd(struct fip_state *fip, int argc, char *argv
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
 
-			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
+			if (uuid_is_null(&uuid) ||
 			    filename[0] == '\0')
 				return COMMAND_ERROR_USAGE;
 
@@ -368,8 +367,7 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
 
-			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
-			    filename[0] == '\0')
+			if (uuid_is_null(&uuid) || filename[0] == '\0')
 				return COMMAND_ERROR_USAGE;
 
 			desc = lookup_image_desc_from_uuid(fip, &uuid);
@@ -478,7 +476,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 			parse_blob_opt(optarg, &uuid,
 			    filename, sizeof(filename));
 
-			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
+			if (uuid_is_null(&uuid))
 				return COMMAND_ERROR_USAGE;
 
 			desc = lookup_image_desc_from_uuid(fip, &uuid);
diff --git a/lib/fip.c b/lib/fip.c
index 63f1469086..774de2ad1d 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -127,7 +127,7 @@ struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
 	struct fip_image_desc *desc;
 
 	fip_for_each_desc(fip, desc)
-		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
+		if (uuid_equal(&desc->uuid, uuid))
 			return desc;
 	return NULL;
 }
@@ -210,7 +210,7 @@ int parse_fip(struct fip_state *fip,
 		struct fip_image_desc *desc;
 
 		/* Found the ToC terminator, we are done. */
-		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
+		if (uuid_is_null(&toc_entry->uuid)) {
 			terminated = 1;
 			break;
 		}

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:18 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:18 +0100
Subject: [PATCH v2 05/20] fip: use linux list implementation
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-5-8dd1bb0ce60a@pengutronix.de>

Replace open coded list handling with Linux list implementation.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 commands/fiptool.c | 16 ++++++++--------
 include/fiptool.h  | 16 ++++++++++++----
 lib/fip.c          | 40 +++++++++++++++++++++++-----------------
 3 files changed, 43 insertions(+), 29 deletions(-)

diff --git a/commands/fiptool.c b/commands/fiptool.c
index a4370c9eef..45d534e470 100644
--- a/commands/fiptool.c
+++ b/commands/fiptool.c
@@ -73,7 +73,7 @@ static int info_cmd(struct fip_state *fip, int argc, char *argv[])
 	pr_verbose("toc_header[flags]: 0x%llX\n",
 	    (unsigned long long)toc_header.flags);
 
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+	fip_for_each_desc(fip, desc) {
 		struct fip_image *image = desc->image;
 
 		if (image == NULL)
@@ -409,7 +409,7 @@ static int unpack_cmd(struct fip_state *fip, int argc, char *argv[])
 		}
 
 	/* Unpack all specified images. */
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+	fip_for_each_desc(fip, desc) {
 		char file[PATH_MAX];
 		struct fip_image *image = desc->image;
 
@@ -517,7 +517,7 @@ static __maybe_unused int remove_cmd(struct fip_state *fip, int argc, char *argv
 	if (ret)
 		return ret;
 
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+	fip_for_each_desc(fip, desc) {
 		if (desc->action != DO_REMOVE)
 			continue;
 
@@ -548,7 +548,7 @@ static cmd_t cmds[] = {
 static int do_fiptool(int argc, char *argv[])
 {
 	int i, opt, ret = 0;
-	struct fip_state fip = {};
+	struct fip_state *fip = fip_new();
 
 	/*
 	 * Set POSIX mode so getopt stops at the first non-option
@@ -557,7 +557,7 @@ static int do_fiptool(int argc, char *argv[])
 	while ((opt = getopt(argc, argv, "+v")) > 0) {
 		switch (opt) {
 		case 'v':
-			fip.verbose = 1;
+			fip->verbose = 1;
 			break;
 		default:
 			return COMMAND_ERROR_USAGE;
@@ -569,14 +569,14 @@ static int do_fiptool(int argc, char *argv[])
 	if (argc == 0)
 		return COMMAND_ERROR_USAGE;
 
-	fill_image_descs(&fip);
+	fill_image_descs(fip);
 	for (i = 0; i < ARRAY_SIZE(cmds); i++) {
 		if (strcmp(cmds[i].name, argv[0]) == 0) {
 			struct getopt_context gc;
 
 			getopt_context_store(&gc);
 
-			ret = cmds[i].handler(&fip, argc, argv);
+			ret = cmds[i].handler(fip, argc, argv);
 
 			getopt_context_restore(&gc);
 			break;
@@ -585,7 +585,7 @@ static int do_fiptool(int argc, char *argv[])
 
 	if (i == ARRAY_SIZE(cmds))
 		return COMMAND_ERROR_USAGE;
-	free_image_descs(&fip);
+	fip_free(fip);
 	return ret;
 }
 
diff --git a/include/fiptool.h b/include/fiptool.h
index 6f1d69d178..5a3fdee6e0 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -8,6 +8,7 @@
 
 #include <linux/uuid.h>
 #include <fip.h>
+#include <linux/list.h>
 
 enum {
 	DO_UNSPEC = 0,
@@ -23,7 +24,7 @@ struct fip_image_desc {
 	int                action;
 	char              *action_arg;
 	struct fip_image  *image;
-	struct fip_image_desc *next;
+	struct list_head  list;
 };
 
 struct fip_image {
@@ -32,7 +33,7 @@ struct fip_image {
 };
 
 struct fip_state {
-	struct fip_image_desc *image_desc_head;
+	struct list_head descs;
 	size_t nr_image_descs;
 	int verbose;
 };
@@ -45,6 +46,9 @@ struct fip_state {
 	} \
 } while (0)
 
+struct fip_state *fip_new(void);
+void fip_free(struct fip_state *fip);
+
 struct fip_image_desc *new_image_desc(const uuid_t *uuid,
 			     const char *name, const char *cmdline_name);
 
@@ -55,8 +59,6 @@ void free_image_desc(struct fip_image_desc *desc);
 
 void add_image_desc(struct fip_state *fip, struct fip_image_desc *desc);
 
-void free_image_descs(struct fip_state *fip);
-
 void fill_image_descs(struct fip_state *fip);
 
 struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
@@ -84,4 +86,10 @@ typedef struct toc_entry {
 extern toc_entry_t toc_entries[];
 extern toc_entry_t plat_def_toc_entries[];
 
+#define fip_for_each_desc(fip, e) \
+        list_for_each_entry(e, &(fip)->descs, list)
+
+#define fip_for_each_desc_safe(fip, e, tmp) \
+        list_for_each_entry_safe(e, tmp, &(fip)->descs, list)
+
 #endif /* FIPTOOL_H */
diff --git a/lib/fip.c b/lib/fip.c
index e7589ff4c2..63f1469086 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -66,27 +66,33 @@ void free_image_desc(struct fip_image_desc *desc)
 
 void add_image_desc(struct fip_state *fip, struct fip_image_desc *desc)
 {
-	struct fip_image_desc **p = &fip->image_desc_head;
+	list_add_tail(&desc->list, &fip->descs);
+	fip->nr_image_descs++;
+}
 
-	while (*p)
-		p = &(*p)->next;
+struct fip_state *fip_new(void)
+{
+	struct fip_state *fip;
 
-	ASSERT(*p == NULL);
-	*p = desc;
-	fip->nr_image_descs++;
+	fip = xzalloc(sizeof(*fip));
+
+	INIT_LIST_HEAD(&fip->descs);
+
+	return fip;
 }
 
-void free_image_descs(struct fip_state *fip)
+void fip_free(struct fip_state *fip)
 {
-	struct fip_image_desc *desc = fip->image_desc_head, *tmp;
+	struct fip_image_desc *desc, *tmp;
 
-	while (desc != NULL) {
-		tmp = desc->next;
+	fip_for_each_desc_safe(fip, desc, tmp) {
 		free_image_desc(desc);
-		desc = tmp;
 		fip->nr_image_descs--;
 	}
+
 	ASSERT(fip->nr_image_descs == 0);
+
+	free(fip);
 }
 
 void fill_image_descs(struct fip_state *fip)
@@ -120,7 +126,7 @@ struct fip_image_desc *lookup_image_desc_from_uuid(struct fip_state *fip,
 {
 	struct fip_image_desc *desc;
 
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next)
+	fip_for_each_desc(fip, desc)
 		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
 			return desc;
 	return NULL;
@@ -135,7 +141,7 @@ struct fip_image_desc *lookup_image_desc_from_opt(struct fip_state *fip, char **
 	eq = strchrnul(*arg, '=');
 	len = eq - *arg;
 
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+	fip_for_each_desc(fip, desc) {
 		if (strncmp(desc->cmdline_name, *arg, len) == 0) {
 			if (*eq)
 				*arg = eq + 1;
@@ -305,7 +311,7 @@ int pack_images(struct fip_state *fip,
 	uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
 	size_t nr_images = 0;
 
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next)
+	fip_for_each_desc(fip, desc)
 		if (desc->image != NULL)
 			nr_images++;
 
@@ -324,7 +330,7 @@ int pack_images(struct fip_state *fip,
 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
 
 	entry_offset = buf_size;
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+	fip_for_each_desc(fip, desc) {
 		struct fip_image *image = desc->image;
 
 		if (image == NULL || (image->toc_e.size == 0ULL))
@@ -360,7 +366,7 @@ int pack_images(struct fip_state *fip,
 
 	pr_verbose("Payload size: %llu bytes\n", payload_size);
 
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+	fip_for_each_desc(fip, desc) {
 		struct fip_image *image = desc->image;
 
 		if (image == NULL)
@@ -399,7 +405,7 @@ int update_fip(struct fip_state *fip)
 	struct fip_image_desc *desc;
 
 	/* Add or replace images in the FIP file. */
-	for (desc = fip->image_desc_head; desc != NULL; desc = desc->next) {
+	fip_for_each_desc(fip, desc) {
 		struct fip_image *image;
 
 		if (desc->action != DO_PACK)

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:29 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:29 +0100
Subject: [PATCH v2 16/20] serial: omap: Use ttyS as Linux console name
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-16-8dd1bb0ce60a@pengutronix.de>

Traditionally Linux used ttyO as console name for Omap devices. This has
been changed to ttyS in 2014. Since then ttyO gets translated to ttyS by
the Kernel. Use ttyS directly to avoid the translation in the Kernel.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/serial/serial_ns16550.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index 45341d1c9b..56a1c6c6b9 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -402,13 +402,13 @@ static struct ns16550_drvdata ns16550_drvdata = {
 
 static __maybe_unused struct ns16550_drvdata omap_drvdata = {
 	.init_port = ns16550_omap_init_port,
-	.linux_console_name = "ttyO",
+	.linux_console_name = "ttyS",
 	.linux_earlycon_name = "omap8250",
 };
 
 static __maybe_unused struct ns16550_drvdata omap_clk48m_drvdata = {
 	.init_port = ns16550_omap_init_port,
-	.linux_console_name = "ttyO",
+	.linux_console_name = "ttyS",
 	.clk_default = 48000000,
 };
 

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:32 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:32 +0100
Subject: [PATCH v2 19/20] ARM: beagleplay: cleanup board entry
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-19-8dd1bb0ce60a@pengutronix.de>

We used to genrate a Linux Kernel compatible image that can be started
from U-Boot. This is no longer necessary as we have full 1st stage
support now in barebox. A FIT image to be started from U-Boot can still
be generated with BOARD_GENERIC_FIT.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/boards/beagleplay/Makefile   |  1 -
 arch/arm/boards/beagleplay/entry.S    | 29 -----------------------------
 arch/arm/boards/beagleplay/lowlevel.c | 18 ++++++------------
 3 files changed, 6 insertions(+), 42 deletions(-)

diff --git a/arch/arm/boards/beagleplay/Makefile b/arch/arm/boards/beagleplay/Makefile
index 396dff29a2..a8c7320bdb 100644
--- a/arch/arm/boards/beagleplay/Makefile
+++ b/arch/arm/boards/beagleplay/Makefile
@@ -1,3 +1,2 @@
 pbl-y += lowlevel.o
-pbl-$(CONFIG_MACH_K3_CORTEX_A) += entry.o
 pbl-$(CONFIG_MACH_K3_CORTEX_R5) += entry-r5.o ddr.o
diff --git a/arch/arm/boards/beagleplay/entry.S b/arch/arm/boards/beagleplay/entry.S
deleted file mode 100644
index 6e4c7196f3..0000000000
--- a/arch/arm/boards/beagleplay/entry.S
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include <linux/linkage.h>
-#include <asm/barebox-arm64.h>
-#include <asm/image.h>
-
-#define IMAGE_FLAGS \
-	(ARM64_IMAGE_FLAG_PAGE_SIZE_4K << ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT) | \
-	(ARM64_IMAGE_FLAG_PHYS_BASE << ARM64_IMAGE_FLAG_PHYS_BASE_SHIFT)
-
-.section .text_head_entry_start_beagleplay
-ENTRY("start_beagleplay")
-	adr x1, 0	   	   /* code0 */
-	b 2f                       /* code1 */
-	.xword 0x80000             /* Image load offset */
-	.xword _barebox_image_size /* Effective Image size */
-	.xword IMAGE_FLAGS	   /* Kernel flags */
-	.xword 0                   /* reserved */
-	.xword 0                   /* reserved */
-	.xword 0                   /* reserved */
-	.ascii ARM64_IMAGE_MAGIC   /* magic number */
-	.int   0                   /* reserved (PE-COFF offset) */
-	.asciz "barebox"	   /* unused for now */
-2:
-	mov sp, x1
-	/* Stack now grows into the 0x80000 image load offset specified
-	 * above. This is more than enough until FDT /memory is decoded.
-	 */
-	b beagleplay
-ENTRY_PROC_END(start_beagleplay)
diff --git a/arch/arm/boards/beagleplay/lowlevel.c b/arch/arm/boards/beagleplay/lowlevel.c
index 744f78d009..9430017568 100644
--- a/arch/arm/boards/beagleplay/lowlevel.c
+++ b/arch/arm/boards/beagleplay/lowlevel.c
@@ -10,27 +10,21 @@
 #include <compressed-dtb.h>
 #include <cache.h>
 #include <mach/k3/r5.h>
+#include <mach/k3/common.h>
 
 #include "ddr.h"
 
-/* Called from assembly */
-void beagleplay(void *dtb);
-
-static noinline void beagleplay_continue(void *dtb)
+static noinline void beagleplay_continue(void)
 {
-	unsigned long membase, memsize;
+	unsigned long membase = 0x80000000, memsize;
 	extern char __dtb_k3_am625_beagleplay_start[];
-	unsigned int size;
-
-	fdt_find_mem(__dtb_k3_am625_beagleplay_start, &membase, &memsize);
 
-	if (blob_is_valid_fdt_ptr(dtb, membase, memsize, &size))
-		handoff_data_add(HANDOFF_DATA_EXTERNAL_DT, dtb, size);
+	memsize = am625_sdram_size();
 
 	barebox_arm_entry(membase, memsize, __dtb_k3_am625_beagleplay_start);
 }
 
-void beagleplay(void *dtb)
+ENTRY_FUNCTION_WITHSTACK(start_beagleplay, 0x80800000, r0, r1, r2)
 {
 	putc_ll('>');
 
@@ -40,7 +34,7 @@ void beagleplay(void *dtb)
 
 	setup_c();
 
-	beagleplay_continue(dtb);
+	beagleplay_continue();
 }
 
 extern char __dtb_k3_am625_r5_beagleplay_start[];

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:30 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:30 +0100
Subject: [PATCH v2 17/20] ARM: k3: remove beagleplay FIT image
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-17-8dd1bb0ce60a@pengutronix.de>

Remove beagleplay FIT image to avoid the dependency to U-Boot mkimage.
We can still build a FIT image using the generic-dt-2nd support.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 images/Makefile.k3             |  4 ----
 images/k3-am625-beagleplay.its | 29 -----------------------------
 2 files changed, 33 deletions(-)

diff --git a/images/Makefile.k3 b/images/Makefile.k3
index 466a84af99..b27b3dfcc5 100644
--- a/images/Makefile.k3
+++ b/images/Makefile.k3
@@ -15,10 +15,6 @@ pblb-$(CONFIG_MACH_BEAGLEPLAY) += start_beagleplay
 FILE_barebox-beagleplay.img = start_beagleplay.pblb
 image-$(CONFIG_MACH_BEAGLEPLAY) += barebox-beagleplay.img
 
-$(obj)/k3-am625-beagleplay.itb: $(obj)/barebox-beagleplay.img
-FILE_barebox-beagleplay-fit.img = k3-am625-beagleplay.itb
-image-$(CONFIG_MACH_BEAGLEPLAY) += barebox-beagleplay-fit.img
-
 endif
 
 ifdef CONFIG_MACH_K3_CORTEX_R5
diff --git a/images/k3-am625-beagleplay.its b/images/k3-am625-beagleplay.its
deleted file mode 100644
index 987d4d1660..0000000000
--- a/images/k3-am625-beagleplay.its
+++ /dev/null
@@ -1,29 +0,0 @@
-
-/dts-v1/;
-
-/ {
-	description = "barebox for BeaglePlay board";
-
-	images {
-		barebox {
-			description = "barebox for BeaglePlay board";
-			type = "firmware";
-			os = "linux";
-			arch = "arm";
-			compression = "none";
-			load = <0x80800000>;
-			entry = <0x80800000>;
-			data = /incbin/("barebox-beagleplay.img");
-		};
-	};
-
-	configurations {
-		default = "conf-0";
-
-		conf-0 {
-			description = "barebox for BeaglePlay board";
-			firmware = "barebox";
-			loadables = "barebox";
-		};
-	};
-};

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:27 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:27 +0100
Subject: [PATCH v2 14/20] ARM: k3: add eMMC barebox update handler
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-14-8dd1bb0ce60a@pengutronix.de>

This adds a barebox update handler to write a barebox image to the
eMMC boot partitions. The image is written to the currently inactive
boot partition which is made active after a successful write thus
enabling a failsafe update.

The update handler expects an image which has the tiboot3.bin right
at the start of the image and a FIP image containing the next stages
at offset 1MiB. This image can't be generated by barebox itself (as
it requires two barebox images built for different architectures). It
must be generated by an external build system.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/Makefile |  1 +
 arch/arm/mach-k3/bbu.c    | 77 +++++++++++++++++++++++++++++++++++++++++++++++
 include/mach/k3/common.h  | 13 ++++++++
 3 files changed, 91 insertions(+)

diff --git a/arch/arm/mach-k3/Makefile b/arch/arm/mach-k3/Makefile
index 8120c6fd35..b1dfb66d74 100644
--- a/arch/arm/mach-k3/Makefile
+++ b/arch/arm/mach-k3/Makefile
@@ -1,6 +1,7 @@
 obj-y += common.o
 obj-pbl-$(CONFIG_MACH_K3_CORTEX_R5) += r5.o
 obj-pbl-y += ddrss.o
+obj-$(CONFIG_BAREBOX_UPDATE) += bbu.o
 
 extra-$(CONFIG_MACH_K3_CORTEX_R5) += combined-dm-cfg-am625.k3cfg combined-sysfw-cfg-am625.k3cfg
 
diff --git a/arch/arm/mach-k3/bbu.c b/arch/arm/mach-k3/bbu.c
new file mode 100644
index 0000000000..815af086e8
--- /dev/null
+++ b/arch/arm/mach-k3/bbu.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "k3-bbu: " fmt
+
+#include <bbu.h>
+#include <xfuncs.h>
+#include <fcntl.h>
+#include <filetype.h>
+#include <linux/printk.h>
+#include <unistd.h>
+#include <mach/k3/common.h>
+#include <linux/sizes.h>
+#include <libfile.h>
+
+static int k3_bbu_mmc_update(struct bbu_handler *handler,
+				  struct bbu_data *data)
+{
+	int fd, ret;
+	enum filetype type;
+
+	if (data->len < K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE + SZ_1K) {
+		pr_err("Image is too small\n");
+		return -EINVAL;
+	}
+
+	type = file_detect_type(data->image + K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE, SZ_1K);
+
+	if (type != filetype_fip) {
+		pr_err("Cannot find FIP image at offset 1M\n");
+		return -EINVAL;
+	}
+
+	pr_debug("Attempting eMMC boot partition update\n");
+
+	ret = bbu_confirm(data);
+	if (ret)
+		return ret;
+
+	fd = open(data->devicefile, O_RDWR);
+	if (fd < 0)
+		return fd;
+
+	ret = pwrite_full(fd, data->image, data->len, 0);
+	if (ret < 0)
+		pr_err("writing to %s failed with %pe\n", data->devicefile, ERR_PTR(ret));
+
+	close(fd);
+
+	return ret < 0 ? ret : 0;
+}
+
+static int k3_bbu_mmc_fip_handler(struct bbu_handler *handler,
+				       struct bbu_data *data)
+{
+	return bbu_mmcboot_handler(handler, data, k3_bbu_mmc_update);
+}
+
+int k3_bbu_emmc_register(const char *name,
+			 const char *devicefile,
+			 unsigned long flags)
+{
+	struct bbu_handler *handler;
+	int ret;
+
+        handler = xzalloc(sizeof(*handler));
+
+        handler->flags = flags | BBU_HANDLER_FLAG_MMC_BOOT_ACK;
+        handler->devicefile = devicefile;
+        handler->name = name;
+        handler->handler = k3_bbu_mmc_fip_handler;
+
+        ret = bbu_register_handler(handler);
+        if (ret)
+                free(handler);
+
+        return ret;
+}
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index 14dfc4a28a..871e9f39e3 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -16,4 +16,17 @@ void am625_enable_32k_crystal(void);
 
 #define K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE	SZ_1M
 
+#ifdef CONFIG_BAREBOX_UPDATE
+int k3_bbu_emmc_register(const char *name,
+			 const char *devicefile,
+			 unsigned long flags);
+#else
+static inline int k3_bbu_emmc_register(const char *name,
+				       const char *devicefile,
+				       unsigned long flags)
+{
+	return 0;
+}
+#endif
+
 #endif /* __MACH_K3_COMMON_H */

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:25 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:25 +0100
Subject: [PATCH v2 12/20] mci: am654: parse generic mmc node properties
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-12-8dd1bb0ce60a@pengutronix.de>

Call mci_of_parse_node() to parse generic node properties like
max-frequency to lower the maximum allowed frequency.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/mci/am654-sdhci.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mci/am654-sdhci.c b/drivers/mci/am654-sdhci.c
index 9787642011..2c1fa5d804 100644
--- a/drivers/mci/am654-sdhci.c
+++ b/drivers/mci/am654-sdhci.c
@@ -594,6 +594,7 @@ static int am654_sdhci_probe(struct device *dev)
 	mci = &plat->mci;
 	mci->f_max = clk_get_rate(plat->clk);
 	mci->f_min = 50000000 / 256;
+	mci_of_parse_node(mci, np);
 
 	if (plat->soc_data->flags & DLL_PRESENT) {
 		ret = of_property_read_u32(np, "ti,trm-icp", &plat->trm_icp);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:31 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:31 +0100
Subject: [PATCH v2 18/20] ARM: am625-sk: cleanup board entry
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-18-8dd1bb0ce60a@pengutronix.de>

We used to genrate a Linux Kernel compatible image that can be started
from U-Boot. This is no longer necessary as we have full 1st stage
support now in barebox. A FIT image to be started from U-Boot can still
be generated with BOARD_GENERIC_FIT.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/boards/am625-sk/Makefile   |  1 -
 arch/arm/boards/am625-sk/entry.S    | 29 -----------------------------
 arch/arm/boards/am625-sk/lowlevel.c | 13 +++----------
 3 files changed, 3 insertions(+), 40 deletions(-)

diff --git a/arch/arm/boards/am625-sk/Makefile b/arch/arm/boards/am625-sk/Makefile
index 8c45b1e154..8cba450528 100644
--- a/arch/arm/boards/am625-sk/Makefile
+++ b/arch/arm/boards/am625-sk/Makefile
@@ -1,4 +1,3 @@
 pbl-y += lowlevel.o
 obj-y += board.o
-pbl-$(CONFIG_MACH_K3_CORTEX_A) += entry.o
 pbl-$(CONFIG_MACH_K3_CORTEX_R5) += entry-r5.o am625-sk-ddr.o am625sip-sk-ddr.o
diff --git a/arch/arm/boards/am625-sk/entry.S b/arch/arm/boards/am625-sk/entry.S
deleted file mode 100644
index 5fc9297d50..0000000000
--- a/arch/arm/boards/am625-sk/entry.S
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-#include <linux/linkage.h>
-#include <asm/barebox-arm64.h>
-#include <asm/image.h>
-
-#define IMAGE_FLAGS \
-	(ARM64_IMAGE_FLAG_PAGE_SIZE_4K << ARM64_IMAGE_FLAG_PAGE_SIZE_SHIFT) | \
-	(ARM64_IMAGE_FLAG_PHYS_BASE << ARM64_IMAGE_FLAG_PHYS_BASE_SHIFT)
-
-.section .text_head_entry_start_vivavis_cu33d
-ENTRY("start_am625_sk")
-	adr x1, 0	   	   /* code0 */
-	b 2f                       /* code1 */
-	.xword 0x80000             /* Image load offset */
-	.xword _barebox_image_size /* Effective Image size */
-	.xword IMAGE_FLAGS	   /* Kernel flags */
-	.xword 0                   /* reserved */
-	.xword 0                   /* reserved */
-	.xword 0                   /* reserved */
-	.ascii ARM64_IMAGE_MAGIC   /* magic number */
-	.int   0                   /* reserved (PE-COFF offset) */
-	.asciz "barebox"	   /* unused for now */
-2:
-	mov sp, x1
-	/* Stack now grows into the 0x80000 image load offset specified
-	 * above. This is more than enough until FDT /memory is decoded.
-	 */
-	b am625_sk
-ENTRY_PROC_END(start_am625_sk)
diff --git a/arch/arm/boards/am625-sk/lowlevel.c b/arch/arm/boards/am625-sk/lowlevel.c
index 5c1c38e325..10da8731ca 100644
--- a/arch/arm/boards/am625-sk/lowlevel.c
+++ b/arch/arm/boards/am625-sk/lowlevel.c
@@ -14,14 +14,10 @@
 
 #include "ddr.h"
 
-/* Called from assembly */
-void am625_sk(void *dtb);
-
-static noinline void am625_sk_continue(void *dtb)
+static noinline void am625_sk_continue(void)
 {
 	unsigned long membase = 0x80000000, memsize;
 	extern char __dtb_z_k3_am625_sk_start[];
-	unsigned int size;
 
 	memsize = am625_sdram_size();
 
@@ -33,13 +29,10 @@ static noinline void am625_sk_continue(void *dtb)
 	if (memsize == SZ_512M)
 		memsize = SZ_512M - 0x04000000; /* substract space needed for TF-A, OP-TEE, ... */
 
-	if (blob_is_valid_fdt_ptr(dtb, membase, memsize, &size))
-		handoff_data_add(HANDOFF_DATA_EXTERNAL_DT, dtb, size);
-
 	barebox_arm_entry(membase, memsize, __dtb_z_k3_am625_sk_start);
 }
 
-void am625_sk(void *dtb)
+ENTRY_FUNCTION_WITHSTACK(start_am625_sk, 0x80800000, r0, r1, r2)
 {
 	putc_ll('>');
 
@@ -49,7 +42,7 @@ void am625_sk(void *dtb)
 
 	setup_c();
 
-	am625_sk_continue(dtb);
+	am625_sk_continue();
 }
 
 static noinline void am625_sk_r5_continue(void)

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:33 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:33 +0100
Subject: [PATCH v2 20/20] ARM: k3: Add k3-r5_defconfig
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-20-8dd1bb0ce60a@pengutronix.de>

This adds a defconfig for the initial stage of K3 Socs.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/configs/k3-r5_defconfig | 43 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/arch/arm/configs/k3-r5_defconfig b/arch/arm/configs/k3-r5_defconfig
new file mode 100644
index 0000000000..59b3aa5a6e
--- /dev/null
+++ b/arch/arm/configs/k3-r5_defconfig
@@ -0,0 +1,43 @@
+CONFIG_ARCH_K3=y
+CONFIG_MACH_AM625_SK=y
+CONFIG_MACH_BEAGLEPLAY=y
+CONFIG_AEABI=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+# CONFIG_BOARD_GENERIC_DT is not set
+# CONFIG_MEMINFO is not set
+CONFIG_ENVIRONMENT_VARIABLES=y
+CONFIG_IMAGE_COMPRESSION_XZKERN=y
+CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x10000000
+CONFIG_MALLOC_SIZE=0x0
+CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
+CONFIG_PROMPT="MLO>"
+CONFIG_SHELL_NONE=y
+# CONFIG_ERRNO_MESSAGES is not set
+CONFIG_CONSOLE_ACTIVATE_NONE=y
+CONFIG_PBL_CONSOLE=y
+CONFIG_BTHREAD=y
+CONFIG_DEBUG_LL=y
+CONFIG_DRIVER_SERIAL_NS16550=y
+# CONFIG_SPI is not set
+CONFIG_I2C=y
+CONFIG_I2C_OMAP=y
+CONFIG_USB_HOST=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+# CONFIG_USB_DWC3_OF_SIMPLE is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DFU=y
+CONFIG_MCI=y
+# CONFIG_MCI_WRITE is not set
+CONFIG_MCI_AM654=y
+# CONFIG_TI_SCI_CLK is not set
+CONFIG_MFD_SYSCON=y
+CONFIG_MFD_TPS65219=y
+CONFIG_PINCTRL_SINGLE=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED=y
+CONFIG_REGULATOR_TPS65219=y
+# CONFIG_VIRTIO_MENU is not set
+CONFIG_MAILBOX=y
+CONFIG_FS_FAT=y

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:23 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:23 +0100
Subject: [PATCH v2 10/20] ARM: k3: r5: add USB DFU and eMMC boot support
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-10-8dd1bb0ce60a@pengutronix.de>

This patch adds USB DFU and eMMC boot support for the k3 SoCs.

DFU mode is entered when the SoC is booted from USB. For continuing the
boot we need several binaries (bl31, OP-TEE, barebox, ti-dm firmware),
these can be uploaded as distinct files or combined together as a FIP
image. This patch also adds the possibility to put a FIP image on the
SD/eMMC card which is then preferred over the distinct files which were
previously expected on SD/eMMC cards.

Also the K3 SoCs have a boot mode to boot from eMMC boot partitions for
which this patch adds support. When this bootmode is selected the
tiboot3.bin file is loaded from the active boot partition. We then need
to load the FIP image from the same boot partition. This image is
expected to be at offset 1MiB in the boot partition.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 Documentation/boards/ti-k3.rst |  47 +++++++++
 arch/arm/mach-k3/Kconfig       |   1 +
 arch/arm/mach-k3/r5.c          | 232 +++++++++++++++++++++++++++++++++++------
 include/mach/k3/common.h       |   7 ++
 4 files changed, 256 insertions(+), 31 deletions(-)

diff --git a/Documentation/boards/ti-k3.rst b/Documentation/boards/ti-k3.rst
index a1bf0b92e8..4b3822c020 100644
--- a/Documentation/boards/ti-k3.rst
+++ b/Documentation/boards/ti-k3.rst
@@ -69,6 +69,9 @@ OP-TEE is built from https://github.com/OP-TEE/optee_os.git::
         PLATFORM=k3-am62x
   cp out/arm-plat-k3/core/tee-raw.bin $TI_BOOT/optee.bin
 
+OP-TEE is optional. barebox will continue without ``optee.bin`` when the file
+does not exist.
+
 Copying ti-dm.bin
 -----------------
 
@@ -77,3 +80,47 @@ copied to the eMMC/SD as well::
 
   cp $TI_LINUX_FIRMWARE/ti-dm/am62xx/ipc_echo_testb_mcu1_0_release_strip.xer5f $TI_BOOT/ti-dm.bin
 
+Combining binaries into a FIP image
+-----------------------------------
+
+Alternatively to putting the different binaries (``barebox.bin``, ``bl31.bin``, ``optee.bin``
+and ``ti-dm.bin``) into the FAT image the files can be combined into a FIP image named
+``k3.fip``.::
+
+  fiptool create --soc-fw bl31.bin \
+    --tos-fw optee.bin \
+    --nt-fw barebox-beagleplay.img \
+    --blob uuid=9e8c2017-8b94-4e2b-a7b3-a0f88eabb8ae,file=ti-dm.bin k3.fip
+
+USB DFU boot
+------------
+K3 Boards can be booted via USB DFU. When in USB boot mode the initial stage can be uploaded
+using ``dfu-util``::
+
+  dfu-util -D barebox-beagleplay-r5.img -a bootloader
+
+This will start the initial stage which then expects the following stages which can
+be uploaded with ``dfu-util`` as well, either as FIP image::
+
+  dfu-util -D k3.fip -a fip
+
+or as separate files::
+
+  dfu-util -D blb31.bin -a tfa
+  dfu-util -D optee.bin -a optee
+  dfu-util -D ti-dm.bin -a ti-dm
+  dfu-util -D barebox-beagleplay.img -a barebox
+
+Uploading optee.bin can be skipped in case it's not needed.
+
+eMMC boot
+---------
+K3 boards can boot from eMMC boot partitions. In this mode the ROM reads the tiboot3.bin
+raw from the active boot partition. In this mode barebox expects the FIP image with the
+following stages in the same boot partition at offset 1MiB. There is a barebox update handler
+which takes a combined image consisting of tiboot3.bin and the FIP image to allow for a
+failsafe update. This image can't be generated by the barebox build system though. It has
+to be generated by a build system or manually::
+
+  dd if=images/barebox-beagleplay-r5.img of=barebox-beagleplay-emmc.img
+  dd if=k3.fip of=barebox-beagleplay-emmc.img bs=1024 seek=1024
diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig
index 51b02b697c..50919dc7e3 100644
--- a/arch/arm/mach-k3/Kconfig
+++ b/arch/arm/mach-k3/Kconfig
@@ -15,6 +15,7 @@ config MACH_K3_CORTEX_R5
 	select ARMV7R_MPU
 	select ELF
 	select K3_DDRSS
+	select FIP
 	depends on 32BIT
 	select ARM_USE_COMPRESSED_DTB
 	default y
diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index 32d98fe89a..ced1eb2856 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -6,6 +6,7 @@
 #include <init.h>
 #include <libfile.h>
 #include <fs.h>
+#include <fip.h>
 #include <firmware.h>
 #include <linux/remoteproc.h>
 #include <soc/ti/ti_sci_protocol.h>
@@ -14,6 +15,11 @@
 #include <asm/cache.h>
 #include <linux/sizes.h>
 #include <barebox.h>
+#include <bootsource.h>
+#include <linux/usb/gadget-multi.h>
+#include <mach/k3/common.h>
+#include <mci.h>
+#include <fiptool.h>
 
 #define RTC_BASE_ADDRESS		0x2b1f0000
 #define K3RTC_KICK0_UNLOCK_VALUE	0x83e70b13
@@ -217,38 +223,143 @@ void am625_early_init(void)
 	ti_pd_wait(pd_base, 0);
 }
 
+#if IN_PROPER
+
 /*
  * The bl31 and optee binaries are relocatable, but these addresses
  * are hardcoded as reserved mem regions in the upstream device trees.
  */
-#define BL31_ADDRESS 0x9e780000
-#define OPTEE_ADDRESS 0x9e800000
+#define BL31_ADDRESS (void *)0x9e780000
+#define BL32_ADDRESS (void *)0x9e800000
+#define BAREBOX_ADDRESS (void *)0x80080000
 
-static int k3_r5_start_image(void)
+static void *k3_ti_dm;
+
+static bool have_bl31;
+static bool have_bl32;
+static bool have_bl33;
+
+static uuid_t uuid_bl31 = UUID_EL3_RUNTIME_FIRMWARE_BL31;
+static uuid_t uuid_ti_dm_fw = UUID_TI_DM_FW;
+static uuid_t uuid_bl33 = UUID_NON_TRUSTED_FIRMWARE_BL33;
+static uuid_t uuid_bl32 = UUID_SECURE_PAYLOAD_BL32;
+
+static int load_fip(const char *filename, off_t offset)
 {
-	int err;
-	void *ti_dm_buf;
-	ssize_t size;
-	struct firmware fw;
-	const struct ti_sci_handle *ti_sci;
-	void *bl31 = (void *)BL31_ADDRESS;
-	void *barebox = (void *)0x80080000;
-	void *optee = (void *)OPTEE_ADDRESS;
-	struct elf_image *elf;
-	void __noreturn (*ti_dm)(void);
-	struct rproc *arm64_rproc;
+	struct fip_state *fip;
+	struct fip_image_desc *desc;
 
-	ti_sci = ti_sci_get_handle(NULL);
-	if (IS_ERR(ti_sci))
-		return -EINVAL;
+	fip = fip_image_open(filename, offset);
+	if (IS_ERR(fip)) {
+		pr_err("Cannot open FIP image: %pe\n", fip);
+		return PTR_ERR(fip);
+	}
 
-	arm64_rproc = ti_k3_am64_get_handle();
-	if (!arm64_rproc) {
-		pr_err("Cannot get rproc handle\n");
-		return -EINVAL;
+	fip_for_each_desc(fip, desc) {
+		struct fip_toc_entry *toc_entry = &desc->image->toc_e;
+
+		if (uuid_equal(&toc_entry->uuid, &uuid_bl31)) {
+			memcpy(BL31_ADDRESS, desc->image->buffer, toc_entry->size);
+			have_bl31 = true;
+		}
+
+		if (uuid_equal(&toc_entry->uuid, &uuid_bl33)) {
+			memcpy(BAREBOX_ADDRESS, desc->image->buffer, toc_entry->size);
+			have_bl33 = true;
+		}
+
+		if (uuid_equal(&toc_entry->uuid, &uuid_bl32)) {
+			memcpy(BL32_ADDRESS, desc->image->buffer, toc_entry->size);
+			have_bl32 = true;
+		}
+
+		if (uuid_equal(&toc_entry->uuid, &uuid_ti_dm_fw)) {
+			k3_ti_dm = xmemdup(desc->image->buffer, toc_entry->size);
+		}
 	}
 
-	size = read_file_into_buf("/boot/optee.bin", optee, SZ_32M);
+	fip_free(fip);
+
+	return 0;
+}
+
+static void do_dfu(void)
+{
+	struct usbgadget_funcs funcs = {};
+	int ret;
+	struct stat s;
+	ssize_t size;
+
+	funcs.flags |= USBGADGET_DFU;
+	funcs.dfu_opts = "/optee.bin(optee)c,"
+			 "/bl31.bin(tfa)c,"
+			 "/ti-dm.bin(ti-dm)c,"
+			 "/barebox.bin(barebox)cs,"
+			 "/fip.img(fip)cs";
+
+	ret = usbgadget_prepare_register(&funcs);
+	if (ret)
+		goto err;
+
+	while (1) {
+		if (!have_bl32) {
+			size = read_file_into_buf("/optee.bin", BL32_ADDRESS, SZ_32M);
+			if (size > 0) {
+				printf("Downloaded OP-TEE\n");
+				have_bl32 = true;
+			}
+		}
+
+		if (!have_bl31) {
+			size = read_file_into_buf("/bl31.bin", BL31_ADDRESS, SZ_32M);
+			if (size > 0) {
+				printf("Downloaded TF-A\n");
+				have_bl31 = true;
+			}
+		}
+
+		if (!k3_ti_dm) {
+			ret = read_file_2("/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
+			if (!ret) {
+				printf("Downloaded TI-DM\n");
+			}
+		}
+
+		size = read_file_into_buf("/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
+		if (size > 0) {
+			have_bl33 = true;
+			printf("Downloaded barebox image, DFU done\n");
+			break;
+		}
+
+		ret = stat("/fip.img", &s);
+		if (!ret) {
+			printf("Downloaded FIP image, DFU done\n");
+			load_fip("/fip.img", 0);
+			break;
+		}
+
+		command_slice_release();
+		mdelay(50);
+		command_slice_acquire();
+	};
+
+	return;
+
+err:
+	pr_err("DFU failed with: %pe\n", ERR_PTR(ret));
+}
+
+static int load_images(void)
+{
+	ssize_t size;
+	int err;
+
+	err = load_fip("/boot/k3.fip", 0);
+	if (!err)
+		return 0;
+
+	size = read_file_into_buf("/boot/optee.bin", BL32_ADDRESS, SZ_32M);
 	if (size < 0) {
 		if (size != -ENOENT) {
 			pr_err("Cannot load optee.bin: %pe\n", ERR_PTR(size));
@@ -256,31 +367,89 @@ static int k3_r5_start_image(void)
 		}
 		pr_info("optee.bin not found, continue without\n");
 	} else {
-		pr_debug("Loaded optee.bin (size %u) to 0x%p\n", size, optee);
+		pr_debug("Loaded optee.bin (size %u) to 0x%p\n", size, BL32_ADDRESS);
 	}
 
-	size = read_file_into_buf("/boot/barebox.bin", barebox, optee - barebox);
+	size = read_file_into_buf("/boot/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
 	if (size < 0) {
 		pr_err("Cannot load barebox.bin: %pe\n", ERR_PTR(size));
 		return size;
 	}
-	pr_debug("Loaded barebox.bin (size %u) to 0x%p\n", size, barebox);
+	pr_debug("Loaded barebox.bin (size %u) to 0x%p\n", size, BAREBOX_ADDRESS);
 
-	size = read_file_into_buf("/boot/bl31.bin", bl31, barebox - optee);
+	size = read_file_into_buf("/boot/bl31.bin", BL31_ADDRESS, SZ_32M);
 	if (size < 0) {
 		pr_err("Cannot load bl31.bin: %pe\n", ERR_PTR(size));
 		return size;
 	}
-	pr_debug("Loaded bl31.bin (size %u) to 0x%p\n", size, bl31);
+	pr_debug("Loaded bl31.bin (size %u) to 0x%p\n", size, BL31_ADDRESS);
 
-	err = read_file_2("/boot/ti-dm.bin", &size, &ti_dm_buf, FILESIZE_MAX);
+	err = read_file_2("/boot/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
 	if (err) {
 		pr_err("Cannot load ti-dm.bin: %pe\n", ERR_PTR(err));
 		return err;
 	}
 	pr_debug("Loaded ti-dm.bin (size %u)\n", size);
 
-	elf = elf_open_binary(ti_dm_buf);
+	return 0;
+}
+
+static int load_fip_emmc(void)
+{
+	int bootpart;
+	struct mci *mci;
+	char *fname;
+	const char *mmcdev = "mmc0";
+
+	device_detect_by_name(mmcdev);
+
+	mci = mci_get_device_by_name(mmcdev);
+	if (!mci)
+		return -EINVAL;
+
+	bootpart = mci->bootpart;
+
+	if (bootpart != 1 && bootpart != 2) {
+		pr_err("Unexpected bootpart value %d\n", bootpart);
+		bootpart = 1;
+	}
+
+	fname = xasprintf("/dev/%s.boot%d", mmcdev, bootpart - 1);
+
+	load_fip(fname, K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE);
+
+	free(fname);
+
+	return 0;
+}
+
+static int k3_r5_start_image(void)
+{
+	int err;
+	struct firmware fw;
+	const struct ti_sci_handle *ti_sci;
+	struct elf_image *elf;
+	void __noreturn (*ti_dm)(void);
+	struct rproc *arm64_rproc;
+
+	if (IS_ENABLED(CONFIG_USB_GADGET_DFU) && bootsource_get() == BOOTSOURCE_SERIAL)
+		do_dfu();
+	else if (k3_boot_is_emmc())
+		load_fip_emmc();
+	else
+		load_images();
+
+	ti_sci = ti_sci_get_handle(NULL);
+	if (IS_ERR(ti_sci))
+		return -EINVAL;
+
+	arm64_rproc = ti_k3_am64_get_handle();
+	if (!arm64_rproc) {
+		pr_err("Cannot get rproc handle\n");
+		return -EINVAL;
+	}
+
+	elf = elf_open_binary(k3_ti_dm);
 	if (IS_ERR(elf)) {
 		pr_err("Cannot open ELF image %pe\n", elf);
 		return PTR_ERR(elf);
@@ -292,9 +461,9 @@ static int k3_r5_start_image(void)
 		elf_close(elf);
 	}
 
-	free(ti_dm_buf);
+	free(k3_ti_dm);
 
-	fw.data = bl31;
+	fw.data = BL31_ADDRESS;
 
 	/* Release all the exclusive devices held by SPL before starting ATF */
 	pr_info("Starting TF-A on A53 core\n");
@@ -324,3 +493,4 @@ static int xload(void)
 	hang();
 }
 postenvironment_initcall(xload);
+#endif /* IN_PROPER */
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index 7f0796f7f4..14dfc4a28a 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -2,6 +2,11 @@
 #define __MACH_K3_COMMON_H
 
 #include <bootsource.h>
+#include <linux/sizes.h>
+#include <linux/uuid.h>
+
+#define UUID_TI_DM_FW \
+        UUID_INIT(0x9e8c2017, 0x8b94, 0x4e2b, 0xa7, 0xb3, 0xa0, 0xf8, 0x8e, 0xab, 0xb8, 0xae)
 
 void am625_get_bootsource(enum bootsource *src, int *instance);
 bool k3_boot_is_emmc(void);
@@ -9,4 +14,6 @@ u64 am625_sdram_size(void);
 void am625_register_dram(void);
 void am625_enable_32k_crystal(void);
 
+#define K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE	SZ_1M
+
 #endif /* __MACH_K3_COMMON_H */

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:26 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:26 +0100
Subject: [PATCH v2 13/20] ARM: k3: limit eMMC frequency to 26MHz
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-13-8dd1bb0ce60a@pengutronix.de>

The eMMCs on am625 currently only work reliably with 26MHz. Until this
issue is sorted out limit them to 26MHz on the affected boards
(beagleplay and am625-sk).

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/dts/k3-am625-beagleplay.dts | 4 ++++
 arch/arm/dts/k3-am625-sk.dts         | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/arch/arm/dts/k3-am625-beagleplay.dts b/arch/arm/dts/k3-am625-beagleplay.dts
index 60340ab8ca..73ac950414 100644
--- a/arch/arm/dts/k3-am625-beagleplay.dts
+++ b/arch/arm/dts/k3-am625-beagleplay.dts
@@ -29,3 +29,7 @@ AM62X_IOPAD(0x0224, PIN_INPUT, 0) /* (D22) MMC1_DAT3 */
 		AM62X_IOPAD(0x0240, PIN_INPUT, 0) /* (D17) MMC1_SDCD */
 	>;
 };
+
+&sdhci0 {
+	max-frequency = <26000000>;
+};
diff --git a/arch/arm/dts/k3-am625-sk.dts b/arch/arm/dts/k3-am625-sk.dts
index 1982c34388..56d5681519 100644
--- a/arch/arm/dts/k3-am625-sk.dts
+++ b/arch/arm/dts/k3-am625-sk.dts
@@ -7,3 +7,7 @@
  * DRAM size differs between board variants. Real size is read from DDRSS
  */
 /delete-node/ &{/memory at 80000000};
+
+&sdhci0 {
+	max-frequency = <26000000>;
+};

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:28 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:28 +0100
Subject: [PATCH v2 15/20] ARM: am625-sk: put environment on eMMC when
 booting from it
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-15-8dd1bb0ce60a@pengutronix.de>

When booting from eMMC put the environment on the eMMC as well.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/boards/am625-sk/board.c |  5 +++++
 arch/arm/dts/k3-am625-sk.dts     | 15 +++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/arm/boards/am625-sk/board.c b/arch/arm/boards/am625-sk/board.c
index fd3bcdeac6..c716f30e69 100644
--- a/arch/arm/boards/am625-sk/board.c
+++ b/arch/arm/boards/am625-sk/board.c
@@ -11,6 +11,11 @@ static int am625_sk_probe(struct device *dev)
 {
 	am625_enable_32k_crystal();
 
+	k3_bbu_emmc_register("emmc", "/dev/mmc0", BBU_HANDLER_FLAG_DEFAULT);
+
+	if (k3_boot_is_emmc())
+		of_device_enable_path("/chosen/environment-emmc");
+
 	return 0;
 }
 
diff --git a/arch/arm/dts/k3-am625-sk.dts b/arch/arm/dts/k3-am625-sk.dts
index 56d5681519..8d7a73babf 100644
--- a/arch/arm/dts/k3-am625-sk.dts
+++ b/arch/arm/dts/k3-am625-sk.dts
@@ -3,6 +3,16 @@
 #include <arm64/ti/k3-am625-sk.dts>
 #include "k3-am625.dtsi"
 
+/ {
+	chosen {
+		environment-emmc {
+			compatible = "barebox,environment";
+			device-path = &env_emmc;
+			status = "disabled";
+		};
+	};
+};
+
 /*
  * DRAM size differs between board variants. Real size is read from DDRSS
  */
@@ -10,4 +20,9 @@
 
 &sdhci0 {
 	max-frequency = <26000000>;
+
+	env_emmc: partition at e0000 {
+		label = "barebox-environment";
+		reg = <0x0 0xe0000 0x0 0x20000>;
+	};
 };

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:09:24 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:09:24 +0100
Subject: [PATCH v2 11/20] ARM: am625-sk: enable 32k crystal
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <20250212-k3-emmc-v2-11-8dd1bb0ce60a@pengutronix.de>

The am625-sk board has the 32k crystal equipped. Enable it to source the
RTC from the crystal rather than from the imprecise RC oscillator.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/boards/am625-sk/Makefile |  1 +
 arch/arm/boards/am625-sk/board.c  | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/arch/arm/boards/am625-sk/Makefile b/arch/arm/boards/am625-sk/Makefile
index 1ff9e75a00..8c45b1e154 100644
--- a/arch/arm/boards/am625-sk/Makefile
+++ b/arch/arm/boards/am625-sk/Makefile
@@ -1,3 +1,4 @@
 pbl-y += lowlevel.o
+obj-y += board.o
 pbl-$(CONFIG_MACH_K3_CORTEX_A) += entry.o
 pbl-$(CONFIG_MACH_K3_CORTEX_R5) += entry-r5.o am625-sk-ddr.o am625sip-sk-ddr.o
diff --git a/arch/arm/boards/am625-sk/board.c b/arch/arm/boards/am625-sk/board.c
new file mode 100644
index 0000000000..fd3bcdeac6
--- /dev/null
+++ b/arch/arm/boards/am625-sk/board.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "am625-sk: " fmt
+
+#include <linux/kernel.h>
+#include <mach/k3/common.h>
+#include <driver.h>
+#include <bbu.h>
+
+static int am625_sk_probe(struct device *dev)
+{
+	am625_enable_32k_crystal();
+
+	return 0;
+}
+
+static __maybe_unused struct of_device_id am625_sk_ids[] = {
+	{
+		.compatible = "ti,am625-sk",
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct driver am625_sk_driver = {
+	.name = "am625-sk",
+	.probe = am625_sk_probe,
+	.of_compatible = am625_sk_ids,
+};
+coredevice_platform_driver(am625_sk_driver);

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 12 06:33:53 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 12 Feb 2025 15:33:53 +0100
Subject: Mount NFSv4.2 filesystem in barebox?
In-Reply-To: <CANH4o6Njc3uHE=NbasRJrRr0W5B89R8MTM_BwGwab7t5fNWuaA@mail.gmail.com>
References: <CANH4o6Njc3uHE=NbasRJrRr0W5B89R8MTM_BwGwab7t5fNWuaA@mail.gmail.com>
Message-ID: <Z6yxUVTp0vGWqs7Q@pengutronix.de>

Hi Martin,

On Tue, Feb 11, 2025 at 01:56:58PM +0100, Martin Wege wrote:
> Hello!
> 
> Does barebox have support to mount a NFSv.2 filesystem?

No, not yet. For NFSv4 we would first need TCP support. While we started
to integrate a TCP stack we are not there yet unfortunately.

Regards,
 Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Fri Feb 14 01:48:50 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 10:48:50 +0100
Subject: [PATCH 2/2] mci: core: reset ERASE_GRP_DEF on startup
In-Reply-To: <20250214094850.2847143-1-a.fatoum@pengutronix.de>
References: <20250214094850.2847143-1-a.fatoum@pengutronix.de>
Message-ID: <20250214094850.2847143-2-a.fatoum@pengutronix.de>

EXT_CSD register EXT_CSD_ERASE_GROUP_DEF loses its value after power
cycles and needs to be reset. Quoting the eMMC 5.1 standard[1]:

  After every power-up, when the host uses a device that partition(s)
  are configured, it must set the ERASE_GROUP_DEF bit to high before
  issuing read, write, erase and write protect commands, because this
  bit is reset after power-up. Otherwise, these may not work correctly
  and it may leave the stored data in an unknown state.

[1]: JESD84-B51

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/mci/mci-core.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 6d55eb8305b9..098c67f0102b 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1218,11 +1218,24 @@ static void mci_extract_block_lengths_from_csd(struct mci *mci)
 }
 
 /**
- * Extract erase group size
+ * Configure erase group size
  * @param mci MCI instance
  */
-static void mci_extract_erase_group_size(struct mci *mci)
+static void mci_configure_erase_group_size(struct mci *mci)
 {
+	/* Enable ERASE_GRP_DEF. This bit is lost after a reset or power off.
+	 * This needs to happen even if we don't have erase support compiled-in.
+	 */
+	if (!IS_SD(mci) && mci->version >= MMC_VERSION_4_3) { 
+		int err;
+
+		err = mci_switch(mci, EXT_CSD_ERASE_GROUP_DEF, 1);
+		if (err)
+			dev_warn(&mci->dev, "failed erase group switch\n");
+		else
+			mci->ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+	}
+
 	if (!IS_ENABLED(CONFIG_MCI_ERASE) ||
 	    !(UNSTUFF_BITS(mci->csd, 84, 12) & CCC_ERASE))
 		return;
@@ -1954,7 +1967,7 @@ static int mci_startup(struct mci *mci)
 	dev_info(&mci->dev, "detected %s card version %s\n", IS_SD(mci) ? "SD" : "MMC",
 		mci_version_string(mci));
 	mci_extract_card_capacity_from_csd(mci);
-	mci_extract_erase_group_size(mci);
+	mci_configure_erase_group_size(mci);
 
 	if (IS_SD(mci))
 		err = mci_startup_sd(mci);
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 01:48:49 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 10:48:49 +0100
Subject: [PATCH 1/2] mci: core: import Linux logic for higher preferred erase size
Message-ID: <20250214094850.2847143-1-a.fatoum@pengutronix.de>

As a comment in the file notes, doing too small a granularity for erases
has considerable effect on performance:

  > Example Samsung eMMC 8GTF4:
  >
  >   time erase /dev/mmc2.part_of_512m # 1024 trims
  >   time: 2849ms
  >
  >   time erase /dev/mmc2.part_of_512m # single trim
  >   time: 56ms

This was deemed acceptable at first, because 3 seconds is still
tolerable.

On a SkyHigh S40004, an erase of the whole 3728 MiB ended up
taking longer than 400s in barebox, but only 4s in Linux, which
dwarfs the time actually needed for writing.

Linux has some rather complicated logic to compute a higher erase size
granularity, which still fits in the max busy timeout that a controller
may require. Until that's support in barebox, we import a simpler
heuristic that Linux uses to compute

  /sys/class/mmc_host/*/*/preferred_erase_size

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/mci/mci-core.c | 105 ++++++++++++++++++++++++++---------------
 include/mci.h          |   1 +
 2 files changed, 69 insertions(+), 37 deletions(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index cc3c6fba3653..6d55eb8305b9 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1774,6 +1774,70 @@ static int mci_startup_mmc(struct mci *mci)
 	return ret >= MMC_BUS_WIDTH_1 ? 0 : ret;
 }
 
+static void mci_init_erase(struct mci *card)
+{
+	unsigned int sz;
+
+	if (!IS_ENABLED(CONFIG_MCI_ERASE))
+		return;
+
+	/* TODO: While it's possible to clear many erase groups at once
+	 * and it greatly improves throughput, drivers need adjustment:
+	 *
+	 * Many drivers hardcode a maximal wait time before aborting
+	 * the wait for R1b and returning -ETIMEDOUT. With long
+	 * erases/trims, we are bound to run into this timeout, so for now
+	 * we just split into sufficiently small erases that are unlikely
+	 * to trigger the timeout.
+	 *
+	 * What Linux does and what we should be doing in barebox is:
+	 *
+	 *  - add a struct mci_cmd::busy_timeout member that drivers should
+	 *    use instead of hardcoding their own timeout delay. The busy
+	 *    timeout length can be calculated by the MCI core after
+	 *    consulting the appropriate CSD/EXT_CSD/SSR registers.
+	 *
+	 *  - add a struct mci_host::max_busy_timeout member, where drivers
+	 *    can indicate the maximum timeout they are able to support.
+	 *    The MCI core will never set a busy_timeout that exceeds this
+	 *    value.
+	 *
+	 *  Example Samsung eMMC 8GTF4:
+	 *
+	 *    time erase /dev/mmc2.part_of_512m # 1024 trims
+	 *    time: 2849ms
+	 *
+	 *    time erase /dev/mmc2.part_of_512m # single trim
+	 *    time: 56ms
+	 */
+	if (IS_SD(card) && card->ssr.au) {
+		card->pref_erase = card->ssr.au;
+	} else if (card->erase_grp_size) {
+		sz = card->capacity >> 11;
+		if (sz < 128)
+			card->pref_erase = 512 * 1024 / 512;
+		else if (sz < 512)
+			card->pref_erase = 1024 * 1024 / 512;
+		else if (sz < 1024)
+			card->pref_erase = 2 * 1024 * 1024 / 512;
+		else
+			card->pref_erase = 4 * 1024 * 1024 / 512;
+		if (card->pref_erase < card->erase_grp_size)
+			card->pref_erase = card->erase_grp_size;
+		else {
+			sz = card->pref_erase % card->erase_grp_size;
+			if (sz)
+				card->pref_erase += card->erase_grp_size - sz;
+		}
+	} else {
+		card->pref_erase = 0;
+		return;
+	}
+
+	dev_add_param_uint32_fixed(&card->dev, "preferred_erase_size",
+				   card->pref_erase * 512, "%u");
+}
+
 /**
  * Scan the given host interfaces and detect connected MMC/SD cards
  * @param mci MCI instance
@@ -1903,6 +1967,8 @@ static int mci_startup(struct mci *mci)
 	/* we setup the blocklength only one times for all accesses to this media  */
 	err = mci_set_blocklen(mci, mci->read_bl_len);
 
+	mci_init_erase(mci);
+
 	mci_part_add(mci, mci->capacity, 0,
 			mci->cdevname, NULL, 0, true,
 			MMC_BLK_DATA_AREA_MAIN);
@@ -2080,7 +2146,7 @@ static int mci_sd_erase(struct block_device *blk, sector_t from,
 	struct mci *mci = part->mci;
 	sector_t i = 0;
 	unsigned arg;
-	sector_t blk_max, to = from + blkcnt;
+	sector_t to = from + blkcnt;
 	int rc;
 
 	mci_blk_part_switch(part);
@@ -2106,45 +2172,10 @@ static int mci_sd_erase(struct block_device *blk, sector_t from,
 	/* 'from' and 'to' are inclusive */
 	to -= 1;
 
-	/* TODO: While it's possible to clear many erase groups at once
-	 * and it greatly improves throughput, drivers need adjustment:
-	 *
-	 * Many drivers hardcode a maximal wait time before aborting
-	 * the wait for R1b and returning -ETIMEDOUT. With long
-	 * erases/trims, we are bound to run into this timeout, so for now
-	 * we just split into sufficiently small erases that are unlikely
-	 * to trigger the timeout.
-	 *
-	 * What Linux does and what we should be doing in barebox is:
-	 *
-	 *  - add a struct mci_cmd::busy_timeout member that drivers should
-	 *    use instead of hardcoding their own timeout delay. The busy
-	 *    timeout length can be calculated by the MCI core after
-	 *    consulting the appropriate CSD/EXT_CSD/SSR registers.
-	 *
-	 *  - add a struct mci_host::max_busy_timeout member, where drivers
-	 *    can indicate the maximum timeout they are able to support.
-	 *    The MCI core will never set a busy_timeout that exceeds this
-	 *    value.
-	 *
-	 *  Example Samsung eMMC 8GTF4:
-	 *
-	 *    time erase /dev/mmc2.part_of_512m # 1024 trims
-	 *    time: 2849ms
-	 *
-	 *    time erase /dev/mmc2.part_of_512m # single trim
-	 *    time: 56ms
-	 */
-
-	if (IS_SD(mci) && mci->ssr.au)
-		blk_max = mci->ssr.au;
-	else
-		blk_max = mci->erase_grp_size;
-
 	while (i < blkcnt) {
 		sector_t blk_r;
 
-		blk_r = min(blkcnt - i, blk_max);
+		blk_r = min_t(blkcnt_t, blkcnt - i, mci->pref_erase);
 
 		rc =  mci_block_erase(mci, from + i, blk_r, arg);
 		if (rc)
diff --git a/include/mci.h b/include/mci.h
index 1e3757027406..15fc0f22088f 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -647,6 +647,7 @@ struct mci {
 	/** currently used data block length for write accesses */
 	unsigned write_bl_len;
 	unsigned erase_grp_size;
+	unsigned pref_erase;	/**< preferred erase granularity in blocks */
 	uint64_t capacity;	/**< Card's data capacity in bytes */
 	int ready_for_use;	/** true if already probed */
 	int dsr_imp;		/**< DSR implementation state from CSD */
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 01:50:50 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 10:50:50 +0100
Subject: [PATCH] nfs: add $global.net.nfsport override
Message-ID: <20250214095050.2849460-1-a.fatoum@pengutronix.de>

Since commit 3ea30d9ce892 ("nfs: parse nfsport and mount port from file
system options"), it's possible to hard code the ports used for NFS,
which is especially useful when talking to a non-kernel NFS daemon
like unfsd.

Add a way to change the NFS port for the /mnt/nfs automount automount to
make this feature more accessible.

A simple one-time configuration can now look like this:

  $ nv user=afa
  $ nv net.server=mydevmachine
  $ nv net.nfsport=2049
  $ nv boot.default=/mnt/nfs

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/nfs.c | 55 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 19 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 9785a313d831..fb76c205db26 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -34,6 +34,7 @@
 #include <byteorder.h>
 #include <globalvar.h>
 #include <parseopt.h>
+#include <magicvar.h>
 
 #define SUNRPC_PORT     111
 
@@ -1390,6 +1391,7 @@ static const struct super_operations nfs_ops = {
 };
 
 static char *rootnfsopts;
+static int nfsport_default;
 
 static void nfs_set_rootarg(struct nfs_priv *npriv, struct fs_device *fsdev)
 {
@@ -1467,30 +1469,41 @@ static int nfs_probe(struct device *dev)
 	/* Need a priviliged source port */
 	net_udp_bind(npriv->con, 1000);
 
-	parseopt_hu(fsdev->options, "mountport", &npriv->mount_port);
-	if (!npriv->mount_port) {
-		ret = rpc_lookup_req(npriv, PROG_MOUNT, 3);
-		if (ret < 0) {
-			printf("lookup mount port failed with %d\n", ret);
-			goto err2;
+	if (nfsport_default == 0) {
+		parseopt_hu(fsdev->options, "mountport", &npriv->mount_port);
+		if (!npriv->mount_port) {
+			ret = rpc_lookup_req(npriv, PROG_MOUNT, 3);
+			if (ret < 0) {
+				printf("lookup mount port failed with %d\n", ret);
+				goto err2;
+			}
+			npriv->mount_port = ret;
+		} else {
+			npriv->manual_mount_port = 1;
 		}
-		npriv->mount_port = ret;
-	} else {
-		npriv->manual_mount_port = 1;
-	}
-	debug("mount port: %hu\n", npriv->mount_port);
 
-	parseopt_hu(fsdev->options, "port", &npriv->nfs_port);
-	if (!npriv->nfs_port) {
-		ret = rpc_lookup_req(npriv, PROG_NFS, 3);
-		if (ret < 0) {
-			printf("lookup nfs port failed with %d\n", ret);
-			goto err2;
+		parseopt_hu(fsdev->options, "port", &npriv->nfs_port);
+		if (!npriv->nfs_port) {
+			ret = rpc_lookup_req(npriv, PROG_NFS, 3);
+			if (ret < 0) {
+				printf("lookup nfs port failed with %d\n", ret);
+				goto err2;
+			}
+			npriv->nfs_port = ret;
+		} else {
+			npriv->manual_nfs_port = 1;
 		}
-		npriv->nfs_port = ret;
 	} else {
-		npriv->manual_nfs_port = 1;
+		if (nfsport_default > U16_MAX) {
+			printf("invalid NFS port: %d\n", nfsport_default);
+			return -EINVAL;
+		}
+
+		npriv->mount_port = npriv->nfs_port = nfsport_default;
+		npriv->manual_nfs_port = npriv->manual_mount_port = 1;
 	}
+
+	debug("mount port: %hu\n", npriv->mount_port);
 	debug("nfs port: %d\n", npriv->nfs_port);
 
 	ret = nfs_mount_req(npriv);
@@ -1555,7 +1568,11 @@ static int nfs_init(void)
 	rootnfsopts = xstrdup("v3,tcp");
 
 	globalvar_add_simple_string("linux.rootnfsopts", &rootnfsopts);
+	globalvar_add_simple_int("net.nfsport", &nfsport_default, "%d");
 
 	return register_fs_driver(&nfs_driver);
 }
 coredevice_initcall(nfs_init);
+
+BAREBOX_MAGICVAR(global.net.nfsport,
+		 "Sets both NFS -o {port.mountport}= to the specified non-zero value");
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 01:51:56 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 10:51:56 +0100
Subject: [PATCH 2/3] fs: remove unused members in struct file_operations
In-Reply-To: <20250214095157.2850839-1-a.fatoum@pengutronix.de>
References: <20250214095157.2850839-1-a.fatoum@pengutronix.de>
Message-ID: <20250214095157.2850839-2-a.fatoum@pengutronix.de>

Eventually, we want to actually use these members in struct file_operations,
but until we do so, having them there without effect only causes
confusion.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/jffs2/dir.c     | 1 -
 fs/ubifs/dir.c     | 2 +-
 include/linux/fs.h | 8 ++++----
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 94ef51f77881..48584466724d 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -26,7 +26,6 @@ static struct dentry *jffs2_lookup (struct inode *,struct dentry *,
 
 const struct file_operations jffs2_dir_operations =
 {
-	.read 	 = NULL,
 	.iterate = jffs2_readdir,
 };
 
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index a16546e615b7..98a4ec6b81e8 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -492,7 +492,7 @@ const struct inode_operations ubifs_dir_inode_operations = {
 const struct file_operations ubifs_dir_operations = {
 /* 	.llseek         = NULL, not present in barebox */
 /* 	.release        = NULL, not present in barebox */
-	.read           = NULL, /* not present in barebox */
+/*	.read           = NULL, not present in barebox */
 	.iterate	= ubifs_readdir,
 /* 	.fsync          = NULL, not present in barebox */
 /*	.unlocked_ioctl = NULL, not present in barebox */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 28d3146516a6..7461eb367d07 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -456,10 +456,10 @@ struct file_operations {
 	int (*open) (struct inode *, struct file *);
 	int (*release) (struct inode *, struct file *);
 	int (*iterate) (struct file *, struct dir_context *);
-	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
-	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
-	int (*ioctl) (struct file *, unsigned int request, void *buf);
-	int (*truncate) (struct file *, loff_t);
+	/*
+	 * TODO: move the remaining callbacks in struct fs_driver
+	 * here with Linux semantics
+	 */
 };
 
 void drop_nlink(struct inode *inode);
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 01:51:57 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 10:51:57 +0100
Subject: [PATCH 3/3] fs: drop unused FS_DRIVER_NO_DEV flag
In-Reply-To: <20250214095157.2850839-1-a.fatoum@pengutronix.de>
References: <20250214095157.2850839-1-a.fatoum@pengutronix.de>
Message-ID: <20250214095157.2850839-3-a.fatoum@pengutronix.de>

The flag used to have an effect, but does so no longer, so let's just
drop it.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/bpkfs.c            | 1 -
 fs/devfs.c            | 1 -
 fs/ext4/ext_barebox.c | 1 -
 fs/fat/fat.c          | 1 -
 fs/jffs2/fs.c         | 1 -
 fs/nfs.c              | 1 -
 fs/omap4_usbbootfs.c  | 1 -
 fs/pstore/fs.c        | 1 -
 fs/ramfs.c            | 1 -
 fs/ratpfs.c           | 1 -
 fs/smhfs.c            | 1 -
 fs/tftp.c             | 1 -
 fs/ubifs/ubifs.c      | 1 -
 fs/uimagefs.c         | 1 -
 include/fs.h          | 4 ----
 15 files changed, 18 deletions(-)

diff --git a/fs/bpkfs.c b/fs/bpkfs.c
index 26ce73ce6bcf..fe6154c555a4 100644
--- a/fs/bpkfs.c
+++ b/fs/bpkfs.c
@@ -504,7 +504,6 @@ static struct fs_driver bpkfs_driver = {
 	.read      = bpkfs_read,
 	.lseek     = bpkfs_lseek,
 	.legacy_ops = &bpkfs_ops,
-	.flags     = 0,
 	.type = filetype_bpk,
 	.drv = {
 		.probe  = bpkfs_probe,
diff --git a/fs/devfs.c b/fs/devfs.c
index 1bc64676b24d..38a85bac3c49 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -312,7 +312,6 @@ static struct fs_driver devfs_driver = {
 	.protect   = devfs_protect,
 	.discard_range = devfs_discard_range,
 	.memmap    = devfs_memmap,
-	.flags     = FS_DRIVER_NO_DEV,
 	.drv = {
 		.probe  = devfs_probe,
 		.remove = devfs_delete,
diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c
index 163c4d2fe1b7..b1888bc4a954 100644
--- a/fs/ext4/ext_barebox.c
+++ b/fs/ext4/ext_barebox.c
@@ -301,7 +301,6 @@ static void ext_remove(struct device *dev)
 static struct fs_driver ext_driver = {
 	.read      = ext_read,
 	.type      = filetype_ext,
-	.flags     = 0,
 	.drv = {
 		.probe  = ext_probe,
 		.remove = ext_remove,
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index d5eade165f1a..15a7b2a96927 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -397,7 +397,6 @@ static struct fs_driver fat_driver = {
 #endif
 	.legacy_ops = &fat_ops,
 	.type = filetype_fat,
-	.flags     = 0,
 	.drv = {
 		.probe  = fat_probe,
 		.remove = fat_remove,
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 3514b0fb3b5a..5952ea9e904f 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -461,7 +461,6 @@ static void jffs2_remove(struct device *dev)
 static struct fs_driver jffs2_driver = {
 	.read = jffs2_read,
 	.type = filetype_jffs2,
-	.flags     = 0,
 	.drv = {
 		.probe  = jffs2_probe,
 		.remove = jffs2_remove,
diff --git a/fs/nfs.c b/fs/nfs.c
index 51bf15196c4e..530d9c6672d8 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -1555,7 +1555,6 @@ static struct fs_driver nfs_driver = {
 	.lseek     = nfs_lseek,
 	.write     = nfs_write,
 	.truncate  = nfs_truncate,
-	.flags     = 0,
 	.drv = {
 		.probe  = nfs_probe,
 		.remove = nfs_remove,
diff --git a/fs/omap4_usbbootfs.c b/fs/omap4_usbbootfs.c
index ad40e9b2c5aa..9c1524c56cc5 100644
--- a/fs/omap4_usbbootfs.c
+++ b/fs/omap4_usbbootfs.c
@@ -160,7 +160,6 @@ static const struct fs_legacy_ops omap4_usbbootfs_ops = {
 static struct fs_driver omap4_usbbootfs_driver = {
 	.read    = omap4_usbbootfs_read,
 	.legacy_ops = &omap4_usbbootfs_ops,
-	.flags	 = 0,
 	.drv = {
 		.probe	= omap4_usbbootfs_probe,
 		.remove	= omap4_usbbootfs_remove,
diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c
index 157f24aaaf72..b77d238ade73 100644
--- a/fs/pstore/fs.c
+++ b/fs/pstore/fs.c
@@ -287,7 +287,6 @@ static const struct fs_legacy_ops pstore_ops = {
 static struct fs_driver pstore_driver = {
 	.read      = pstore_read,
 	.lseek     = pstore_lseek,
-	.flags     = FS_DRIVER_NO_DEV,
 	.legacy_ops = &pstore_ops,
 	.type = filetype_uimage,
 	.drv = {
diff --git a/fs/ramfs.c b/fs/ramfs.c
index 6a824f56fdae..ab3c44270d43 100644
--- a/fs/ramfs.c
+++ b/fs/ramfs.c
@@ -444,7 +444,6 @@ static struct fs_driver ramfs_driver = {
 	.write     = ramfs_write,
 	.memmap    = ramfs_memmap,
 	.truncate  = ramfs_truncate,
-	.flags     = FS_DRIVER_NO_DEV,
 	.drv = {
 		.probe  = ramfs_probe,
 		.remove = ramfs_remove,
diff --git a/fs/ratpfs.c b/fs/ratpfs.c
index 5a1f8febd219..c3c3a248b681 100644
--- a/fs/ratpfs.c
+++ b/fs/ratpfs.c
@@ -456,7 +456,6 @@ static struct fs_driver ratpfs_driver = {
 	.write     = ratpfs_write,
 	.truncate  = ratpfs_truncate,
 	.legacy_ops = &ratpfs_ops,
-	.flags     = FS_DRIVER_NO_DEV,
 	.drv = {
 		.probe  = ratpfs_probe,
 		.remove = ratpfs_remove,
diff --git a/fs/smhfs.c b/fs/smhfs.c
index 425055d98ba8..e0e98f5213e9 100644
--- a/fs/smhfs.c
+++ b/fs/smhfs.c
@@ -150,7 +150,6 @@ static struct fs_driver smhfs_driver = {
 	.write     = smhfs_write,
 	.truncate  = smhfs_truncate,
 	.legacy_ops = &smhfs_ops,
-	.flags     = FS_DRIVER_NO_DEV,
 	.drv = {
 		.probe  = smhfs_probe,
 		.remove = smhfs_remove,
diff --git a/fs/tftp.c b/fs/tftp.c
index 81b87dfcf9e0..b2d5df4aa384 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -1115,7 +1115,6 @@ static struct fs_driver tftp_driver = {
 	.lseek     = tftp_lseek,
 	.write     = tftp_write,
 	.truncate  = tftp_truncate,
-	.flags     = 0,
 	.drv = {
 		.probe  = tftp_probe,
 		.remove = tftp_remove,
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index ef30ae3554f8..45b41ed7541d 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -504,7 +504,6 @@ static void ubifs_remove(struct device *dev)
 static struct fs_driver ubifs_driver = {
 	.read      = ubifs_read,
 	.type = filetype_ubifs,
-	.flags     = 0,
 	.drv = {
 		.probe  = ubifs_probe,
 		.remove = ubifs_remove,
diff --git a/fs/uimagefs.c b/fs/uimagefs.c
index 7ce1a15e0cbe..be268d3679d9 100644
--- a/fs/uimagefs.c
+++ b/fs/uimagefs.c
@@ -530,7 +530,6 @@ static struct fs_driver uimagefs_driver = {
 	.lseek     = uimagefs_lseek,
 	.ioctl	   = uimagefs_ioctl,
 	.legacy_ops = &uimagefs_ops,
-	.flags     = 0,
 	.type = filetype_uimage,
 	.drv = {
 		.probe  = uimagefs_probe,
diff --git a/include/fs.h b/include/fs.h
index 3b8dd93d41d6..fafd91343b5c 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -19,8 +19,6 @@ struct partition;
 struct node_d;
 struct stat;
 
-#define FS_DRIVER_NO_DEV	1
-
 /**
  * enum erase_type - Type of erase operation
  * @ERASE_TO_WRITE: Conduct low-level erase operation to prepare for a write
@@ -86,8 +84,6 @@ struct fs_driver {
 	struct driver drv;
 
 	enum filetype type;
-
-	unsigned long flags;
 };
 
 #define dev_to_fs_device(d) container_of(d, struct fs_device, dev)
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 01:51:55 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 10:51:55 +0100
Subject: [PATCH 1/3] fs: move fs_driver open/close into struct file_operations
Message-ID: <20250214095157.2850839-1-a.fatoum@pengutronix.de>

Linux places open and close (called release) in struct file_operations
and thereby allows implementing them differently depending on inode type.

So far, not being able to do that in barebox didn't bother us much, but
some kernel file systems depend on the directories to be opened before
they are iterated through and barebox will start supporting that in the
later commit.

This would induce breakage in our existing file systems as open so far
was only called for file open. Let's change that by moving open/close
out of fs_driver and implement them only for operations on regular files
for all the existing file systems.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/bpkfs.c             |  4 ++--
 fs/devfs.c             | 12 ++++++------
 fs/efi.c               |  4 ++--
 fs/efivarfs.c          |  4 ++--
 fs/fat/fat.c           |  4 ++--
 fs/fs.c                | 11 ++++-------
 fs/jffs2/fs.c          | 13 +++++++------
 fs/legacy.c            | 36 ++++++++++++++++++++++++++++++++++++
 fs/nfs.c               | 12 ++++++------
 fs/omap4_usbbootfs.c   |  4 ++--
 fs/pstore/fs.c         |  4 ++--
 fs/ratpfs.c            |  4 ++--
 fs/smhfs.c             |  4 ++--
 fs/squashfs/inode.c    |  2 ++
 fs/squashfs/squashfs.c | 14 ++++++++------
 fs/squashfs/squashfs.h |  3 +++
 fs/tftp.c              | 13 +++++++------
 fs/ubifs/super.c       |  5 ++++-
 fs/ubifs/ubifs.c       |  7 ++-----
 fs/ubifs/ubifs.h       |  3 ++-
 fs/uimagefs.c          |  4 ++--
 include/fs.h           |  4 ++--
 include/linux/fs.h     |  2 ++
 23 files changed, 109 insertions(+), 64 deletions(-)

diff --git a/fs/bpkfs.c b/fs/bpkfs.c
index b12c1a8ac25e..26ce73ce6bcf 100644
--- a/fs/bpkfs.c
+++ b/fs/bpkfs.c
@@ -492,6 +492,8 @@ static int bpkfs_probe(struct device *dev)
 }
 
 static const struct fs_legacy_ops bpkfs_ops = {
+	.open      = bpkfs_open,
+	.close     = bpkfs_close,
 	.opendir   = bpkfs_opendir,
 	.readdir   = bpkfs_readdir,
 	.closedir  = bpkfs_closedir,
@@ -499,8 +501,6 @@ static const struct fs_legacy_ops bpkfs_ops = {
 };
 
 static struct fs_driver bpkfs_driver = {
-	.open      = bpkfs_open,
-	.close     = bpkfs_close,
 	.read      = bpkfs_read,
 	.lseek     = bpkfs_lseek,
 	.legacy_ops = &bpkfs_ops,
diff --git a/fs/devfs.c b/fs/devfs.c
index f6db6f716ad1..1bc64676b24d 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -100,9 +100,8 @@ static int devfs_memmap(struct device *_dev, struct file *f, void **map, int fla
 	return cdev_memmap(cdev, map, flags);
 }
 
-static int devfs_open(struct device *_dev, struct file *f, const char *filename)
+static int devfs_open(struct inode *inode, struct file *f)
 {
-	struct inode *inode = f->f_inode;
 	struct devfs_inode *node = container_of(inode, struct devfs_inode, inode);
 	struct cdev *cdev = node->cdev;
 
@@ -113,7 +112,7 @@ static int devfs_open(struct device *_dev, struct file *f, const char *filename)
 	return cdev_open(cdev, f->f_flags);
 }
 
-static int devfs_close(struct device *_dev, struct file *f)
+static int devfs_close(struct inode *inode, struct file *f)
 {
 	struct cdev *cdev = f->private_data;
 
@@ -176,7 +175,10 @@ static int devfs_iterate(struct file *file, struct dir_context *ctx)
 static const struct inode_operations devfs_file_inode_operations;
 static const struct file_operations devfs_dir_operations;
 static const struct inode_operations devfs_dir_inode_operations;
-static const struct file_operations devfs_file_operations;
+static const struct file_operations devfs_file_operations = {
+	.open = devfs_open,
+	.release = devfs_close,
+};
 
 static int devfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
 {
@@ -303,8 +305,6 @@ static struct fs_driver devfs_driver = {
 	.read      = devfs_read,
 	.write     = devfs_write,
 	.lseek     = devfs_lseek,
-	.open      = devfs_open,
-	.close     = devfs_close,
 	.flush     = devfs_flush,
 	.ioctl     = devfs_ioctl,
 	.truncate  = devfs_truncate,
diff --git a/fs/efi.c b/fs/efi.c
index ed799e59eaae..40f71ff241d3 100644
--- a/fs/efi.c
+++ b/fs/efi.c
@@ -421,6 +421,8 @@ static void efifs_remove(struct device *dev)
 }
 
 static const struct fs_legacy_ops efifs_ops = {
+	.open      = efifs_open,
+	.close     = efifs_close,
 	.create    = efifs_create,
 	.unlink    = efifs_unlink,
 	.mkdir     = efifs_mkdir,
@@ -434,8 +436,6 @@ static const struct fs_legacy_ops efifs_ops = {
 };
 
 static struct fs_driver efifs_driver = {
-	.open      = efifs_open,
-	.close     = efifs_close,
 	.truncate  = efifs_truncate,
 	.read      = efifs_read,
 	.write     = efifs_write,
diff --git a/fs/efivarfs.c b/fs/efivarfs.c
index 6a765e0e5003..f5217ae91eda 100644
--- a/fs/efivarfs.c
+++ b/fs/efivarfs.c
@@ -346,6 +346,8 @@ static void efivarfs_remove(struct device *dev)
 }
 
 static const struct fs_legacy_ops efivarfs_ops = {
+	.open      = efivarfs_open,
+	.close     = efivarfs_close,
 	.create    = efivars_create,
 	.unlink    = efivars_unlink,
 	.opendir   = efivarfs_opendir,
@@ -355,8 +357,6 @@ static const struct fs_legacy_ops efivarfs_ops = {
 };
 
 static struct fs_driver efivarfs_driver = {
-	.open      = efivarfs_open,
-	.close     = efivarfs_close,
 	.read      = efivarfs_read,
 	.write     = efivarfs_write,
 	.truncate  = efivarfs_truncate,
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 188408e5a0c9..d5eade165f1a 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -374,6 +374,8 @@ static void fat_remove(struct device *dev)
 }
 
 static const struct fs_legacy_ops fat_ops = {
+	.open      = fat_open,
+	.close     = fat_close,
 	.opendir   = fat_opendir,
 	.readdir   = fat_readdir,
 	.closedir  = fat_closedir,
@@ -387,8 +389,6 @@ static const struct fs_legacy_ops fat_ops = {
 };
 
 static struct fs_driver fat_driver = {
-	.open      = fat_open,
-	.close     = fat_close,
 	.read      = fat_read,
 	.lseek     = fat_lseek,
 #ifdef CONFIG_FS_FAT_WRITE
diff --git a/fs/fs.c b/fs/fs.c
index 689dd77cdbf3..96ca60341ea4 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -747,8 +747,8 @@ int close(int fd)
 		if (fsdrv != ramfs_driver)
 			assert_command_context();
 
-		if (fsdrv->close)
-			ret = fsdrv->close(&f->fsdev->dev, f);
+		if (f->f_inode->i_fop->release)
+			ret = f->f_inode->i_fop->release(f->f_inode, f);
 	}
 
 	put_file(f);
@@ -2660,11 +2660,8 @@ int openat(int dirfd, const char *pathname, int flags)
 	if (flags & O_PATH)
 		return file_to_fd(f);
 
-	if (fsdrv->open) {
-		char *pathname = dpath(dentry, fsdev->vfsmount.mnt_root);
-
-		error = fsdrv->open(&fsdev->dev, f, pathname);
-		free(pathname);
+	if (f->f_inode->i_fop->open) {
+		error = f->f_inode->i_fop->open(inode, f);
 		if (error)
 			goto out;
 	}
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index fda2e86d8135..3514b0fb3b5a 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -37,12 +37,10 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)
 	inode->i_gid = gid;
 }
 
-const struct file_operations jffs2_file_operations;
 const struct inode_operations jffs2_file_inode_operations;
 
-static int jffs2_open(struct device *dev, struct file *file, const char *filename)
+static int jffs2_open(struct inode *inode, struct file *file)
 {
-	struct inode *inode = file->f_inode;
 	struct jffs2_file *jf;
 
 	jf = xzalloc(sizeof(*jf));
@@ -56,7 +54,7 @@ static int jffs2_open(struct device *dev, struct file *file, const char *filenam
 	return 0;
 }
 
-static int jffs2_close(struct device *dev, struct file *f)
+static int jffs2_close(struct inode *inode, struct file *f)
 {
 	struct jffs2_file *jf = f->private_data;
 
@@ -66,6 +64,11 @@ static int jffs2_close(struct device *dev, struct file *f)
 	return 0;
 }
 
+const struct file_operations jffs2_file_operations = {
+	.open = jffs2_open,
+	.release = jffs2_close,
+};
+
 static int jffs2_get_block(struct jffs2_file *jf, unsigned int pos)
 {
 	struct jffs2_sb_info *c = JFFS2_SB_INFO(jf->inode->i_sb);
@@ -456,8 +459,6 @@ static void jffs2_remove(struct device *dev)
 
 
 static struct fs_driver jffs2_driver = {
-	.open = jffs2_open,
-	.close = jffs2_close,
 	.read = jffs2_read,
 	.type = filetype_jffs2,
 	.flags     = 0,
diff --git a/fs/legacy.c b/fs/legacy.c
index c1facfd6d708..f0901ce0d461 100644
--- a/fs/legacy.c
+++ b/fs/legacy.c
@@ -78,6 +78,36 @@ static struct dentry *legacy_lookup(struct inode *dir, struct dentry *dentry,
 	return NULL;
 }
 
+static int legacy_open(struct inode *inode, struct file *file)
+{
+	struct super_block *sb = inode->i_sb;
+	struct fs_device *fsdev = container_of(sb, struct fs_device, sb);
+	const struct fs_legacy_ops *legacy_ops = fsdev->driver->legacy_ops;
+	char *pathname;
+	int error;
+
+	if (!legacy_ops->open)
+		return 0;
+
+	pathname = dpath(file->f_dentry, fsdev->vfsmount.mnt_root);
+	error = legacy_ops->open(&file->fsdev->dev, file, pathname);
+	free(pathname);
+
+	return error;
+}
+
+static int legacy_release(struct inode *inode, struct file *file)
+{
+	struct super_block *sb = inode->i_sb;
+	struct fs_device *fsdev = container_of(sb, struct fs_device, sb);
+	const struct fs_legacy_ops *legacy_ops = fsdev->driver->legacy_ops;
+
+	if (!legacy_ops->close)
+		return 0;
+
+	return legacy_ops->close(&file->fsdev->dev, file);
+}
+
 static int legacy_create(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
 	struct super_block *sb = dir->i_sb;
@@ -280,6 +310,11 @@ static const struct inode_operations legacy_dir_inode_operations = {
 	.symlink = legacy_symlink,
 };
 
+static const struct file_operations legacy_file_operations = {
+	.open = legacy_open,
+	.release = legacy_release,
+};
+
 static const struct file_operations legacy_dir_operations = {
 	.iterate = legacy_iterate,
 };
@@ -306,6 +341,7 @@ static struct inode *legacy_get_inode(struct super_block *sb, const struct inode
 	case S_IFCHR:
 	case S_IFBLK:
 		inode->i_op = &legacy_file_inode_operations;
+		inode->i_fop = &legacy_file_operations;
 		break;
 	case S_IFDIR:
 		inode->i_op = &legacy_dir_inode_operations;
diff --git a/fs/nfs.c b/fs/nfs.c
index fb76c205db26..51bf15196c4e 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -1157,9 +1157,8 @@ static const char *nfs_get_link(struct dentry *dentry, struct inode *inode)
 	return inode->i_link;
 }
 
-static int nfs_open(struct device *dev, struct file *file, const char *filename)
+static int nfs_open(struct inode *inode, struct file *file)
 {
-	struct inode *inode = file->f_inode;
 	struct nfs_inode *ninode = nfsi(inode);
 	struct nfs_priv *npriv = ninode->npriv;
 	struct file_priv *priv;
@@ -1178,7 +1177,7 @@ static int nfs_open(struct device *dev, struct file *file, const char *filename)
 	return 0;
 }
 
-static int nfs_close(struct device *dev, struct file *file)
+static int nfs_close(struct inode *inode, struct file *file)
 {
 	struct file_priv *priv = file->private_data;
 
@@ -1319,7 +1318,10 @@ static void nfs_destroy_inode(struct inode *inode)
 static const struct inode_operations nfs_file_inode_operations;
 static const struct file_operations nfs_dir_operations;
 static const struct inode_operations nfs_dir_inode_operations;
-static const struct file_operations nfs_file_operations;
+static const struct file_operations nfs_file_operations = {
+	.open      = nfs_open,
+	.release     = nfs_close,
+};
 static const struct inode_operations nfs_symlink_inode_operations = {
 	.get_link = nfs_get_link,
 };
@@ -1549,8 +1551,6 @@ static void nfs_remove(struct device *dev)
 }
 
 static struct fs_driver nfs_driver = {
-	.open      = nfs_open,
-	.close     = nfs_close,
 	.read      = nfs_read,
 	.lseek     = nfs_lseek,
 	.write     = nfs_write,
diff --git a/fs/omap4_usbbootfs.c b/fs/omap4_usbbootfs.c
index 9d8f4d04f9b8..ad40e9b2c5aa 100644
--- a/fs/omap4_usbbootfs.c
+++ b/fs/omap4_usbbootfs.c
@@ -151,13 +151,13 @@ static void omap4_usbbootfs_remove(struct device *dev)
 }
 
 static const struct fs_legacy_ops omap4_usbbootfs_ops = {
+	.open    = omap4_usbbootfs_open,
+	.close   = omap4_usbbootfs_close,
 	.opendir = omap4_usbbootfs_opendir,
 	.stat    = omap4_usbbootfs_stat,
 };
 
 static struct fs_driver omap4_usbbootfs_driver = {
-	.open    = omap4_usbbootfs_open,
-	.close   = omap4_usbbootfs_close,
 	.read    = omap4_usbbootfs_read,
 	.legacy_ops = &omap4_usbbootfs_ops,
 	.flags	 = 0,
diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c
index 24b0fa5c9d9c..157f24aaaf72 100644
--- a/fs/pstore/fs.c
+++ b/fs/pstore/fs.c
@@ -275,6 +275,8 @@ static int pstore_probe(struct device *dev)
 }
 
 static const struct fs_legacy_ops pstore_ops = {
+	.open      = pstore_open,
+	.close     = pstore_close,
 	.unlink    = pstore_unlink,
 	.opendir   = pstore_opendir,
 	.readdir   = pstore_readdir,
@@ -283,8 +285,6 @@ static const struct fs_legacy_ops pstore_ops = {
 };
 
 static struct fs_driver pstore_driver = {
-	.open      = pstore_open,
-	.close     = pstore_close,
 	.read      = pstore_read,
 	.lseek     = pstore_lseek,
 	.flags     = FS_DRIVER_NO_DEV,
diff --git a/fs/ratpfs.c b/fs/ratpfs.c
index 766291fff216..5a1f8febd219 100644
--- a/fs/ratpfs.c
+++ b/fs/ratpfs.c
@@ -439,6 +439,8 @@ static void ratpfs_remove(struct device __always_unused *dev)
 }
 
 static const struct fs_legacy_ops ratpfs_ops = {
+	.open      = ratpfs_open,
+	.close     = ratpfs_close,
 	.opendir   = ratpfs_opendir,
 	.readdir   = ratpfs_readdir,
 	.closedir  = ratpfs_closedir,
@@ -450,8 +452,6 @@ static const struct fs_legacy_ops ratpfs_ops = {
 };
 
 static struct fs_driver ratpfs_driver = {
-	.open      = ratpfs_open,
-	.close     = ratpfs_close,
 	.read      = ratpfs_read,
 	.write     = ratpfs_write,
 	.truncate  = ratpfs_truncate,
diff --git a/fs/smhfs.c b/fs/smhfs.c
index ed98cd247bd8..425055d98ba8 100644
--- a/fs/smhfs.c
+++ b/fs/smhfs.c
@@ -134,6 +134,8 @@ static void smhfs_remove(struct device __always_unused *dev)
 }
 
 static const struct fs_legacy_ops smhfs_ops = {
+	.open      = smhfs_open,
+	.close     = smhfs_close,
 	.opendir   = smhfs_opendir,
 	.stat      = smhfs_stat,
 	.create    = smhfs_create,
@@ -143,8 +145,6 @@ static const struct fs_legacy_ops smhfs_ops = {
 };
 
 static struct fs_driver smhfs_driver = {
-	.open      = smhfs_open,
-	.close     = smhfs_close,
 	.read      = smhfs_read,
 	.lseek     = smhfs_lseek,
 	.write     = smhfs_write,
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index f702f6c0a2d9..5128f01486b0 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -156,6 +156,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 
 		inode->i_size = le32_to_cpu(sqsh_ino->file_size);
 		inode->i_op = &squashfs_inode_ops;
+		inode->i_fop = &squashfs_file_operations;
 		inode->i_mode |= S_IFREG;
 		inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
 		squashfs_i(inode)->fragment_block = frag_blk;
@@ -198,6 +199,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
 
 		inode->i_size = le64_to_cpu(sqsh_ino->file_size);
 		inode->i_op = &squashfs_inode_ops;
+		inode->i_fop = &squashfs_file_operations;
 		inode->i_mode |= S_IFREG;
 		inode->i_blocks = (inode->i_size -
 				le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;
diff --git a/fs/squashfs/squashfs.c b/fs/squashfs/squashfs.c
index dc4fbf11c46e..5441271e45f1 100644
--- a/fs/squashfs/squashfs.c
+++ b/fs/squashfs/squashfs.c
@@ -131,9 +131,8 @@ static void squashfs_remove(struct device *dev)
 	squashfs_put_super(sb);
 }
 
-static int squashfs_open(struct device *dev, struct file *file, const char *filename)
+static int squashfs_open(struct inode *inode, struct file *file)
 {
-	struct inode *inode = file->f_inode;
 	struct squashfs_page *page;
 	int i;
 
@@ -142,7 +141,7 @@ static int squashfs_open(struct device *dev, struct file *file, const char *file
 	for (i = 0; i < 32; i++) {
 		page->buf[i] = malloc(PAGE_CACHE_SIZE);
 		if (page->buf[i] == NULL) {
-			dev_err(dev, "error allocation read buffer\n");
+			dev_err(&file->fsdev->dev, "error allocation read buffer\n");
 			goto error;
 		}
 	}
@@ -164,7 +163,7 @@ static int squashfs_open(struct device *dev, struct file *file, const char *file
 	return -ENOMEM;
 }
 
-static int squashfs_close(struct device *dev, struct file *f)
+static int squashfs_close(struct inode *inode, struct file *f)
 {
 	struct squashfs_page *page = f->private_data;
 	int i;
@@ -178,6 +177,11 @@ static int squashfs_close(struct device *dev, struct file *f)
 	return 0;
 }
 
+const struct file_operations squashfs_file_operations = {
+	.open = squashfs_open,
+	.release = squashfs_close,
+};
+
 static int squashfs_read_buf(struct squashfs_page *page, int pos, void **buf)
 {
 	unsigned int data_block = pos / (32 * PAGE_CACHE_SIZE);
@@ -251,8 +255,6 @@ struct squashfs_dir {
 };
 
 static struct fs_driver squashfs_driver = {
-	.open		= squashfs_open,
-	.close		= squashfs_close,
 	.read		= squashfs_read,
 	.type		= filetype_squashfs,
 	.drv = {
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
index 1f2fee59d688..205753c51b97 100644
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -58,6 +58,9 @@ extern int squashfs_mount(struct fs_device *fsdev,
 			  int silent);
 extern void squashfs_put_super(struct super_block *sb);
 
+/* squashfs.c */
+extern const struct file_operations squashfs_file_operations;
+
 /* block.c */
 extern int squashfs_read_data(struct super_block *, u64, int, u64 *,
 				struct squashfs_page_actor *);
diff --git a/fs/tftp.c b/fs/tftp.c
index 37b7a64fcdba..81b87dfcf9e0 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -765,11 +765,11 @@ static struct file_priv *tftp_do_open(struct device *dev,
 	return ERR_PTR(ret);
 }
 
-static int tftp_open(struct device *dev, struct file *file, const char *filename)
+static int tftp_open(struct inode *inode, struct file *file)
 {
 	struct file_priv *priv;
 
-	priv = tftp_do_open(dev, file->f_flags, file->f_dentry, false);
+	priv = tftp_do_open(&file->fsdev->dev, file->f_flags, file->f_dentry, false);
 	if (IS_ERR(priv))
 		return PTR_ERR(priv);
 
@@ -818,7 +818,7 @@ static int tftp_do_close(struct file_priv *priv)
 	return 0;
 }
 
-static int tftp_close(struct device *dev, struct file *f)
+static int tftp_close(struct inode *inode, struct file *f)
 {
 	struct file_priv *priv = f->private_data;
 
@@ -943,7 +943,10 @@ static int tftp_lseek(struct device *dev, struct file *f, loff_t pos)
 
 static const struct inode_operations tftp_file_inode_operations;
 static const struct inode_operations tftp_dir_inode_operations;
-static const struct file_operations tftp_file_operations;
+static const struct file_operations tftp_file_operations = {
+	.open = tftp_open,
+	.release = tftp_close,
+};
 
 static struct inode *tftp_get_inode(struct super_block *sb, const struct inode *dir,
                                      umode_t mode)
@@ -1108,8 +1111,6 @@ static void tftp_remove(struct device *dev)
 }
 
 static struct fs_driver tftp_driver = {
-	.open      = tftp_open,
-	.close     = tftp_close,
 	.read      = tftp_read,
 	.lseek     = tftp_lseek,
 	.write     = tftp_write,
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 564ac950ebf2..285c40b4c21c 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -105,7 +105,10 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
 }
 
 const struct inode_operations ubifs_file_inode_operations;
-const struct file_operations ubifs_file_operations;
+const struct file_operations ubifs_file_operations = {
+	.open = ubifs_open,
+	.release = ubifs_close,
+};
 
 struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
 {
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 63dab3c197c3..ef30ae3554f8 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -340,9 +340,8 @@ struct ubifs_file {
 	struct ubifs_data_node *dn;
 };
 
-static int ubifs_open(struct device *dev, struct file *file, const char *filename)
+int ubifs_open(struct inode *inode, struct file *file)
 {
-	struct inode *inode = file->f_inode;
 	struct ubifs_file *uf;
 
 	uf = xzalloc(sizeof(*uf));
@@ -357,7 +356,7 @@ static int ubifs_open(struct device *dev, struct file *file, const char *filenam
 	return 0;
 }
 
-static int ubifs_close(struct device *dev, struct file *f)
+int ubifs_close(struct inode *inode, struct file *f)
 {
 	struct ubifs_file *uf = f->private_data;
 
@@ -503,8 +502,6 @@ static void ubifs_remove(struct device *dev)
 }
 
 static struct fs_driver ubifs_driver = {
-	.open      = ubifs_open,
-	.close     = ubifs_close,
 	.read      = ubifs_read,
 	.type = filetype_ubifs,
 	.flags     = 0,
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 598614efea1e..4695772355ef 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -2058,8 +2058,9 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
 #include "key.h"
 
 /* barebox specific */
+int ubifs_open(struct inode *inode, struct file *file);
+int ubifs_close(struct inode *inode, struct file *f);
 void ubifs_umount(struct ubifs_info *c);
-/* barebox specific */
 int ubifs_get_super(struct device *dev, struct ubi_volume_desc *ubi,
 		    int silent);
 
diff --git a/fs/uimagefs.c b/fs/uimagefs.c
index d7993bf9c78e..7ce1a15e0cbe 100644
--- a/fs/uimagefs.c
+++ b/fs/uimagefs.c
@@ -517,6 +517,8 @@ static int uimagefs_probe(struct device *dev)
 }
 
 static const struct fs_legacy_ops uimagefs_ops = {
+	.open      = uimagefs_open,
+	.close     = uimagefs_close,
 	.opendir   = uimagefs_opendir,
 	.readdir   = uimagefs_readdir,
 	.closedir  = uimagefs_closedir,
@@ -524,8 +526,6 @@ static const struct fs_legacy_ops uimagefs_ops = {
 };
 
 static struct fs_driver uimagefs_driver = {
-	.open      = uimagefs_open,
-	.close     = uimagefs_close,
 	.read      = uimagefs_read,
 	.lseek     = uimagefs_lseek,
 	.ioctl	   = uimagefs_ioctl,
diff --git a/include/fs.h b/include/fs.h
index 622c12a2d238..3b8dd93d41d6 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -48,8 +48,6 @@ struct fs_driver {
 	/* Truncate a file to given size */
 	int (*truncate)(struct device *dev, struct file *f, loff_t size);
 
-	int (*open)(struct device *dev, struct file *f, const char *pathname);
-	int (*close)(struct device *dev, struct file *f);
 	int (*read)(struct device *dev, struct file *f, void *buf, size_t size);
 	int (*write)(struct device *dev, struct file *f, const void *buf,
 		     size_t size);
@@ -67,6 +65,8 @@ struct fs_driver {
 	int (*memmap)(struct device *dev, struct file *f, void **map, int flags);
 
 	const struct fs_legacy_ops {
+		int (*open)(struct device *dev, struct file *f, const char *pathname);
+		int (*close)(struct device *dev, struct file *f);
 		/* create a file. The file is guaranteed to not exist */
 		int (*create)(struct device *dev, const char *pathname, mode_t mode);
 		int (*unlink)(struct device *dev, const char *pathname);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 7694ed5cbe76..28d3146516a6 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -453,6 +453,8 @@ static inline int dir_emit_dots(struct file *file, struct dir_context *ctx)
 }
 
 struct file_operations {
+	int (*open) (struct inode *, struct file *);
+	int (*release) (struct inode *, struct file *);
 	int (*iterate) (struct file *, struct dir_context *);
 	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
 	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 01:54:12 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 10:54:12 +0100
Subject: [PATCH] boot: omit menu freeing loop when CONFIG_MENU is disabled
Message-ID: <20250214095412.2852561-1-a.fatoum@pengutronix.de>

While free() can handle NULL pointers, it's better to not even call
free() when we know at compile-time that the pointers are NULL.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/boot.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/common/boot.c b/common/boot.c
index f6ac4779cc33..ced3b3a3477c 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -50,13 +50,14 @@ void bootentries_free(struct bootentries *bootentries)
 		be->release(be);
 	}
 
-	if (bootentries->menu) {
+	if (IS_ENABLED(CONFIG_MENU) && bootentries->menu) {
 		int i;
 		for (i = 0; i < bootentries->menu->display_lines; i++)
 			free_const(bootentries->menu->display[i]);
 		free_const(bootentries->menu->display);
+		free(bootentries->menu);
 	}
-	free(bootentries->menu);
+
 	free(bootentries);
 }
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:12:04 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:12:04 +0100
Subject: [PATCH 1/3] lib: add scatterlist abstraction
Message-ID: <20250214101206.2876051-1-a.fatoum@pengutronix.de>

With barebox using 1:1 memory mapping whenever possible, scatter-gather
DMA seems not that important. Many Linux APIs use struct scatterlist
as parameters though, so adding a basic support in barebox will make
easier to port these drivers.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/linux/scatterlist.h | 138 +++++++++++++++++++++++++++++++++++
 lib/Makefile                |   1 +
 lib/scatterlist.c           | 142 ++++++++++++++++++++++++++++++++++++
 3 files changed, 281 insertions(+)
 create mode 100644 include/linux/scatterlist.h
 create mode 100644 lib/scatterlist.c

diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
new file mode 100644
index 000000000000..4ac164b6d3f7
--- /dev/null
+++ b/include/linux/scatterlist.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SCATTERLIST_H
+#define _LINUX_SCATTERLIST_H
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/bug.h>
+#include <asm/io.h>
+
+
+struct scatterlist {
+	void		*address;
+	unsigned int	flags:2;
+#define SG_CHAIN	0x01UL
+#define SG_END		0x02UL
+	unsigned int	length:30;
+};
+
+struct sg_table {
+	struct scatterlist *sgl;	/* the list */
+	unsigned int nents;		/* number of mapped entries */
+	unsigned int orig_nents;	/* original size of list */
+};
+
+/*
+ * Notes on SG table design.
+ *
+ * We use the the scatterlist struct to place the address AND encode
+ * information about the sg table as well. The two flag bits are reserved
+ * for this information.
+ *
+ * If bit 0 is set, then the address member is a pointer to the next sg
+ * table list. Otherwise the next entry is at sg + 1.
+ *
+ * If bit 1 is set, then this sg entry is the last element in a list.
+ *
+ * See sg_next().
+ *
+ */
+
+static inline unsigned int __sg_flags(struct scatterlist *sg)
+{
+	return sg->flags;
+}
+
+static inline bool sg_is_chain(struct scatterlist *sg)
+{
+	return __sg_flags(sg) & SG_CHAIN;
+}
+
+static inline bool sg_is_last(struct scatterlist *sg)
+{
+	return __sg_flags(sg) & SG_END;
+}
+
+static inline struct scatterlist *sg_chain_ptr(struct scatterlist *sg)
+{
+	return sg->address;
+}
+
+int sg_nents(struct scatterlist *sg);
+int sg_nents_for_len(struct scatterlist *sg, u64 len);
+
+/**
+ * sg_set_buf - Set sg entry to point at given data
+ * @sg:		 SG entry
+ * @buf:	 Data
+ * @buflen:	 Data length
+ *
+ **/
+static inline void sg_set_buf(struct scatterlist *sg, const void *buf,
+			      unsigned int buflen)
+{
+	sg->address = (void *)buf;
+	sg->length = buflen;
+}
+
+/*
+ * Loop over each sg element, following the pointer to a new list if necessary
+ */
+#define for_each_sg(sglist, sg, nr, __i)	\
+	for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg))
+
+/*
+ * Loop over each sg element in the given sg_table object.
+ */
+#define for_each_sgtable_sg(sgt, sg, i)		\
+	for_each_sg((sgt)->sgl, sg, (sgt)->orig_nents, i)
+
+/**
+ * sg_mark_end - Mark the end of the scatterlist
+ * @sg:		 SG entryScatterlist
+ *
+ * Description:
+ *   Marks the passed in sg entry as the termination point for the sg
+ *   table. A call to sg_next() on this entry will return NULL.
+ *
+ **/
+static inline void sg_mark_end(struct scatterlist *sg)
+{
+	/*
+	 * Set termination bit, clear potential chain bit
+	 */
+	sg->flags |= SG_END;
+	sg->flags &= ~SG_CHAIN;
+}
+
+/**
+ * sg_unmark_end - Undo setting the end of the scatterlist
+ * @sg:		 SG entryScatterlist
+ *
+ * Description:
+ *   Removes the termination marker from the given entry of the scatterlist.
+ *
+ **/
+static inline void sg_unmark_end(struct scatterlist *sg)
+{
+	sg->flags &= ~SG_END;
+}
+
+/**
+ * sg_init_marker - Initialize markers in sg table
+ * @sgl:	   The SG table
+ * @nents:	   Number of entries in table
+ *
+ **/
+static inline void sg_init_marker(struct scatterlist *sgl,
+				  unsigned int nents)
+{
+	sg_mark_end(&sgl[nents - 1]);
+}
+
+struct scatterlist *sg_next(struct scatterlist *);
+struct scatterlist *sg_last(struct scatterlist *s, unsigned int);
+void sg_init_table(struct scatterlist *, unsigned int);
+void sg_init_one(struct scatterlist *, const void *, unsigned int);
+
+#endif /* _LINUX_SCATTERLIST_H */
diff --git a/lib/Makefile b/lib/Makefile
index 46b42146cbc9..4e75f2467ac1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_FIP)	+= fip.o tbbr_config.o
 obj-$(CONFIG_JSMN)	+= jsmn.o
 obj-$(CONFIG_BLOBGEN)	+= blobgen.o
 obj-y			+= stringlist.o
+obj-y			+= scatterlist.o
 obj-y			+= cmdlinepart.o
 obj-y			+= recursive_action.o
 obj-y			+= make_directory.o
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
new file mode 100644
index 000000000000..f7b06013a552
--- /dev/null
+++ b/lib/scatterlist.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2007 Jens Axboe <jens.axboe at oracle.com>
+ *
+ * Scatterlist handling helpers.
+ */
+
+#include <linux/export.h>
+#include <linux/scatterlist.h>
+#include <linux/errno.h>
+
+/**
+ * sg_next - return the next scatterlist entry in a list
+ * @sg:		The current sg entry
+ *
+ * Description:
+ *   Usually the next entry will be @sg@ + 1, but if this sg element is part
+ *   of a chained scatterlist, it could jump to the start of a new
+ *   scatterlist array.
+ *
+ **/
+struct scatterlist *sg_next(struct scatterlist *sg)
+{
+	if (sg_is_last(sg))
+		return NULL;
+
+	sg++;
+	if (unlikely(sg_is_chain(sg)))
+		sg = sg_chain_ptr(sg);
+
+	return sg;
+}
+EXPORT_SYMBOL(sg_next);
+
+/**
+ * sg_nents - return total count of entries in scatterlist
+ * @sg:		The scatterlist
+ *
+ * Description:
+ * Allows to know how many entries are in sg, taking into account
+ * chaining as well
+ *
+ **/
+int sg_nents(struct scatterlist *sg)
+{
+	int nents;
+	for (nents = 0; sg; sg = sg_next(sg))
+		nents++;
+	return nents;
+}
+EXPORT_SYMBOL(sg_nents);
+
+/**
+ * sg_nents_for_len - return total count of entries in scatterlist
+ *                    needed to satisfy the supplied length
+ * @sg:		The scatterlist
+ * @len:	The total required length
+ *
+ * Description:
+ * Determines the number of entries in sg that are required to meet
+ * the supplied length, taking into account chaining as well
+ *
+ * Returns:
+ *   the number of sg entries needed, negative error on failure
+ *
+ **/
+int sg_nents_for_len(struct scatterlist *sg, u64 len)
+{
+	int nents;
+	u64 total;
+
+	if (!len)
+		return 0;
+
+	for (nents = 0, total = 0; sg; sg = sg_next(sg)) {
+		nents++;
+		total += sg->length;
+		if (total >= len)
+			return nents;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL(sg_nents_for_len);
+
+/**
+ * sg_last - return the last scatterlist entry in a list
+ * @sgl:	First entry in the scatterlist
+ * @nents:	Number of entries in the scatterlist
+ *
+ * Description:
+ *   Should only be used casually, it (currently) scans the entire list
+ *   to get the last entry.
+ *
+ *   Note that the @sgl@ pointer passed in need not be the first one,
+ *   the important bit is that @nents@ denotes the number of entries that
+ *   exist from @sgl at .
+ *
+ **/
+struct scatterlist *sg_last(struct scatterlist *sgl, unsigned int nents)
+{
+	struct scatterlist *sg, *ret = NULL;
+	unsigned int i;
+
+	for_each_sg(sgl, sg, nents, i)
+		ret = sg;
+
+	BUG_ON(!sg_is_last(ret));
+	return ret;
+}
+EXPORT_SYMBOL(sg_last);
+
+/**
+ * sg_init_table - Initialize SG table
+ * @sgl:	   The SG table
+ * @nents:	   Number of entries in table
+ *
+ * Notes:
+ *   If this is part of a chained sg table, sg_mark_end() should be
+ *   used only on the last table part.
+ *
+ **/
+void sg_init_table(struct scatterlist *sgl, unsigned int nents)
+{
+	memset(sgl, 0, sizeof(*sgl) * nents);
+	sg_init_marker(sgl, nents);
+}
+EXPORT_SYMBOL(sg_init_table);
+
+/**
+ * sg_init_one - Initialize a single entry sg list
+ * @sg:		 SG entry
+ * @buf:	 Virtual address for IO
+ * @buflen:	 IO length
+ *
+ **/
+void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
+{
+	sg_init_table(sg, 1);
+	sg_set_buf(sg, buf, buflen);
+}
+EXPORT_SYMBOL(sg_init_one);
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:12:06 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:12:06 +0100
Subject: [PATCH 3/3] virtio: add token data parameter to virtqueue_add_sgs
In-Reply-To: <20250214101206.2876051-1-a.fatoum@pengutronix.de>
References: <20250214101206.2876051-1-a.fatoum@pengutronix.de>
Message-ID: <20250214101206.2876051-3-a.fatoum@pengutronix.de>

In Linux, virtqueue_get_buf doesn't return the buffer, but the cookie
value specified when the entry was first added to the virtqueue via
virtqueue_add_sgs.

To make it easier to port Linux drivers that keep around metadata for
requests, adopt the Linux API.

No functional change expected.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/block/virtio_blk.c      |  2 +-
 drivers/hw_random/virtio-rng.c  |  2 +-
 drivers/input/virtio_input.c    |  4 ++--
 drivers/net/virtio.c            |  6 +++---
 drivers/serial/virtio_console.c |  4 ++--
 drivers/virtio/virtio_ring.c    | 24 +++++++++++++-----------
 include/linux/virtio_ring.h     | 24 ++++++++++++++++++------
 7 files changed, 40 insertions(+), 26 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 3ee7972fe859..11111f174142 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -49,7 +49,7 @@ static int virtio_blk_do_req(struct virtio_blk_priv *priv, void *buffer,
 	sg_init_one(&status_sg, &status, sizeof(status));
 	sgs[num_out + num_in++] = &status_sg;
 
-	ret = virtqueue_add_sgs(priv->vq, sgs, num_out, num_in);
+	ret = virtqueue_add_sgs(priv->vq, sgs, num_out, num_in, &out_hdr);
 	if (ret)
 		return ret;
 
diff --git a/drivers/hw_random/virtio-rng.c b/drivers/hw_random/virtio-rng.c
index 6c283c784fb7..1ce321352935 100644
--- a/drivers/hw_random/virtio-rng.c
+++ b/drivers/hw_random/virtio-rng.c
@@ -41,7 +41,7 @@ static int virtio_rng_read(struct hwrng *hwrng, void *data, size_t len, bool wai
 	while (remaining) {
 		sg_init_one(&sg, buf, min(remaining, sizeof(buf)));
 
-		ret = virtqueue_add_inbuf(vi->rng_vq, &sg, 1);
+		ret = virtqueue_add_inbuf(vi->rng_vq, &sg, 1, buf);
 		if (ret)
 			return ret;
 
diff --git a/drivers/input/virtio_input.c b/drivers/input/virtio_input.c
index cdcee556a6c7..6e73e7873986 100644
--- a/drivers/input/virtio_input.c
+++ b/drivers/input/virtio_input.c
@@ -27,7 +27,7 @@ static void virtinput_queue_evtbuf(struct virtio_input *vi,
 {
 	struct scatterlist sg;
 	sg_init_one(&sg, evtbuf, sizeof(*evtbuf));
-	virtqueue_add_inbuf(vi->evt, &sg, 1);
+	virtqueue_add_inbuf(vi->evt, &sg, 1, evtbuf);
 }
 
 static int virtinput_recv_events(struct virtio_input *vi)
@@ -78,7 +78,7 @@ static int virtinput_send_status(struct sound_card *beeper, unsigned freq, unsig
 	stsbuf->value = cpu_to_le32(freq);
 	sg_init_one(&sg, stsbuf, sizeof(*stsbuf));
 
-	rc = virtqueue_add_outbuf(vi->sts, &sg, 1);
+	rc = virtqueue_add_outbuf(vi->sts, &sg, 1, stsbuf);
 	virtqueue_kick(vi->sts);
 
 	if (rc != 0)
diff --git a/drivers/net/virtio.c b/drivers/net/virtio.c
index 26a1dde5199a..73afbc7645bd 100644
--- a/drivers/net/virtio.c
+++ b/drivers/net/virtio.c
@@ -57,7 +57,7 @@ static int virtio_net_start(struct eth_device *edev)
 			sg.length = VIRTIO_NET_RX_BUF_SIZE;
 
 			sg_init_one(&sg, priv->rx_buff[i], VIRTIO_NET_RX_BUF_SIZE);
-			virtqueue_add_inbuf(priv->rx_vq, &sg, 1);
+			virtqueue_add_inbuf(priv->rx_vq, &sg, 1, priv->rx_buff[i]);
 		}
 
 		virtqueue_kick(priv->rx_vq);
@@ -86,7 +86,7 @@ static int virtio_net_send(struct eth_device *edev, void *packet, int length)
 
 	sg_set_buf(&sgs[1], packet, length);
 
-	ret = virtqueue_add_outbuf(priv->tx_vq, sgs, ARRAY_SIZE(sgs));
+	ret = virtqueue_add_outbuf(priv->tx_vq, sgs, ARRAY_SIZE(sgs), &sgs[0].address);
 	if (ret)
 		return ret;
 
@@ -119,7 +119,7 @@ static void virtio_net_recv(struct eth_device *edev)
 	net_receive(edev, buf, len);
 
 	/* Put the buffer back to the rx ring */
-	virtqueue_add_inbuf(priv->rx_vq, &sg, 1);
+	virtqueue_add_inbuf(priv->rx_vq, &sg, 1, addr);
 }
 
 static void virtio_net_stop(struct eth_device *dev)
diff --git a/drivers/serial/virtio_console.c b/drivers/serial/virtio_console.c
index eb3b1158171d..09249aef7a14 100644
--- a/drivers/serial/virtio_console.c
+++ b/drivers/serial/virtio_console.c
@@ -49,7 +49,7 @@ static void put_chars(struct virtio_console *virtcons, const char *buf, int coun
 	 * add_buf wants a token to identify this buffer: we hand it
 	 * any non-NULL pointer, since there's only ever one buffer.
 	 */
-	if (virtqueue_add_outbuf(out_vq, &sg, 1) >= 0) {
+	if (virtqueue_add_outbuf(out_vq, &sg, 1, (void *)buf) >= 0) {
 		/* Tell Host to go! */
 		virtqueue_kick(out_vq);
 		/* Chill out until it's done with the buffer. */
@@ -76,7 +76,7 @@ static void add_inbuf(struct virtio_console *virtcons)
 	sg_init_one(&sg, virtcons->inbuf, sizeof(virtcons->inbuf));
 
 	/* We should always be able to add one buffer to an empty queue. */
-	if (virtqueue_add_inbuf(virtcons->in_vq, &sg, 1) < 0)
+	if (virtqueue_add_inbuf(virtcons->in_vq, &sg, 1, virtcons->inbuf) < 0)
 		BUG();
 	virtqueue_kick(virtcons->in_vq);
 }
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index cd3677ff73f9..29d7bb9ef662 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -58,7 +58,8 @@ static void vring_unmap_one(struct virtqueue *vq,
 }
 
 int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[],
-		      unsigned int out_sgs, unsigned int in_sgs)
+		      unsigned int out_sgs, unsigned int in_sgs,
+		      void *data)
 {
 	struct vring_desc *desc;
 	unsigned int total_sg = out_sgs + in_sgs;
@@ -67,6 +68,7 @@ int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[],
 	int head;
 
 	WARN_ON(total_sg == 0);
+	BUG_ON(data == NULL);
 
 	head = vq->free_head;
 
@@ -128,6 +130,9 @@ int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[],
 	/* Update free pointer */
 	vq->free_head = i;
 
+	/* Store token. */
+	vq->desc_state[head].data = data;
+
 	/*
 	 * Put entry in available array (but don't update avail->idx
 	 * until they do sync).
@@ -204,6 +209,9 @@ static void detach_buf(struct virtqueue *vq, unsigned int head)
 	unsigned int i;
 	__virtio16 nextflag = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT);
 
+	/* Clear data ptr. */
+	vq->desc_state[head].data = NULL;
+
 	/* Put back on free list: unmap first-level descriptors and find end */
 	i = head;
 
@@ -230,6 +238,7 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
 {
 	unsigned int i;
 	u16 last_used;
+	void *ret;
 
 	if (!more_used(vq)) {
 		vq_debug(vq, "No more buffers in queue\n");
@@ -252,6 +261,7 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
 		return NULL;
 	}
 
+	ret = vq->desc_state[i].data;
 	detach_buf(vq, i);
 	vq->last_used_idx++;
 	/*
@@ -263,8 +273,7 @@ void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
 		virtio_store_mb(&vring_used_event(&vq->vring),
 				cpu_to_virtio16(vq->vdev, vq->last_used_idx));
 
-	return IOMEM((uintptr_t)virtio64_to_cpu(vq->vdev,
-						  vq->vring.desc[i].addr));
+	return ret;
 }
 
 static struct virtqueue *__vring_new_virtqueue(unsigned int index,
@@ -274,7 +283,7 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
 	unsigned int i;
 	struct virtqueue *vq;
 
-	vq = malloc(sizeof(*vq));
+	vq = calloc(1, struct_size(vq, desc_state, vring.num));
 	if (!vq)
 		return NULL;
 
@@ -282,12 +291,6 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
 	vq->index = index;
 	vq->num_free = vring.num;
 	vq->vring = vring;
-	vq->last_used_idx = 0;
-	vq->avail_flags_shadow = 0;
-	vq->avail_idx_shadow = 0;
-	vq->num_added = 0;
-	vq->queue_dma_addr = 0;
-	vq->queue_size_in_bytes = 0;
 	list_add_tail(&vq->list, &vdev->vqs);
 
 	vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
@@ -299,7 +302,6 @@ static struct virtqueue *__vring_new_virtqueue(unsigned int index,
 				vq->avail_flags_shadow);
 
 	/* Put everything in free lists */
-	vq->free_head = 0;
 	for (i = 0; i < vring.num - 1; i++)
 		vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1);
 
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index 1fa9c2ed7428..04a2ad0cb1f9 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -82,6 +82,10 @@ struct vring {
 	struct vring_used *used;
 };
 
+struct vring_desc_state_split {
+	void *data;			/* Data for callback. */
+};
+
 /**
  * virtqueue - a queue to register buffers for sending or receiving.
  *
@@ -96,6 +100,7 @@ struct vring {
  * @last_used_idx: last used index we've seen
  * @avail_flags_shadow: last written value to avail->flags
  * @avail_idx_shadow: last written value to avail->idx in guest byte order
+ * @desc_state: cookie data associated with descritptors
  */
 struct virtqueue {
 	struct list_head list;
@@ -111,6 +116,7 @@ struct virtqueue {
 	u16 avail_idx_shadow;
 	dma_addr_t queue_dma_addr;
 	size_t queue_size_in_bytes;
+	struct vring_desc_state_split desc_state[];
 };
 
 /*
@@ -170,6 +176,7 @@ static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
  * @out_sgs:	the number of scatterlists readable by other side
  * @in_sgs:	the number of scatterlists which are writable
  *		(after readable ones)
+ * @data:	the token identifying the buffer.
  *
  * Caller must ensure we don't call this with other virtqueue operations
  * at the same time (except where noted).
@@ -177,13 +184,15 @@ static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
  * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[],
-		      unsigned int out_sgs, unsigned int in_sgs);
+		      unsigned int out_sgs, unsigned int in_sgs,
+		      void *data);
 
 /**
  * virtqueue_add_outbuf - expose output buffers to other end
  * @vq: the struct virtqueue we're talking about.
  * @sg: scatterlist (must be well-formed and terminated!)
  * @num: the number of entries in @sg readable by other side
+ * @data: the token identifying the buffer.
  *
  * Caller must ensure we don't call this with other virtqueue operations
  * at the same time (except where noted).
@@ -191,9 +200,10 @@ int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[],
  * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 static inline int virtqueue_add_outbuf(struct virtqueue *vq,
-				       struct scatterlist *sg, unsigned int num)
+				       struct scatterlist *sg, unsigned int num,
+				       void *data)
 {
-	return virtqueue_add_sgs(vq, &sg, num, 0);
+	return virtqueue_add_sgs(vq, &sg, num, 0, data);
 }
 
 /**
@@ -201,6 +211,7 @@ static inline int virtqueue_add_outbuf(struct virtqueue *vq,
  * @vq: the struct virtqueue we're talking about.
  * @sg: scatterlist (must be well-formed and terminated!)
  * @num: the number of entries in @sg writable by other side
+ * @data: the token identifying the buffer.
  *
  * Caller must ensure we don't call this with other virtqueue operations
  * at the same time (except where noted).
@@ -208,9 +219,10 @@ static inline int virtqueue_add_outbuf(struct virtqueue *vq,
  * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 static inline int virtqueue_add_inbuf(struct virtqueue *vq,
-				      struct scatterlist *sg, unsigned int num)
+				      struct scatterlist *sg, unsigned int num,
+				      void *data)
 {
-	return virtqueue_add_sgs(vq, &sg, 0, num);
+	return virtqueue_add_sgs(vq, &sg, 0, num, data);
 }
 
 /**
@@ -240,7 +252,7 @@ void virtqueue_kick(struct virtqueue *vq);
  * Caller must ensure we don't call this with other virtqueue
  * operations at the same time (except where noted).
  *
- * Returns NULL if there are no used buffers, or the memory buffer
+ * Returns NULL if there are no used buffers, or the "data" token
  * handed to virtqueue_add_*().
  */
 void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:12:05 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:12:05 +0100
Subject: [PATCH 2/3] virtio: replace virtio_sg with common scatterlist
In-Reply-To: <20250214101206.2876051-1-a.fatoum@pengutronix.de>
References: <20250214101206.2876051-1-a.fatoum@pengutronix.de>
Message-ID: <20250214101206.2876051-2-a.fatoum@pengutronix.de>

Now that we have a basic scatterlist implementation in barebox, let's
switch virtio to use it instead of the virtio_sg knock-off.

This introduces no functional change, but will make porting virtio
driver from Linux easier in future.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/block/virtio_blk.c      | 13 ++++----
 drivers/hw_random/virtio-rng.c  | 11 +++----
 drivers/input/virtio_input.c    | 12 +++----
 drivers/net/virtio.c            | 46 +++++++++++++--------------
 drivers/serial/virtio_console.c | 16 +++++-----
 drivers/virtio/virtio_ring.c    | 55 +++++++++++++++++++--------------
 include/linux/virtio.h          | 18 -----------
 include/linux/virtio_ring.h     | 19 ++++++------
 8 files changed, 87 insertions(+), 103 deletions(-)

diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index cbef500d59b3..3ee7972fe859 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -23,20 +23,20 @@ static int virtio_blk_do_req(struct virtio_blk_priv *priv, void *buffer,
 			     sector_t sector, blkcnt_t blkcnt, u32 type)
 {
 	unsigned int num_out = 0, num_in = 0;
-	struct virtio_sg *sgs[3];
-	u8 status;
+	struct scatterlist hdr_sg, data_sg, status_sg, *sgs[3];
+	u8 status = VIRTIO_BLK_S_IOERR;
 	int ret;
 
 	struct virtio_blk_outhdr out_hdr = {
 		.type = cpu_to_virtio32(priv->vdev, type),
 		.sector = cpu_to_virtio64(priv->vdev, sector),
 	};
-	struct virtio_sg hdr_sg = { &out_hdr, sizeof(out_hdr) };
-	struct virtio_sg data_sg = { buffer, blkcnt * 512 };
-	struct virtio_sg status_sg = { &status, sizeof(status) };
 
+	sg_init_one(&hdr_sg, &out_hdr, sizeof(out_hdr));
 	sgs[num_out++] = &hdr_sg;
 
+	sg_init_one(&data_sg, buffer, blkcnt * 512);
+
 	switch(type) {
 	case VIRTIO_BLK_T_OUT:
 		sgs[num_out++] = &data_sg;
@@ -46,9 +46,10 @@ static int virtio_blk_do_req(struct virtio_blk_priv *priv, void *buffer,
 		break;
 	}
 
+	sg_init_one(&status_sg, &status, sizeof(status));
 	sgs[num_out + num_in++] = &status_sg;
 
-	ret = virtqueue_add(priv->vq, sgs, num_out, num_in);
+	ret = virtqueue_add_sgs(priv->vq, sgs, num_out, num_in);
 	if (ret)
 		return ret;
 
diff --git a/drivers/hw_random/virtio-rng.c b/drivers/hw_random/virtio-rng.c
index f0a3d3cb74e7..6c283c784fb7 100644
--- a/drivers/hw_random/virtio-rng.c
+++ b/drivers/hw_random/virtio-rng.c
@@ -32,19 +32,16 @@ static int virtio_rng_read(struct hwrng *hwrng, void *data, size_t len, bool wai
 {
 	int ret;
 	unsigned int rsize;
-	unsigned char buf[BUFFER_SIZE] __aligned(4);
+	unsigned char buf[BUFFER_SIZE] __aligned(8);
 	unsigned char *ptr = data;
-	struct virtio_sg sg;
-	struct virtio_sg *sgs[1];
+	struct scatterlist sg;
 	struct virtrng_info *vi = to_virtrng_info(hwrng);
 	size_t remaining = len;
 
 	while (remaining) {
-		sg.addr = buf;
-		sg.length = min(remaining, sizeof(buf));
-		sgs[0] = &sg;
+		sg_init_one(&sg, buf, min(remaining, sizeof(buf)));
 
-		ret = virtqueue_add(vi->rng_vq, sgs, 0, 1);
+		ret = virtqueue_add_inbuf(vi->rng_vq, &sg, 1);
 		if (ret)
 			return ret;
 
diff --git a/drivers/input/virtio_input.c b/drivers/input/virtio_input.c
index 655a9051726a..cdcee556a6c7 100644
--- a/drivers/input/virtio_input.c
+++ b/drivers/input/virtio_input.c
@@ -25,9 +25,9 @@ struct virtio_input {
 static void virtinput_queue_evtbuf(struct virtio_input *vi,
 				   struct virtio_input_event *evtbuf)
 {
-	struct virtio_sg sg[1];
-	virtio_sg_init_one(sg, evtbuf, sizeof(*evtbuf));
-	virtqueue_add_inbuf(vi->evt, sg, 1);
+	struct scatterlist sg;
+	sg_init_one(&sg, evtbuf, sizeof(*evtbuf));
+	virtqueue_add_inbuf(vi->evt, &sg, 1);
 }
 
 static int virtinput_recv_events(struct virtio_input *vi)
@@ -63,7 +63,7 @@ static int virtinput_send_status(struct sound_card *beeper, unsigned freq, unsig
 {
 	struct virtio_input *vi = container_of(beeper, struct virtio_input, beeper);
 	struct virtio_input_event *stsbuf;
-	struct virtio_sg sg[1];
+	struct scatterlist sg;
 	u16 code;
 	int rc;
 
@@ -76,9 +76,9 @@ static int virtinput_send_status(struct sound_card *beeper, unsigned freq, unsig
 	stsbuf->type  = cpu_to_le16(EV_SND);
 	stsbuf->code  = cpu_to_le16(code);
 	stsbuf->value = cpu_to_le32(freq);
-	virtio_sg_init_one(sg, stsbuf, sizeof(*stsbuf));
+	sg_init_one(&sg, stsbuf, sizeof(*stsbuf));
 
-	rc = virtqueue_add_outbuf(vi->sts, sg, 1);
+	rc = virtqueue_add_outbuf(vi->sts, &sg, 1);
 	virtqueue_kick(vi->sts);
 
 	if (rc != 0)
diff --git a/drivers/net/virtio.c b/drivers/net/virtio.c
index 0c8a88530f0f..26a1dde5199a 100644
--- a/drivers/net/virtio.c
+++ b/drivers/net/virtio.c
@@ -46,18 +46,18 @@ static inline struct virtio_net_priv *to_priv(struct eth_device *edev)
 static int virtio_net_start(struct eth_device *edev)
 {
 	struct virtio_net_priv *priv = to_priv(edev);
-	struct virtio_sg sg;
-	struct virtio_sg *sgs[] = { &sg };
+	struct scatterlist sg;
 	int i;
 
 	if (!priv->rx_running) {
-		/* receive buffer length is always 1526 */
-		sg.length = VIRTIO_NET_RX_BUF_SIZE;
 
 		/* setup the receive buffer address */
 		for (i = 0; i < VIRTIO_NET_NUM_RX_BUFS; i++) {
-			sg.addr = priv->rx_buff[i];
-			virtqueue_add(priv->rx_vq, sgs, 0, 1);
+			/* receive buffer length is always 1526 */
+			sg.length = VIRTIO_NET_RX_BUF_SIZE;
+
+			sg_init_one(&sg, priv->rx_buff[i], VIRTIO_NET_RX_BUF_SIZE);
+			virtqueue_add_inbuf(priv->rx_vq, &sg, 1);
 		}
 
 		virtqueue_kick(priv->rx_vq);
@@ -72,22 +72,21 @@ static int virtio_net_start(struct eth_device *edev)
 static int virtio_net_send(struct eth_device *edev, void *packet, int length)
 {
 	struct virtio_net_priv *priv = to_priv(edev);
-	struct virtio_net_hdr_v1 hdr_v1;
-	struct virtio_net_hdr hdr;
-	struct virtio_sg hdr_sg;
-	struct virtio_sg data_sg = { packet, length };
-	struct virtio_sg *sgs[] = { &hdr_sg, &data_sg };
+	struct virtio_net_hdr_v1 hdr_v1 = {};
+	struct virtio_net_hdr hdr = {};
+	struct scatterlist sgs[2];
 	int ret;
 
+	sg_init_table(sgs, ARRAY_SIZE(sgs));
+
 	if (priv->net_hdr_len == sizeof(struct virtio_net_hdr))
-		hdr_sg.addr = &hdr;
+		sg_set_buf(&sgs[0], &hdr, priv->net_hdr_len);
 	else
-		hdr_sg.addr = &hdr_v1;
+		sg_set_buf(&sgs[0], &hdr_v1, priv->net_hdr_len);
 
-	hdr_sg.length = priv->net_hdr_len;
-	memset(hdr_sg.addr, 0, priv->net_hdr_len);
+	sg_set_buf(&sgs[1], packet, length);
 
-	ret = virtqueue_add(priv->tx_vq, sgs, 2, 0);
+	ret = virtqueue_add_outbuf(priv->tx_vq, sgs, ARRAY_SIZE(sgs));
 	if (ret)
 		return ret;
 
@@ -104,24 +103,23 @@ static int virtio_net_send(struct eth_device *edev, void *packet, int length)
 static void virtio_net_recv(struct eth_device *edev)
 {
 	struct virtio_net_priv *priv = to_priv(edev);
-	struct virtio_sg sg;
-	struct virtio_sg *sgs[] = { &sg };
+	struct scatterlist sg;
 	unsigned int len;
-	void *buf;
+	void *buf, *addr;
 
-	sg.addr = virtqueue_get_buf(priv->rx_vq, &len);
-	if (!sg.addr)
+	addr = virtqueue_get_buf(priv->rx_vq, &len);
+	if (!addr)
 		return;
 
-	sg.length = VIRTIO_NET_RX_BUF_SIZE;
+	sg_init_one(&sg, addr, VIRTIO_NET_RX_BUF_SIZE);
 
-	buf = sg.addr + priv->net_hdr_len;
+	buf = sg.address + priv->net_hdr_len;
 	len -= priv->net_hdr_len;
 
 	net_receive(edev, buf, len);
 
 	/* Put the buffer back to the rx ring */
-	virtqueue_add(priv->rx_vq, sgs, 0, 1);
+	virtqueue_add_inbuf(priv->rx_vq, &sg, 1);
 }
 
 static void virtio_net_stop(struct eth_device *dev)
diff --git a/drivers/serial/virtio_console.c b/drivers/serial/virtio_console.c
index a4adb77610f6..eb3b1158171d 100644
--- a/drivers/serial/virtio_console.c
+++ b/drivers/serial/virtio_console.c
@@ -41,15 +41,15 @@ static void put_chars(struct virtio_console *virtcons, const char *buf, int coun
 {
 	struct virtqueue *out_vq = virtcons->out_vq;
 	unsigned int len;
-	struct virtio_sg *sgs[1] = {
-		&(struct virtio_sg) { .addr = (void *)buf, .length = count }
-	};
+	struct scatterlist sg;
+
+	sg_init_one(&sg, buf, count);
 
 	/*
 	 * add_buf wants a token to identify this buffer: we hand it
 	 * any non-NULL pointer, since there's only ever one buffer.
 	 */
-	if (virtqueue_add(out_vq, sgs, 1, 0) >= 0) {
+	if (virtqueue_add_outbuf(out_vq, &sg, 1) >= 0) {
 		/* Tell Host to go! */
 		virtqueue_kick(out_vq);
 		/* Chill out until it's done with the buffer. */
@@ -71,12 +71,12 @@ static void virtcons_putc(struct console_device *cdev, char c)
  */
 static void add_inbuf(struct virtio_console *virtcons)
 {
-	struct virtio_sg *sgs[1] = { &(struct virtio_sg) {
-		.addr = virtcons->inbuf, .length = sizeof(virtcons->inbuf) }
-	};
+	struct scatterlist sg;
+
+	sg_init_one(&sg, virtcons->inbuf, sizeof(virtcons->inbuf));
 
 	/* We should always be able to add one buffer to an empty queue. */
-	if (virtqueue_add(virtcons->in_vq, sgs, 0, 1) < 0)
+	if (virtqueue_add_inbuf(virtcons->in_vq, &sg, 1) < 0)
 		BUG();
 	virtqueue_kick(virtcons->in_vq);
 }
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index b0b402834aca..cd3677ff73f9 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -29,10 +29,12 @@ static inline struct device *vring_dma_dev(const struct virtqueue *vq)
 
 /* Map one sg entry. */
 static dma_addr_t vring_map_one_sg(struct virtqueue *vq,
-				   struct virtio_sg *sg,
+				   struct scatterlist *sg,
 				   enum dma_data_direction direction)
 {
-	return dma_map_single(vring_dma_dev(vq), sg->addr, sg->length, direction);
+	return dma_map_single(vring_dma_dev(vq),
+			      sg->address, sg->length,
+			      direction);
 }
 
 static int vring_mapping_error(struct virtqueue *vq,
@@ -55,11 +57,12 @@ static void vring_unmap_one(struct virtqueue *vq,
 		       DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
-int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
-		  unsigned int out_sgs, unsigned int in_sgs)
+int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[],
+		      unsigned int out_sgs, unsigned int in_sgs)
 {
 	struct vring_desc *desc;
 	unsigned int total_sg = out_sgs + in_sgs;
+	struct scatterlist *sg;
 	unsigned int i, err_idx, n, avail, descs_used, uninitialized_var(prev);
 	int head;
 
@@ -85,33 +88,37 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
 	}
 
 	for (n = 0; n < out_sgs; n++) {
-		struct virtio_sg *sg = sgs[n];
-		dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_TO_DEVICE);
-		if (vring_mapping_error(vq, addr))
-			goto unmap_release;
+		for (sg = sgs[n]; sg; sg = sg_next(sg)) {
+			dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_TO_DEVICE);
+			if (vring_mapping_error(vq, addr))
+				goto unmap_release;
 
+			desc[i].flags = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT);
+			desc[i].addr = cpu_to_virtio64(vq->vdev, addr);
+			desc[i].len = cpu_to_virtio32(vq->vdev, sg->length);
 
-		desc[i].flags = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT);
-		desc[i].addr = cpu_to_virtio64(vq->vdev, addr);
-		desc[i].len = cpu_to_virtio32(vq->vdev, sg->length);
-
-		prev = i;
-		i = virtio16_to_cpu(vq->vdev, desc[i].next);
+			prev = i;
+			i = virtio16_to_cpu(vq->vdev, desc[i].next);
+		}
 	}
+
 	for (; n < (out_sgs + in_sgs); n++) {
-		struct virtio_sg *sg = sgs[n];
-		dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_FROM_DEVICE);
-		if (vring_mapping_error(vq, addr))
-			goto unmap_release;
+		for (sg = sgs[n]; sg; sg = sg_next(sg)) {
+			struct scatterlist *sg = sgs[n];
+			dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_FROM_DEVICE);
+			if (vring_mapping_error(vq, addr))
+				goto unmap_release;
 
-		desc[i].flags = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT |
-						VRING_DESC_F_WRITE);
-		desc[i].addr = cpu_to_virtio64(vq->vdev, addr);
-		desc[i].len = cpu_to_virtio32(vq->vdev, sg->length);
+			desc[i].flags = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT |
+							VRING_DESC_F_WRITE);
+			desc[i].addr = cpu_to_virtio64(vq->vdev, addr);
+			desc[i].len = cpu_to_virtio32(vq->vdev, sg->length);
 
-		prev = i;
-		i = virtio16_to_cpu(vq->vdev, desc[i].next);
+			prev = i;
+			i = virtio16_to_cpu(vq->vdev, desc[i].next);
+		}
 	}
+
 	/* Last one doesn't continue */
 	desc[prev].flags &= cpu_to_virtio16(vq->vdev, ~VRING_DESC_F_NEXT);
 
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index a4a54531ca63..3d4c88336055 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -13,24 +13,6 @@ struct virtio_device_id {
 };
 #define VIRTIO_DEV_ANY_ID	0xffffffff
 
-/**
- * virtio scatter-gather struct
- *
- * @addr:		sg buffer address
- * @lengh:		sg buffer length
- */
-struct virtio_sg {
-	void *addr;
-	size_t length;
-};
-
-static inline void virtio_sg_init_one(struct virtio_sg *sg,
-				      void *addr, size_t length)
-{
-	sg[0].addr = addr;
-	sg[0].length = length;
-}
-
 struct virtio_config_ops;
 
 /**
diff --git a/include/linux/virtio_ring.h b/include/linux/virtio_ring.h
index bdef47b0fa6c..1fa9c2ed7428 100644
--- a/include/linux/virtio_ring.h
+++ b/include/linux/virtio_ring.h
@@ -10,6 +10,7 @@
 #define _LINUX_VIRTIO_RING_H
 
 #include <linux/virtio_types.h>
+#include <linux/scatterlist.h>
 
 /* This marks a buffer as continuing via the next field */
 #define VRING_DESC_F_NEXT		1
@@ -161,10 +162,8 @@ static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
 	return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
 }
 
-struct virtio_sg;
-
 /**
- * virtqueue_add - expose buffers to other end
+ * virtqueue_add_sgs - expose buffers to other end
  *
  * @vq:		the struct virtqueue we're talking about
  * @sgs:	array of terminated scatterlists
@@ -177,8 +176,8 @@ struct virtio_sg;
  *
  * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
-int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
-		  unsigned int out_sgs, unsigned int in_sgs);
+int virtqueue_add_sgs(struct virtqueue *vq, struct scatterlist *sgs[],
+		      unsigned int out_sgs, unsigned int in_sgs);
 
 /**
  * virtqueue_add_outbuf - expose output buffers to other end
@@ -192,9 +191,9 @@ int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
  * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 static inline int virtqueue_add_outbuf(struct virtqueue *vq,
-                                      struct virtio_sg *sg, unsigned int num)
+				       struct scatterlist *sg, unsigned int num)
 {
-	return virtqueue_add(vq, &sg, num, 0);
+	return virtqueue_add_sgs(vq, &sg, num, 0);
 }
 
 /**
@@ -209,9 +208,9 @@ static inline int virtqueue_add_outbuf(struct virtqueue *vq,
  * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
  */
 static inline int virtqueue_add_inbuf(struct virtqueue *vq,
-                                     struct virtio_sg *sg, unsigned int num)
+				      struct scatterlist *sg, unsigned int num)
 {
-	return virtqueue_add(vq, &sg, 0, num);
+	return virtqueue_add_sgs(vq, &sg, 0, num);
 }
 
 /**
@@ -219,7 +218,7 @@ static inline int virtqueue_add_inbuf(struct virtqueue *vq,
  *
  * @vq:		the struct virtqueue
  *
- * After one or more virtqueue_add() calls, invoke this to kick
+ * After one or more virtqueue_add_sgs() calls, invoke this to kick
  * the other side.
  *
  * Caller must ensure we don't call this with other virtqueue
-- 
2.39.5



From s.hauer at pengutronix.de  Fri Feb 14 02:31:00 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Feb 2025 11:31:00 +0100
Subject: [PATCH v3 0/6] Initial support for Allwinner A64 SoC
In-Reply-To: <20250212104842.504-1-jmaselbas@zdiv.net>
References: <20250212104842.504-1-jmaselbas@zdiv.net>
Message-ID: <173952906062.1543284.10772766948007639190.b4-ty@pengutronix.de>


On Wed, 12 Feb 2025 11:48:36 +0100, Jules Maselbas wrote:
> This series adds an initial support for Allwinner, currently only
> targetting the Pine64+ board, based on the A64 SoC.
> 
> This first series is intented as a second boot image only, that can
> be started from u-boot. This series provides the bare minimal for
> barebox to load the next OS from sd/mmc.
> 
> [...]

Applied, thanks!

[1/6] clk: divider: add error code propagation
      https://git.pengutronix.de/cgit/barebox/commit/?id=2faf9ac88f41 (link may not be stable)
[2/6] clk: Add clock driver for sun50i-a64
      https://git.pengutronix.de/cgit/barebox/commit/?id=8a8afdc9afe0 (link may not be stable)
[3/6] pinctrl: Add sun50i-a64 pinctrl driver
      https://git.pengutronix.de/cgit/barebox/commit/?id=199f3e78b059 (link may not be stable)
[4/6] mci: Add sunxi-mmc driver
      https://git.pengutronix.de/cgit/barebox/commit/?id=085180b15e4c (link may not be stable)
[5/6] ARM: sunxi: Introduce mach-sunxi
      https://git.pengutronix.de/cgit/barebox/commit/?id=da8c77923696 (link may not be stable)
[6/6] Documentation: sunxi: Add some documentation
      https://git.pengutronix.de/cgit/barebox/commit/?id=0429625f4d83 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 14 02:31:00 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 14 Feb 2025 11:31:00 +0100
Subject: (subset) [PATCH 0/6] Initial support for Allwinner A64 SoC
In-Reply-To: <20241107145722.5145-1-jmaselbas@zdiv.net>
References: <20241107145722.5145-1-jmaselbas@zdiv.net>
Message-ID: <173952906060.1543284.15217476443299658555.b4-ty@pengutronix.de>


On Thu, 07 Nov 2024 15:57:16 +0100, Jules Maselbas wrote:
> This series adds the initial support for Allwinner, currently only
> targetting the Pine64+ board, based on the A64 SoC.
> 
> This first series is intented as a second boot image only, that can
> be started from u-boot. This series provides the bare minimal so
> barebox can load the next OS from sd/mmc.
> 
> [...]

Applied, thanks!

[2/6] clk: divider: add error code propagation
      https://git.pengutronix.de/cgit/barebox/commit/?id=2faf9ac88f41 (link may not be stable)
[3/6] clk: Add clock driver for sun50i-a64
      https://git.pengutronix.de/cgit/barebox/commit/?id=8a8afdc9afe0 (link may not be stable)
[4/6] pinctrl: Add sun50i-a64 pinctrl driver
      https://git.pengutronix.de/cgit/barebox/commit/?id=199f3e78b059 (link may not be stable)
[5/6] mci: Add sunxi-mmc driver
      https://git.pengutronix.de/cgit/barebox/commit/?id=085180b15e4c (link may not be stable)
[6/6] ARM: sunxi: Introduce mach-sunxi
      https://git.pengutronix.de/cgit/barebox/commit/?id=da8c77923696 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From a.fatoum at pengutronix.de  Fri Feb 14 02:31:14 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:31:14 +0100
Subject: [PATCH] mount: support specifying mount -o options more than once
Message-ID: <20250214103114.2900899-1-a.fatoum@pengutronix.de>

Specifying -o more than once is useful for scripts: A mount.9P script
for example can specify some default options and the caller of the
script can specify an extra -o to add extra options.

This is supported by normal mount(1), but wasn't so far in the barebox
variant. Remedy that.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/mount.c | 41 ++++++++++++++++++++++++++++++-----------
 1 file changed, 30 insertions(+), 11 deletions(-)

diff --git a/commands/mount.c b/commands/mount.c
index 81a40e951076..002a38e1959f 100644
--- a/commands/mount.c
+++ b/commands/mount.c
@@ -9,14 +9,18 @@
 #include <errno.h>
 #include <getopt.h>
 #include <linux/err.h>
+#include <stringlist.h>
 
 static int do_mount(int argc, char *argv[])
 {
-	int opt, verbose = 0;
+	int ret = 0, opt, verbose = 0;
 	struct driver *drv;
 	const char *type = NULL;
 	const char *mountpoint, *devstr;
-	const char *fsoptions = NULL;
+	struct string_list fsoption_list;
+	char *fsoptions = NULL;
+
+	string_list_init(&fsoption_list);
 
 	while ((opt = getopt(argc, argv, "ao:t:v")) > 0) {
 		switch (opt) {
@@ -27,7 +31,7 @@ static int do_mount(int argc, char *argv[])
 			type = optarg;
 			break;
 		case 'o':
-			fsoptions = optarg;
+			string_list_add(&fsoption_list, optarg);
 			break;
 		case 'v':
 			verbose++;
@@ -56,11 +60,22 @@ static int do_mount(int argc, char *argv[])
 			}
 		}
 
-		return 0;
+		goto out;
+	}
+
+	if (argc == 0) {
+		ret = COMMAND_ERROR_USAGE;
+		goto out;
 	}
 
 	devstr = argv[0];
 
+	fsoptions = string_list_join(&fsoption_list, " ");
+	if (!fsoptions) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
 	if (argc == 1) {
 		struct cdev *cdev;
 		const char *path;
@@ -70,8 +85,10 @@ static int do_mount(int argc, char *argv[])
 		device_detect_by_name(devstr);
 
 		cdev = cdev_by_name(devstr);
-		if (!cdev)
-			return -ENOENT;
+		if (!cdev) {
+			ret = -ENOENT;
+			goto out;
+		}
 
 		path = cdev_mount_default(cdev, fsoptions);
 		if (IS_ERR(path))
@@ -79,12 +96,9 @@ static int do_mount(int argc, char *argv[])
 
 		printf("mounted /dev/%s on %s\n", devstr, path);
 
-		return 0;
+		goto out;
 	}
 
-	if (argc < 2)
-		return COMMAND_ERROR_USAGE;
-
 	if (argc == 3) {
 		/*
 		 * Old behaviour: mount <dev> <type> <mountpoint>
@@ -95,7 +109,12 @@ static int do_mount(int argc, char *argv[])
 		mountpoint = argv[1];
 	}
 
-	return mount(devstr, type, mountpoint, fsoptions);
+	ret = mount(devstr, type, mountpoint, fsoptions);
+
+out:
+	free(fsoptions);
+	string_list_free(&fsoption_list);
+	return ret;
 }
 
 BAREBOX_CMD_HELP_START(mount)
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:10 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:10 +0100
Subject: [PATCH 0/7] commands: boot: add support for overriding boot artifacts
Message-ID: <20250214104817.2975052-1-a.fatoum@pengutronix.de>

Replacing part of the boot artifacts is a common development use case,
e.g. to load the kernel from the network, but otherwise boot the
bootloader spec file as-is or to inject an initrd into an existing boot
flow (e.g. rsinit to enable usb9pfs boot).

This series adds a simple to use way to achieve that.

Ahmad Fatoum (7):
  bootm: add helper functions for checking if FIT image is used
  boot: move global.linux.bootargs.dyn. to common code
  blspec: don't clobber bootm.image on boot attempt
  fastboot: drop useless bootm.image clobber
  bootm: don't clobber global.bootm. variables after script boot fails
  bootm: retire bootm_has_initrd
  commands: boot: add support for overriding boot artifacts

 Documentation/user/booting-linux.rst |   8 ++
 arch/arm/lib32/bootm.c               |  18 ++-
 arch/kvx/lib/bootm.c                 |  23 ++--
 commands/boot.c                      |  53 +++++++-
 common/Kconfig                       |   7 ++
 common/blspec.c                      |   7 +-
 common/boot.c                        |  14 ++-
 common/booti.c                       |  10 +-
 common/bootm.c                       | 173 +++++++++++++++++++--------
 common/fastboot.c                    |   3 -
 include/bootm.h                      |  23 +++-
 11 files changed, 249 insertions(+), 90 deletions(-)

-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:13 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:13 +0100
Subject: [PATCH 3/7] blspec: don't clobber bootm.image on boot attempt
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <20250214104817.2975052-4-a.fatoum@pengutronix.de>

bootm_data_init_defaults() initialized the defaults from global
variables and thus the blspec code cleared the global variables.

This roundabout way can be confusing to users as a failing bootloader
spec boot would clobber these variables.

Let's improve upon this by just ignoring the variables explicitly
instead of clobbering them.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/blspec.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/common/blspec.c b/common/blspec.c
index 8a7f996e78d2..1cbadf8963af 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -81,12 +81,8 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
 		.dryrun = dryrun,
 	};
 
-	globalvar_set("bootm.image", "");
-	globalvar_set("bootm.oftree", "");
-	globalvar_set("bootm.initrd", "");
-
 	bootm_data_init_defaults(&data);
-
+	data.os_file = data.oftree_file = data.initrd_file = NULL;
 	data.verbose = max(verbose, data.verbose);
 
 	devicetree = blspec_entry_var_get(entry, "devicetree");
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:15 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:15 +0100
Subject: [PATCH 5/7] bootm: don't clobber global.bootm. variables after script boot fails
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <20250214104817.2975052-6-a.fatoum@pengutronix.de>

While there is global.linux.bootargs.dyn to avoid boot script variables
contaminating later boot targets, there is no such thing for the
global.bootm. variables and as such it was up to the boot targets to
either ignore the variables or to override them.

The proper way would to expect the boot script boot callback to restore
the variables as they were before, so let's do that.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/boot.c   | 11 ++++++++---
 common/bootm.c  | 17 +++++++++++++++++
 include/bootm.h |  1 +
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/common/boot.c b/common/boot.c
index 42818c6e2154..2530a5bbeeac 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -74,20 +74,22 @@ static int bootscript_boot(struct bootentry *entry, int verbose, int dryrun)
 	struct bootentry_script *bs = container_of(entry, struct bootentry_script, entry);
 	int ret;
 
-	struct bootm_data data = {};
+	struct bootm_data backup = {}, data = {};
 
 	if (dryrun == 1) {
 		printf("Would run %s\n", bs->scriptpath);
 		return 0;
 	}
 
+	bootm_data_init_defaults(&backup);
+
 	globalvar_add_simple("linux.bootargs.dyn.ip", NULL);
 	globalvar_add_simple("linux.bootargs.dyn.root", NULL);
 
 	ret = run_command(bs->scriptpath);
 	if (ret) {
 		pr_err("Running script '%s' failed: %s\n", bs->scriptpath, strerror(-ret));
-		return ret;
+		goto out;
 	}
 
 	bootm_data_init_defaults(&data);
@@ -97,7 +99,10 @@ static int bootscript_boot(struct bootentry *entry, int verbose, int dryrun)
 	if (dryrun >= 2)
 		data.dryrun = dryrun - 1;
 
-	return bootm_boot(&data);
+	ret = bootm_boot(&data);
+out:
+	bootm_data_restore_defaults(&backup);
+	return ret;
 }
 
 static unsigned int boot_watchdog_timeout;
diff --git a/common/bootm.c b/common/bootm.c
index d1dbf6890f6f..d24b18b41cb2 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -68,6 +68,23 @@ void bootm_data_init_defaults(struct bootm_data *data)
 	data->dryrun = bootm_dryrun;
 }
 
+void bootm_data_restore_defaults(const struct bootm_data *data)
+{
+	globalvar_set("bootm.oftree", data->oftree_file);
+	globalvar_set("bootm.tee", data->tee_file);
+	globalvar_set("bootm.image", data->os_file);
+	pr_setenv("global.bootm.image.loadaddr", "0x%lx", data->os_address);
+	pr_setenv("global.bootm.initrd.loadaddr", "0x%lx", data->initrd_address);
+	globalvar_set("bootm.initrd", data->initrd_file);
+	globalvar_set("bootm.root_dev", data->root_dev);
+	bootm_set_verify_mode(data->verify);
+	bootm_appendroot = data->appendroot;
+	bootm_provide_machine_id = data->provide_machine_id;
+	bootm_provide_hostname = data->provide_hostname;
+	bootm_verbosity = data->verbose;
+	bootm_dryrun = data->dryrun;
+}
+
 static enum bootm_verify bootm_verify_mode = BOOTM_VERIFY_HASH;
 
 enum bootm_verify bootm_get_verify_mode(void)
diff --git a/include/bootm.h b/include/bootm.h
index 98ac5e5a9374..fdec137771f0 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -138,6 +138,7 @@ static inline int bootm_verbose(struct image_data *data)
 #endif
 
 void bootm_data_init_defaults(struct bootm_data *data);
+void bootm_data_restore_defaults(const struct bootm_data *data);
 
 int bootm_load_os(struct image_data *data, unsigned long load_address);
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:14 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:14 +0100
Subject: [PATCH 4/7] fastboot: drop useless bootm.image clobber
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <20250214104817.2975052-5-a.fatoum@pengutronix.de>

Clobbering bootm.image before a fastboot boot is not useful, because no
code would look at bootm.image anyway.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/fastboot.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/common/fastboot.c b/common/fastboot.c
index acc91490a553..60bef0ec776b 100644
--- a/common/fastboot.c
+++ b/common/fastboot.c
@@ -419,8 +419,6 @@ static void __maybe_unused cb_boot(struct fastboot *fb, const char *opt)
 
 	fastboot_tx_print(fb, FASTBOOT_MSG_INFO, "Booting kernel..\n");
 
-	globalvar_set("bootm.image", "");
-
 	data.os_file = fb->tempname;
 
 	ret = bootm_boot(&data);
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:12 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:12 +0100
Subject: [PATCH 2/7] boot: move global.linux.bootargs.dyn. to common code
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <20250214104817.2975052-3-a.fatoum@pengutronix.de>

Instead of clearing these options by select boot targets prior to boot,
let's instead clear them directly after the boot aborting.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/blspec.c   | 1 -
 common/boot.c     | 3 ++-
 common/fastboot.c | 1 -
 3 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/common/blspec.c b/common/blspec.c
index ea334e18718a..8a7f996e78d2 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -81,7 +81,6 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
 		.dryrun = dryrun,
 	};
 
-	globalvar_set_match("linux.bootargs.dyn.", "");
 	globalvar_set("bootm.image", "");
 	globalvar_set("bootm.oftree", "");
 	globalvar_set("bootm.initrd", "");
diff --git a/common/boot.c b/common/boot.c
index ced3b3a3477c..42818c6e2154 100644
--- a/common/boot.c
+++ b/common/boot.c
@@ -83,7 +83,6 @@ static int bootscript_boot(struct bootentry *entry, int verbose, int dryrun)
 
 	globalvar_add_simple("linux.bootargs.dyn.ip", NULL);
 	globalvar_add_simple("linux.bootargs.dyn.root", NULL);
-	globalvar_set_match("linux.bootargs.dyn.", "");
 
 	ret = run_command(bs->scriptpath);
 	if (ret) {
@@ -162,6 +161,8 @@ int boot_entry(struct bootentry *be, int verbose, int dryrun)
 	if (ret && ret != -ENOMEDIUM)
 		pr_err("Booting entry '%s' failed: %pe\n", be->title, ERR_PTR(ret));
 
+	globalvar_set_match("linux.bootargs.dyn.", "");
+
 	return ret;
 }
 
diff --git a/common/fastboot.c b/common/fastboot.c
index 66b59ab9b0d7..acc91490a553 100644
--- a/common/fastboot.c
+++ b/common/fastboot.c
@@ -419,7 +419,6 @@ static void __maybe_unused cb_boot(struct fastboot *fb, const char *opt)
 
 	fastboot_tx_print(fb, FASTBOOT_MSG_INFO, "Booting kernel..\n");
 
-	globalvar_set_match("linux.bootargs.dyn.", "");
 	globalvar_set("bootm.image", "");
 
 	data.os_file = fb->tempname;
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:16 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:16 +0100
Subject: [PATCH 6/7] bootm: retire bootm_has_initrd
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <20250214104817.2975052-7-a.fatoum@pengutronix.de>

All what's done by bootm_has_initrd can be folded into bootm_load_initrd
by having it return a special value (NULL) to indicate that no initrd
is available.

The advantage of doing it in one function is that it simplifies
overriding the initrd in a follow-up commit

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/lib32/bootm.c | 18 ++++++++----------
 arch/kvx/lib/bootm.c   | 23 +++++++++++------------
 common/booti.c         | 10 +++++-----
 common/bootm.c         | 35 ++++++++++++++---------------------
 include/bootm.h        |  4 ++--
 5 files changed, 40 insertions(+), 50 deletions(-)

diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c
index aeb873a3a723..d3a4d99a5828 100644
--- a/arch/arm/lib32/bootm.c
+++ b/arch/arm/lib32/bootm.c
@@ -241,6 +241,7 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem,
 {
 	unsigned long kernel;
 	unsigned long initrd_start = 0, initrd_size = 0, initrd_end = 0;
+	const struct resource *initrd_res;
 	void *tee;
 	enum arm_security_state state = bootm_arm_security_state();
 	void *fdt_load_address = NULL;
@@ -259,16 +260,13 @@ static int __do_bootm_linux(struct image_data *data, unsigned long free_mem,
 		}
 	}
 
-	if (bootm_has_initrd(data)) {
-		ret = bootm_load_initrd(data, initrd_start);
-		if (ret)
-			return ret;
-	}
-
-	if (data->initrd_res) {
-		initrd_start = data->initrd_res->start;
-		initrd_end = data->initrd_res->end;
-		initrd_size = resource_size(data->initrd_res);
+	initrd_res = bootm_load_initrd(data, initrd_start);
+	if (IS_ERR(initrd_res)) {
+		return PTR_ERR(initrd_res);
+	} else if (initrd_res) {
+		initrd_start = initrd_res->start;
+		initrd_end = initrd_res->end;
+		initrd_size = resource_size(initrd_res);
 		free_mem = PAGE_ALIGN(initrd_end + 1);
 	}
 
diff --git a/arch/kvx/lib/bootm.c b/arch/kvx/lib/bootm.c
index 4c77f676ec0b..6c35b68f3d5d 100644
--- a/arch/kvx/lib/bootm.c
+++ b/arch/kvx/lib/bootm.c
@@ -54,6 +54,7 @@ static int do_boot_entry(struct image_data *data, boot_func_entry entry,
 
 static int do_boot_elf(struct image_data *data, struct elf_image *elf)
 {
+	const struct resource *initrd_res;
 	int ret;
 	void *fdt;
 	boot_func_entry entry;
@@ -61,21 +62,19 @@ static int do_boot_elf(struct image_data *data, struct elf_image *elf)
 
 	/* load initrd after the elf */
 	load_addr = PAGE_ALIGN((unsigned long) elf->high_addr);
-	if (bootm_has_initrd(data)) {
-		if (data->initrd_address != UIMAGE_INVALID_ADDRESS)
-			initrd_address = data->initrd_address;
-		else
-			initrd_address = load_addr;
+	if (data->initrd_address != UIMAGE_INVALID_ADDRESS)
+		initrd_address = data->initrd_address;
+	else
+		initrd_address = load_addr;
 
+	initrd_res = bootm_load_initrd(data, initrd_address);
+	if (IS_ERR(initrd_res)) {
+		printf("Failed to load initrd\n");
+		return ret;
+	} else if (initrd_res) {
 		printf("Loading initrd at 0x%lx\n", initrd_address);
-		ret = bootm_load_initrd(data, initrd_address);
-		if (ret) {
-			printf("Failed to load initrd\n");
-			return ret;
-		}
-
 		if (data->initrd_address == UIMAGE_INVALID_ADDRESS) {
-			load_addr += resource_size(data->initrd_res);
+			load_addr += resource_size(initrd_res);
 			load_addr = PAGE_ALIGN(load_addr);
 		}
 	}
diff --git a/common/booti.c b/common/booti.c
index e745ff696376..5efd4f97bbc2 100644
--- a/common/booti.c
+++ b/common/booti.c
@@ -58,12 +58,12 @@ void *booti_load_image(struct image_data *data, phys_addr_t *oftree)
 
 	if (oftree) {
 		unsigned long devicetree;
+		const struct resource *initrd_res;
 
-		if (bootm_has_initrd(data)) {
-			ret = bootm_load_initrd(data, image_end);
-			if (ret)
-				return ERR_PTR(ret);
-
+		initrd_res = bootm_load_initrd(data, image_end);
+		if (IS_ERR(initrd_res)) {
+			return ERR_CAST(initrd_res);
+		} else if (initrd_res) {
 			image_end += resource_size(data->initrd_res);
 			image_end = PAGE_ALIGN(image_end);
 		}
diff --git a/common/bootm.c b/common/bootm.c
index d24b18b41cb2..d2373f321c19 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -213,14 +213,6 @@ static bool fitconfig_has_ramdisk(struct image_data *data)
 	return fit_has_image(data->os_fit, data->fit_config, "ramdisk");
 }
 
-bool bootm_has_initrd(struct image_data *data)
-{
-	if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
-		return false;
-
-	return fitconfig_has_ramdisk(data) || data->initrd_file;
-}
-
 static int bootm_open_initrd_uimage(struct image_data *data)
 {
 	int ret;
@@ -262,19 +254,17 @@ static int bootm_open_initrd_uimage(struct image_data *data)
  *
  * Return: 0 on success, negative error code otherwise
  */
-int bootm_load_initrd(struct image_data *data, unsigned long load_address)
+const struct resource *
+bootm_load_initrd(struct image_data *data, unsigned long load_address)
 {
 	enum filetype type;
 	int ret;
 
 	if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
-		return -ENOSYS;
-
-	if (!bootm_has_initrd(data))
-		return -EINVAL;
+		return NULL;
 
 	if (data->initrd_res)
-		return 0;
+		return data->initrd_res;
 
 	if (fitconfig_has_ramdisk(data)) {
 		const void *initrd;
@@ -285,7 +275,7 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address)
 		if (ret) {
 			pr_err("Cannot open ramdisk image in FIT image: %s\n",
 					strerror(-ret));
-			return ret;
+			return ERR_PTR(ret);
 		}
 		data->initrd_res = request_sdram_region("initrd",
 				load_address,
@@ -295,17 +285,20 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address)
 					" 0x%08llx-0x%08llx\n",
 				(unsigned long long)load_address,
 				(unsigned long long)load_address + initrd_size - 1);
-			return -ENOMEM;
+			return ERR_PTR(-ENOMEM);
 		}
 		memcpy((void *)load_address, initrd, initrd_size);
 		pr_info("Loaded initrd from FIT image\n");
 		goto done1;
 	}
 
+	if (!data->initrd_file)
+		return NULL;
+
 	ret = file_name_detect_type(data->initrd_file, &type);
 	if (ret) {
 		pr_err("could not open initrd \"%s\": %s\n", data->initrd_file, strerror(-ret));
-		return ret;
+		return ERR_PTR(ret);
 	}
 
 	if (type == filetype_uimage) {
@@ -314,7 +307,7 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address)
 		if (ret) {
 			pr_err("loading initrd failed with %s\n",
 			       strerror(-ret));
-			return ret;
+			return ERR_PTR(ret);
 		}
 
 		num = uimage_part_num(data->initrd_part);
@@ -322,14 +315,14 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address)
 		data->initrd_res = uimage_load_to_sdram(data->initrd,
 			num, load_address);
 		if (!data->initrd_res)
-			return -ENOMEM;
+			return ERR_PTR(-ENOMEM);
 
 		goto done;
 	}
 
 	data->initrd_res = file_to_sdram(data->initrd_file, load_address);
 	if (!data->initrd_res)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 done:
 
@@ -343,7 +336,7 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address)
 		&data->initrd_res->start,
 		&data->initrd_res->end);
 
-	return 0;
+	return data->initrd_res;
 }
 
 static int bootm_open_oftree_uimage(struct image_data *data, size_t *size,
diff --git a/include/bootm.h b/include/bootm.h
index fdec137771f0..b86d06b0f55d 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -142,8 +142,8 @@ void bootm_data_restore_defaults(const struct bootm_data *data);
 
 int bootm_load_os(struct image_data *data, unsigned long load_address);
 
-bool bootm_has_initrd(struct image_data *data);
-int bootm_load_initrd(struct image_data *data, unsigned long load_address);
+const struct resource *
+bootm_load_initrd(struct image_data *data, unsigned long load_address);
 
 void *bootm_get_devicetree(struct image_data *data);
 int bootm_load_devicetree(struct image_data *data, void *fdt,
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:17 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:17 +0100
Subject: [PATCH 7/7] commands: boot: add support for overriding boot artifacts
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <20250214104817.2975052-8-a.fatoum@pengutronix.de>

Replacing part of the boot artifacts is a common development use case,
e.g. to load the kernel from the network, but otherwise boot the
bootloader spec file as-is or to inject an initrd into an existing boot
flow (e.g. rsinit to enable usb9pfs boot).

Add a simple to use way to achieve that.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/user/booting-linux.rst |   8 ++
 commands/boot.c                      |  53 +++++++++++++-
 common/Kconfig                       |   7 ++
 common/bootm.c                       | 106 +++++++++++++++++++++------
 include/bootm.h                      |  18 +++++
 5 files changed, 169 insertions(+), 23 deletions(-)

diff --git a/Documentation/user/booting-linux.rst b/Documentation/user/booting-linux.rst
index b26ada943a59..b49b2c93b1f3 100644
--- a/Documentation/user/booting-linux.rst
+++ b/Documentation/user/booting-linux.rst
@@ -161,6 +161,14 @@ This entry can be booted with ``boot mmc``. It can also be made the default by
 setting the ``global.boot.default`` variable to ``mmc`` and then calling
 ``boot`` without arguments.
 
+Especially for development, it can be useful to override only parts of
+the images used in a boot. To do so, set ``CONFIG_BOOT_OVERRIDE=y``
+and configure the overrides as arguments to the ``boot`` command::
+
+.. code-block:: sh
+
+  boot -o bootm.image=/mnt/tftp/oftree mmc
+
 .. _bootloader_spec:
 
 Boot Loader Specification
diff --git a/commands/boot.c b/commands/boot.c
index e4699520e8f5..820708380191 100644
--- a/commands/boot.c
+++ b/commands/boot.c
@@ -6,6 +6,7 @@
 #include <getopt.h>
 #include <malloc.h>
 #include <boot.h>
+#include <bootm.h>
 #include <complete.h>
 
 #include <linux/stat.h>
@@ -23,6 +24,42 @@ static char *next_word(void *context)
 	return strsep(context, " ");
 }
 
+static int boot_add_override(struct bootm_overrides *overrides, char *var)
+{
+	const char *val;
+
+	if (!IS_ENABLED(CONFIG_BOOT_OVERRIDE))
+		return -ENOSYS;
+
+	var += str_has_prefix(var, "global.");
+
+	val = parse_assignment(var);
+	if (!val) {
+		val = globalvar_get(var);
+		if (isempty(val))
+			val = NULL;
+	}
+
+	if (!strcmp(var, "bootm.image")) {
+		if (isempty(val))
+			return -EINVAL;
+		overrides->os_file = val;
+	} else if (!strcmp(var, "bootm.oftree")) {
+		overrides->oftree_file = val;
+	} else if (!strcmp(var, "bootm.initrd")) {
+		overrides->initrd_file = val;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static inline bool boot_has_overrides(const struct bootm_overrides *overrides)
+{
+	return overrides->os_file || overrides->oftree_file || overrides->initrd_file;
+}
+
 static int do_boot(int argc, char *argv[])
 {
 	char *freep = NULL;
@@ -31,11 +68,12 @@ static int do_boot(int argc, char *argv[])
 	unsigned default_menu_entry = 0;
 	struct bootentries *entries;
 	struct bootentry *entry;
+	struct bootm_overrides overrides = {};
 	void *handle;
 	const char *name;
 	char *(*next)(void *);
 
-	while ((opt = getopt(argc, argv, "vldmM:t:w:")) > 0) {
+	while ((opt = getopt(argc, argv, "vldmM:t:w:o:")) > 0) {
 		switch (opt) {
 		case 'v':
 			verbose++;
@@ -65,6 +103,11 @@ static int do_boot(int argc, char *argv[])
 		case 'w':
 			boot_set_watchdog_timeout(simple_strtoul(optarg, NULL, 0));
 			break;
+		case 'o':
+			ret = boot_add_override(&overrides, optarg);
+			if (ret)
+				return ret;
+			break;
 		default:
 			return COMMAND_ERROR_USAGE;
 		}
@@ -85,6 +128,8 @@ static int do_boot(int argc, char *argv[])
 	}
 
 	entries = bootentries_alloc();
+	if (boot_has_overrides(&overrides))
+		bootm_set_overrides(&overrides);
 
 	while ((name = next(&handle)) != NULL) {
 		if (!*name)
@@ -119,6 +164,8 @@ static int do_boot(int argc, char *argv[])
 
 	ret = 0;
 out:
+	if (boot_has_overrides(&overrides))
+		bootm_unset_overrides();
 	bootentries_free(entries);
 	free(freep);
 
@@ -150,6 +197,10 @@ BAREBOX_CMD_HELP_OPT ("-l","List available boot sources")
 BAREBOX_CMD_HELP_OPT ("-m","Show a menu with boot options")
 BAREBOX_CMD_HELP_OPT ("-M INDEX","Show a menu with boot options with entry INDEX preselected")
 BAREBOX_CMD_HELP_OPT ("-w SECS","Start watchdog with timeout SECS before booting")
+#ifdef CONFIG_BOOT_OVERRIDE
+BAREBOX_CMD_HELP_OPT ("-o VAR[=VAL]","override VAR (bootm.{image,oftree,initrd}) with VAL")
+BAREBOX_CMD_HELP_OPT ("            ","if VAL is not specified, the value of VAR is taken")
+#endif
 BAREBOX_CMD_HELP_OPT ("-t SECS","specify timeout in SECS")
 BAREBOX_CMD_HELP_END
 
diff --git a/common/Kconfig b/common/Kconfig
index b5fba72390d8..0ce99e98286c 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -599,6 +599,13 @@ menuconfig BOOTM
 	default y if COMMAND_SUPPORT
 	bool "bootm support"
 
+config BOOT_OVERRIDE
+	bool "Support partial override of boot entries"
+	depends on BOOTM
+	help
+	  Allow overriding of bootm image, oftree and initrd by passing
+	  -o as an argument to the boot command.
+
 config BOOTM_SHOW_TYPE
 	bool
 	depends on BOOTM && UIMAGE
diff --git a/common/bootm.c b/common/bootm.c
index d2373f321c19..80905d4cf1ce 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -17,6 +17,8 @@
 
 static LIST_HEAD(handler_list);
 
+static __maybe_unused struct bootm_overrides bootm_overrides;
+
 int register_image_handler(struct image_handler *handler)
 {
 	list_add_tail(&handler->list, &handler_list);
@@ -141,6 +143,23 @@ static inline bool image_is_uimage(struct image_data *data)
 	return IS_ENABLED(CONFIG_BOOTM_UIMAGE) && data->os;
 }
 
+static bool bootm_get_override(char **oldpath, const char *newpath)
+{
+	if (!IS_ENABLED(CONFIG_BOOT_OVERRIDE))
+		return false;
+	if (bootm_signed_images_are_forced())
+		return false;
+	if (!newpath)
+		return false;
+
+	if (oldpath && strcmp(*oldpath, newpath)) {
+		free(*oldpath);
+		*oldpath = *newpath ? xstrdup(newpath) : NULL;
+	}
+
+	return true;
+}
+
 /*
  * bootm_load_os() - load OS to RAM
  *
@@ -155,6 +174,12 @@ static inline bool image_is_uimage(struct image_data *data)
  */
 int bootm_load_os(struct image_data *data, unsigned long load_address)
 {
+	if (bootm_get_override(&data->os_file, bootm_overrides.os_file)) {
+		if (load_address == UIMAGE_INVALID_ADDRESS)
+			return -EINVAL;
+		goto os_file;
+	}
+
 	if (data->os_res)
 		return 0;
 
@@ -194,15 +219,15 @@ int bootm_load_os(struct image_data *data, unsigned long load_address)
 	if (IS_ENABLED(CONFIG_ELF) && data->elf)
 		return elf_load(data->elf);
 
-	if (data->os_file) {
-		data->os_res = file_to_sdram(data->os_file, load_address);
-		if (!data->os_res)
-			return -ENOMEM;
+os_file:
+	if (!data->os_file)
+		return -EINVAL;
 
-		return 0;
-	}
+	data->os_res = file_to_sdram(data->os_file, load_address);
+	if (!data->os_res)
+		return -ENOMEM;
 
-	return -EINVAL;
+	return 0;
 }
 
 static bool fitconfig_has_ramdisk(struct image_data *data)
@@ -263,6 +288,9 @@ bootm_load_initrd(struct image_data *data, unsigned long load_address)
 	if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
 		return NULL;
 
+	if (bootm_get_override(&data->initrd_file, bootm_overrides.initrd_file))
+		goto initrd_file;
+
 	if (data->initrd_res)
 		return data->initrd_res;
 
@@ -292,6 +320,7 @@ bootm_load_initrd(struct image_data *data, unsigned long load_address)
 		goto done1;
 	}
 
+initrd_file:
 	if (!data->initrd_file)
 		return NULL;
 
@@ -404,12 +433,17 @@ void *bootm_get_devicetree(struct image_data *data)
 {
 	enum filetype type;
 	struct fdt_header *oftree;
+	bool from_fit = false;
 	int ret;
 
 	if (!IS_ENABLED(CONFIG_OFTREE))
 		return ERR_PTR(-ENOSYS);
 
-	if (fitconfig_has_fdt(data)) {
+	from_fit = fitconfig_has_fdt(data);
+	if (bootm_get_override(&data->oftree_file, bootm_overrides.oftree_file))
+		from_fit = false;
+
+	if (from_fit) {
 		const void *of_tree;
 		unsigned long of_size;
 
@@ -530,24 +564,29 @@ int bootm_load_devicetree(struct image_data *data, void *fdt,
 
 int bootm_get_os_size(struct image_data *data)
 {
+	const char *os_file;
+	struct stat s;
 	int ret;
 
-	if (data->elf)
-		return elf_get_mem_size(data->elf);
-	if (image_is_uimage(data))
-		return uimage_get_size(data->os, uimage_part_num(data->os_part));
-	if (data->os_fit)
-		return data->fit_kernel_size;
-
-	if (data->os_file) {
-		struct stat s;
-		ret = stat(data->os_file, &s);
-		if (ret)
-			return ret;
-		return s.st_size;
+	if (bootm_get_override(NULL, bootm_overrides.os_file)) {
+		os_file = bootm_overrides.os_file;
+	} else {
+		if (data->elf)
+			return elf_get_mem_size(data->elf);
+		if (image_is_uimage(data))
+			return uimage_get_size(data->os, uimage_part_num(data->os_part));
+		if (data->os_fit)
+			return data->fit_kernel_size;
+		if (!data->os_file)
+			return -EINVAL;
+		os_file = data->os_file;
 	}
 
-	return -EINVAL;
+	ret = stat(os_file, &s);
+	if (ret)
+		return ret;
+
+	return s.st_size;
 }
 
 static int bootm_open_os_uimage(struct image_data *data)
@@ -909,6 +948,22 @@ int bootm_boot(struct bootm_data *bootm_data)
 		printf("Passing control to %s handler\n", handler->name);
 	}
 
+	if (bootm_get_override(&data->os_file, bootm_overrides.os_file)) {
+		if (data->os_res) {
+			release_sdram_region(data->os_res);
+			data->os_res = NULL;
+		}
+	}
+
+	bootm_get_override(&data->oftree_file, bootm_overrides.oftree_file);
+
+	if (bootm_get_override(&data->initrd_file, bootm_overrides.initrd_file)) {
+		if (data->initrd_res) {
+			release_sdram_region(data->initrd_res);
+			data->initrd_res = NULL;
+		}
+	}
+
 	ret = handler->bootm(data);
 	if (data->dryrun)
 		pr_info("Dryrun. Aborted\n");
@@ -946,6 +1001,13 @@ int bootm_boot(struct bootm_data *bootm_data)
 	return ret;
 }
 
+#ifdef CONFIG_BOOT_OVERRIDE
+void bootm_set_overrides(const struct bootm_overrides *overrides)
+{
+	bootm_overrides = *overrides;
+}
+#endif
+
 static int do_bootm_compressed(struct image_data *img_data)
 {
 	struct bootm_data bootm_data = {
diff --git a/include/bootm.h b/include/bootm.h
index b86d06b0f55d..0e5e99773a26 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -160,4 +160,22 @@ void bootm_force_signed_images(void);
 
 void *booti_load_image(struct image_data *data, phys_addr_t *oftree);
 
+struct bootm_overrides {
+	const char *os_file;
+	const char *oftree_file;
+	const char *initrd_file;
+};
+
+#ifdef CONFIG_BOOT_OVERRIDE
+void bootm_set_overrides(const struct bootm_overrides *overrides);
+#else
+static inline void bootm_set_overrides(const struct bootm_overrides *overrides) {}
+#endif
+
+static inline void bootm_unset_overrides(void)
+{
+	struct bootm_overrides overrides = {};
+	bootm_set_overrides(&overrides);
+}
+
 #endif /* __BOOTM_H */
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 02:48:11 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 11:48:11 +0100
Subject: [PATCH 1/7] bootm: add helper functions for checking if FIT image is used
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <20250214104817.2975052-2-a.fatoum@pengutronix.de>

This introduces no functional change, but improves code readability.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/bootm.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/common/bootm.c b/common/bootm.c
index 2c7d3691407b..d1dbf6890f6f 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -188,19 +188,20 @@ int bootm_load_os(struct image_data *data, unsigned long load_address)
 	return -EINVAL;
 }
 
+static bool fitconfig_has_ramdisk(struct image_data *data)
+{
+	if (!IS_ENABLED(CONFIG_FITIMAGE) || !data->os_fit)
+		return false;
+
+	return fit_has_image(data->os_fit, data->fit_config, "ramdisk");
+}
+
 bool bootm_has_initrd(struct image_data *data)
 {
 	if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
 		return false;
 
-	if (IS_ENABLED(CONFIG_FITIMAGE) && data->os_fit &&
-	    fit_has_image(data->os_fit, data->fit_config, "ramdisk"))
-		return true;
-
-	if (data->initrd_file)
-		return true;
-
-	return false;
+	return fitconfig_has_ramdisk(data) || data->initrd_file;
 }
 
 static int bootm_open_initrd_uimage(struct image_data *data)
@@ -258,8 +259,7 @@ int bootm_load_initrd(struct image_data *data, unsigned long load_address)
 	if (data->initrd_res)
 		return 0;
 
-	if (IS_ENABLED(CONFIG_FITIMAGE) && data->os_fit &&
-	    fit_has_image(data->os_fit, data->fit_config, "ramdisk")) {
+	if (fitconfig_has_ramdisk(data)) {
 		const void *initrd;
 		unsigned long initrd_size;
 
@@ -371,6 +371,14 @@ static int bootm_open_oftree_uimage(struct image_data *data, size_t *size,
 	return 0;
 }
 
+static bool fitconfig_has_fdt(struct image_data *data)
+{
+	if (!IS_ENABLED(CONFIG_FITIMAGE) || !data->os_fit)
+		return false;
+
+	return fit_has_image(data->os_fit, data->fit_config, "fdt");
+}
+
 /*
  * bootm_get_devicetree() - get devicetree
  *
@@ -391,8 +399,7 @@ void *bootm_get_devicetree(struct image_data *data)
 	if (!IS_ENABLED(CONFIG_OFTREE))
 		return ERR_PTR(-ENOSYS);
 
-	if (IS_ENABLED(CONFIG_FITIMAGE) && data->os_fit &&
-	    fit_has_image(data->os_fit, data->fit_config, "fdt")) {
+	if (fitconfig_has_fdt(data)) {
 		const void *of_tree;
 		unsigned long of_size;
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 03:23:42 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 12:23:42 +0100
Subject: [PATCH master 1/2] FIT: factor out fit_fdt_is_compatible for readability
Message-ID: <20250214112343.3076535-1-a.fatoum@pengutronix.de>

This introduces no functional change, but makes the code inside
fit_find_compatible_unit() more readable.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/image-fit.c | 67 +++++++++++++++++++++++++---------------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/common/image-fit.c b/common/image-fit.c
index 58ce461623e6..e05161379d04 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -719,6 +719,40 @@ static int fit_config_verify_signature(struct fit_handle *handle, struct device_
 	return ret;
 }
 
+static int fit_fdt_is_compatible(struct fit_handle *handle,
+				 struct device_node *child,
+				 const char *machine)
+{
+	struct device_node *image;
+	const char *unit = "fdt";
+	int data_len;
+	const void *data;
+	int ret;
+
+	if (of_property_present(child, "compatible"))
+		return 0;
+	if (!of_property_present(child, "fdt"))
+		return 0;
+
+	ret = fit_get_image(handle, child, &unit, &image);
+	if (ret)
+		goto err;
+
+	data = of_get_property(image, "data", &data_len);
+	if (!data)
+		goto err;
+
+	ret = fit_handle_decompression(image, "fdt", &data, &data_len);
+	if (ret)
+		goto err;
+
+	return fdt_machine_is_compatible(data, data_len, machine);
+err:
+	pr_warn("skipping malformed configuration \"%pOF\"\n",
+		child);
+	return 0;
+}
+
 static int fit_find_compatible_unit(struct fit_handle *handle,
 				    struct device_node *conf_node,
 				    const char **unit)
@@ -740,37 +774,8 @@ static int fit_find_compatible_unit(struct fit_handle *handle,
 	for_each_child_of_node(conf_node, child) {
 		int score = of_device_is_compatible(child, machine);
 
-		if (!score && !of_property_present(child, "compatible") &&
-		    of_property_present(child, "fdt")) {
-			struct device_node *image;
-			const char *unit = "fdt";
-			int data_len;
-			const void *data;
-			int ret;
-
-			ret = fit_get_image(handle, child, &unit, &image);
-			if (ret)
-				goto next;
-
-			data = of_get_property(image, "data", &data_len);
-			if (!data) {
-				ret = -EINVAL;
-				goto next;
-			}
-
-			ret = fit_handle_decompression(image, "fdt", &data, &data_len);
-			if (ret) {
-				ret = -EILSEQ;
-				goto next;
-			}
-
-			score = fdt_machine_is_compatible(data, data_len, machine);
-
-next:
-			if (ret)
-				pr_warn("skipping malformed configuration: %pOF (%pe)\n",
-					child, ERR_PTR(ret));
-		}
+		if (!score)
+			score = fit_fdt_is_compatible(handle, child, machine);
 
 		if (score > best_score) {
 			best_score = score;
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 03:23:43 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 12:23:43 +0100
Subject: [PATCH master 2/2] FIT: do not decompress device trees to find compatible
In-Reply-To: <20250214112343.3076535-1-a.fatoum@pengutronix.de>
References: <20250214112343.3076535-1-a.fatoum@pengutronix.de>
Message-ID: <20250214112343.3076535-2-a.fatoum@pengutronix.de>

Uncompressing all FDTs just to look up the compatible is detrimental to
boot speed and negatively impacts security. Let's thus throw an error
and expect users to specify a compatible property in the configuration
or just refrain from compressing their DTs.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/image-fit.c | 37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/common/image-fit.c b/common/image-fit.c
index e05161379d04..959384abd275 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -570,18 +570,29 @@ static void fit_uncompress_error_fn(char *x)
 	pr_err("%s\n", x);
 }
 
+static const char *get_compression_type(struct device_node *image)
+{
+	const char *compression = NULL;
+
+	of_property_read_string(image, "compression", &compression);
+	if (!compression || !strcmp(compression, "none"))
+		return NULL;
+
+	return compression;
+}
+
 static int fit_handle_decompression(struct device_node *image,
 				    const char *type,
 				    const void **data,
 				    int *data_len)
 {
-	const char *compression = NULL;
+	const char *compression;
 	struct property *pp;
 	void *uc_data;
 	int ret;
 
-	of_property_read_string(image, "compression", &compression);
-	if (!compression || !strcmp(compression, "none"))
+	compression = get_compression_type(image);
+	if (!compression)
 		return 0;
 
 	if (!strcmp(type, "ramdisk")) {
@@ -723,6 +734,7 @@ static int fit_fdt_is_compatible(struct fit_handle *handle,
 				 struct device_node *child,
 				 const char *machine)
 {
+	const char *reason = "malformed";
 	struct device_node *image;
 	const char *unit = "fdt";
 	int data_len;
@@ -742,14 +754,25 @@ static int fit_fdt_is_compatible(struct fit_handle *handle,
 	if (!data)
 		goto err;
 
-	ret = fit_handle_decompression(image, "fdt", &data, &data_len);
-	if (ret)
+	/* We have three options here:
+	 *
+	 * 1) Increase our attack surface by all supported compression algos
+	 * 2) Verify all configurations in the image as we search for best
+	 *    OF match score
+	 * 3) Blame the user and expect them to supply a compatible property
+	 *    in the configuration node if they want to compress their FDTs
+	 *
+	 * We go for option 3.
+	 */
+	if (get_compression_type(image)) {
+		reason = "compressed";
 		goto err;
+	}
 
 	return fdt_machine_is_compatible(data, data_len, machine);
 err:
-	pr_warn("skipping malformed configuration \"%pOF\"\n",
-		child);
+	pr_warn("skipping %s configuration \"%pOF\"\n",
+		reason, child);
 	return 0;
 }
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 06:23:54 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 15:23:54 +0100
Subject: [PATCH master 1/3] common: introduce CONFIG_HAS_INSECURE_DEFAULT
Message-ID: <20250214142356.3624561-1-a.fatoum@pengutronix.de>

Unlike the functionality controlled by CONFIG_INSECURE, most
functionality in barebox is not as clear-cut: In secure systems, it's
better to turn off the option, but with enough care, board code may
disable the option later on.

To help with securing barebox, let's identify these options that need a
more thorough look by having them select HAS_INSECURE_DEFAULT.

In the future, we will start selecting HAS_INSECURE_DEFAULT when
hardening options are missing. We may also drop HAS_INSECURE_DEFAULT
again from options that are changed to minimize potential for abuse.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/Kconfig        | 49 ++++++++++++++++++++++++++++++++++++++++---
 lib/Kconfig.hardening |  6 ++++++
 net/Kconfig           |  4 ++++
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/common/Kconfig b/common/Kconfig
index 0ce99e98286c..fc29d1ca9427 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -149,9 +149,20 @@ config LOCALVERSION_AUTO
 
 	  which is done within the script "scripts/setlocalversion".)
 
+config HAS_INSECURE_DEFAULT
+	bool
+	help
+	  This is selected by options that have potentially insecure defaults.
+	  Extra care needs to be taken when these options are not disabled
+	  in secure booted systems.
+
+	  Any option selecting this should include in its help text
+	  an explanation of the security considerations.
+
 config INSECURE
 	bool "enable convenient defaults that are unsuitable for secure-booting systems"
 	default y
+	select HAS_INSECURE_DEFAULT
 	help
 	  Say n here when barebox is part of a secure boot chain and you
 	  want to disable defaults that may compromise the boot chain.
@@ -344,13 +355,17 @@ endchoice
 config MODULES
 	depends on HAS_MODULES
 	depends on EXPERIMENTAL
+	select HAS_INSECURE_DEFAULT
 	bool "module support"
 	modules
 	help
 	  This option enables support for loadable modules via insmod. Module
 	  support is quite experimental at the moment. There is no convenient
 	  way to compile modules and the list of exported symbols to actually
-	  make use of modules is short to nonexistent
+	  make use of modules is short to nonexistent.
+
+	  As modules aren't be signed, loading external modules is not
+	  recommended for secure systems.
 
 config HAVE_MOD_ARCH_SPECIFIC
 	bool
@@ -750,6 +765,15 @@ config BOOTM_FORCE_SIGNED_IMAGES
 	  are refused to boot. Effectively this means only FIT images can be booted
 	  since they are the only supported image type that support signing.
 
+config BOOTM_OPTIONAL_SIGNED_IMAGES
+	def_bool !BOOTM_FORCE_SIGNED_IMAGES
+	select HAS_INSECURE_DEFAULT
+	help
+	  With this option enabled, barebox can be reconfigured to not verify signed
+	  images. It's the board code's responsibility to call the function
+	  bootm_force_signed_images() when secure booted to ensure that runtime
+	  reconfiguration is no longer possible.
+
 config BLSPEC
 	depends on FLEXIBLE_BOOTARGS
 	depends on !SHELL_NONE
@@ -964,6 +988,7 @@ source "common/partitions/Kconfig"
 
 config ENV_HANDLING
 	select CRC32
+	select HAS_INSECURE_DEFAULT
 	bool "Support environment files storage"
 	default y if !SHELL_NONE
 	help
@@ -972,6 +997,17 @@ config ENV_HANDLING
 	  the persistent environment, the "loadenv" command (also executed during
 	  startup) will bring them back. If unsure, say yes.
 
+	  As the environment is not cryptographically verified, an attacker with
+	  raw access to the environment storage may set any nv variable and
+	  inject shell scripts to be run by barebox.
+
+	  In general, secure systems should rely exclusively on the barebox
+	  built-in environment, disable the mutable environment and use the
+	  barebox-state framework for persisting a fixed set of variables.
+
+	  A safe use of the mutable environment may be possible if board code only
+	  mounts it after verifying a JSON Web Token that enables a debug mode.
+
 config DEFAULT_ENVIRONMENT
 	select CRC32
 	bool
@@ -1271,8 +1307,9 @@ config OPTEE_SHM_SIZE
 config BOOTM_OPTEE
 	bool
 	prompt "support booting OP-TEE"
-	depends on BOOTM && ARM && 32BIT
+	depends on BOOTM && ARM32
 	select HAVE_OPTEE
+	select HAS_INSECURE_DEFAULT
 	help
 	  OP-TEE is a trusted execution environment (TEE). With this option
 	  enabled barebox supports starting optee_os as part of the bootm command.
@@ -1280,6 +1317,11 @@ config BOOTM_OPTEE
 	  the kernel in nonsecure mode. Pass the optee_os binary with the -t option
 	  or in the global.bootm.tee variable.
 
+	  This mode of late loading OP-TEE just before the kernel is deprecated
+	  in favor of early loading OP-TEE in the PBL (CONFIG_PBL_OPTEE).
+	  Early-loading greatly reduces the attack surface and is the only mode
+	  supported outside of ARMv7.
+
 config PBL_OPTEE
 	bool "Enable OP-TEE early start"
 	depends on ARM
@@ -1307,9 +1349,10 @@ config FASTBOOT_SPARSE
 config FASTBOOT_CMD_OEM
 	bool
 	prompt "Enable OEM commands"
+	select HAS_INSECURE_DEFAULT
 	help
 	  This option enables the fastboot "oem" group of commands. They allow to
-	  executing arbitrary barebox commands and may be disabled in secure
+	  executing arbitrary barebox commands and should be disabled in secure
 	  environments.
 
 endmenu
diff --git a/lib/Kconfig.hardening b/lib/Kconfig.hardening
index 6457d24c7382..53d824af7615 100644
--- a/lib/Kconfig.hardening
+++ b/lib/Kconfig.hardening
@@ -1,5 +1,11 @@
 menu "Hardening options"
 
+if HAS_INSECURE_DEFAULT
+comment "This barebox configuration has CONFIG_HAS_INSECURE_DEFAULT=y indicating"
+comment "that some of the configured options have potentially insecure defaults."
+comment "Extra care needs to be in secure booted systems."
+endif
+
 config BUG_ON_DATA_CORRUPTION
 	bool "Trigger a BUG when data corruption is detected"
 	select DEBUG_LIST
diff --git a/net/Kconfig b/net/Kconfig
index 2491c497bdfc..fc70efb97aa8 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -31,9 +31,13 @@ config NET_NETCONSOLE
 	bool
 	depends on !CONSOLE_NONE
 	prompt "network console support"
+	select HAS_INSECURE_DEFAULT
 	help
 	  This option adds support for a simple udp based network console.
 
+	  This console's communication is not encrypted and is thus not
+	  suitable for use in untrusted networks.
+
 config NET_RESOLV
 	bool
 	prompt "dns support"
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 06:23:55 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 15:23:55 +0100
Subject: [PATCH master 2/3] Documentation: user: optee: bring up-to-date
In-Reply-To: <20250214142356.3624561-1-a.fatoum@pengutronix.de>
References: <20250214142356.3624561-1-a.fatoum@pengutronix.de>
Message-ID: <20250214142356.3624561-2-a.fatoum@pengutronix.de>

Most platforms now use OP-TEE early loading and we have gained support
to communicate with OP-TEE and not only loading it.

Reflect that in the docs.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/user/optee.rst | 45 +++++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 11 deletions(-)

diff --git a/Documentation/user/optee.rst b/Documentation/user/optee.rst
index 950917b446ad..2729d21d2e44 100644
--- a/Documentation/user/optee.rst
+++ b/Documentation/user/optee.rst
@@ -4,20 +4,20 @@
 OP-TEE
 ======
 
-Barebox is able to start the Open Portable Trusted Execution Environment
-(OP-TEE) either before starting the linux kernel or during lowlevel board
-initialization in the Pre Bootloader ``PBL``.
+barebox has support for loading and communicating with the Open Portable Trusted
+Execution Environment (OP-TEE).
 
-Before Linux start
-------------------
-Enable the `CONFIG_BOOTM_OPTEE` configuration variable and configure the
-`CONFIG_OPTEE_SIZE` variable. This will reserve a memory area at the end
-of memory for OP-TEE to run, usually Barebox would relocate itself there. To
-load OP-TEE before the kernel is started, configure the global ``bootm.tee``
-variable to point to a valid OPTEE v1 binary.
+Loading OP-TEE
+--------------
+
+barebox can start OP-TEE either during lowlevel board initialization
+in the :ref:`prebootloader <pbl>` or prior to starting the linux kernel.
+
+.. _optee_early_loading:
 
 During the PBL
---------------
+^^^^^^^^^^^^^^
+
 To start OP-TEE during the lowlevel initialization of your board in the ``PBL``,
 enable the ``CONFIG_PBL_OPTEE`` configuration variable. your board should then
 call the function ``start_optee_early(void* tee, void* fdt)`` with a valid tee
@@ -27,3 +27,26 @@ Since OP-TEE in the default configuration also modifies the device tree, don't
 pass the barebox internal device tree, instead copy it into a different memory
 location and pass it to OP-TEE afterwards.
 The modified device tree can then be passed to the main barebox start function.
+
+Before Linux start
+^^^^^^^^^^^^^^^^^^
+
+.. warning:: Late loading of OP-TEE is deprecated, greatly increases the
+   attack surface and is only supported on 32-bit ARM systems.
+   Systems should prefer early loading OP-TEE whenever possible.
+
+Enable the `CONFIG_BOOTM_OPTEE` configuration variable and configure the
+`CONFIG_OPTEE_SIZE` variable. This will reserve a memory area at the end
+of memory for OP-TEE to run, usually Barebox would relocate itself there. To
+load OP-TEE before the kernel is started, configure the global ``bootm.tee``
+variable to point to a valid OPTEE v1 binary.
+
+Communication with OP-TEE
+-------------------------
+
+Controlled by the ``CONFIG_OPTEE`` option, barebox has support for
+communicating with OP-TEE via secure monitor calls and dynamic shared memory.
+This is possible independently of whether OP-TEE was loaded by barebox or not.
+
+The primary use cases currently is SCMI-over-OP-TEE, which is required on
+the STM32MP13.
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 06:23:56 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 15:23:56 +0100
Subject: [PATCH master 3/3] Documentation: user: add security consideration for using barebox
In-Reply-To: <20250214142356.3624561-1-a.fatoum@pengutronix.de>
References: <20250214142356.3624561-1-a.fatoum@pengutronix.de>
Message-ID: <20250214142356.3624561-3-a.fatoum@pengutronix.de>

There are implicit assumptions around use of barebox in secure systems,
which isn't spelt out anywhere, e.g. that FIT images should be located
in raw partitions.

Let's start by writing down these security considerations.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/boards/imx.rst    |   2 +
 Documentation/user/security.rst | 160 ++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+)
 create mode 100644 Documentation/user/security.rst

diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst
index 13246599838b..b4adb55d1bea 100644
--- a/Documentation/boards/imx.rst
+++ b/Documentation/boards/imx.rst
@@ -119,6 +119,8 @@ correspond directly to the boot fusemap settings.
 
 See the section on :ref:`Reboot modes<reboot_mode>` for general information.
 
+.. _hab:
+
 High Assurance Boot
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/Documentation/user/security.rst b/Documentation/user/security.rst
new file mode 100644
index 000000000000..507df9a79e84
--- /dev/null
+++ b/Documentation/user/security.rst
@@ -0,0 +1,160 @@
+.. _security:
+
+Security Considerations
+=======================
+
+As bootloader, barebox is often used as part of a cryptographically verified
+boot chain. Such a boot chain is only as secure as its weakest link and
+special care needs to be taken while configuring and deploying barebox.
+
+Verified Boot
+-------------
+
+In a cryptographically verified boot chain (henceforth termed "Verified Boot"),
+each boot stage must be verified by the previous boot stage before execution.
+
+At the start of the verification chain lies some hardware root of trust, most
+often a public key (or its hash) that's programmed into one-time-programmable
+(OTP) eFuses while the board is still in the factory.
+
+The SoC's mask ROM (sometime called BootROM) will consult the eFuses and
+use them to verify the first stage bootloader image. From there on, it's
+expected that every boot stage will only boot the next one after verification.
+
+Verification can take many forms:
+
+- The mask ROM provides an API to verify later images against the same key
+  used to verify the first boot stage.
+
+- If both first stage and second stage result from the same build, the first
+  stage can embed the hash of the second stage.
+
+- The boot stage has an embedded public key which is used to verify the
+  signature of the later boot stage.
+
+Verifying barebox itself
+------------------------
+
+The way that barebox is verified is highly SoC-specific as it's usually done
+by the SoC mask ROM and in some cases by a different first stage bootloader
+like ARM Trusted Firmware.
+
+For some SoCs, like i.MX :ref:`High Assurance Boot <hab>`, the barebox
+build system has built-in support for invoking the necessary external tools
+to sign the boot images.  In the general case however, the signing happens
+outside the barebox build system and the integrator needs to ensure that
+the images are signed with the correct keys.
+
+In any case, each individual board must be locked down, i.e., configured to
+only boot correctly signed images.
+
+The latter is often done by writing a different set of eFuses, see for
+example the barebox :ref:`hab command <command_hab>` which does the necessary
+fusing for both HABv4 and AHAB.
+
+.. warning:: barebox commands likes :ref:`hab command <command_hab>` do only
+   touch the subset of fuses relevant to most users. It's up to the integrators
+   to fuse away unneeded functionality like USB recovery or JTAG as needed.
+
+Loading firmware
+----------------
+
+In systems utilizing the ARM TrustZone, barebox is often tasked with loading
+the secure OS (Usually OP-TEE). After OP-TEE is loaded, the rest of the
+software runs in a less-privileged non-secure or "normal" world.
+
+The installation of OP-TEE (and any higher privileged firmware like ARM Trusted
+Firmware) should happen as early as possible, i.e., within the barebox
+:ref:`prebootloader <pbl>`. Delaying installation of OP-TEE means that most of
+barebox will run with elevated permission, which greatly increases the attack
+surface.
+
+In concrete terms, the deprecated ``CONFIG_BOOTM_OPTEE`` option should be
+disabled in favor of :ref:`loading OP-TEE early <optee_early_loading>`.
+
+Verifying the kernel by barebox
+-------------------------------
+
+barebox can embed one or more RSA or ECDSA public keys that it will use to
+verify signed FIT images. In a verified boot system, barebox should not
+be allowed to boot any images that have not been signed by the correct key.
+This can be enforced by setting ``CONFIG_BOOTM_FORCE_SIGNED_IMAGES=y``
+and disabling any ways that could use used to override this, e.g.:
+
+- While useful for development, the barebox shell can be used in creative
+  ways to circumvent boot restrictions. It's thus advisable to disable
+  the shell completely (``CONFIG_SHELL_NONE=y``) or make it non-interactive
+  (``CONSOLE_DISABLE_INPUT=y``). This may be coupled with muxing UART RX
+  pin as GPIO for maximum effectiveness.
+
+- Anything done interactively by the shell can also be done automatically by
+  means of init scripts in the environment. A secure barebox should only
+  consult the environment that it has built in and not parse an externally
+  located environment.
+  This can be enforced by disabling ``CONFIG_ENV_HANDLING``.
+  This does not preclude the use of :ref:`Bootchooser` as the
+  :ref:`barebox-state framework <state_framework>` can be used independently.
+
+- There are alternative methods of accessing the shell like netconsole,
+  or fastboot. These should preferably be disabled or at least not activated
+  by default.
+
+Note that any list here is bound to be incomplete. The barebox configuration
+needs to be vetted individually according to threat model.
+
+Use of file systems
+^^^^^^^^^^^^^^^^^^^
+
+File systems are among the most complex parser code in barebox and a common
+source of bugs.
+Unlike Linux with its dm-verity support, barebox currently has no way to
+verify a file system before mounting it.
+
+The consequence is that in a verified boot setup, barebox should **never**
+be allowed to mount file systems.
+Especially, :ref:`bootloader spec files <bootloader_spec>` should not be used
+in verified boot setups and signed FIT images **must** be located outside
+a file system and directly in a raw partition.
+
+Configuring barebox
+-------------------
+
+To aid identification of security impact of config options, barebox provides
+two top-level security-related options:
+
+- ``CONFIG_INSECURE``: This enables convenient, but insecure, defaults.
+  Any secure system should disable this option.
+
+- ``CONFIG_HAS_INSECURE_DEFAULT``: This is selected by options that have
+  an outsized potential of compromising security. It's recommended that
+  all configuration options that select ``CONFIG_HAS_INSECURE_DEFAULT``
+  are disabled.
+  If not possible, special care needs to be taken in vetting the insecure
+  defaults in question.
+
+Compile-time configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Any code that's eliminated at compile-time is code that can't be exploited by
+an attacker. It's thus strongly advisable to keep a separate secure
+configuration that disables all features that are used for development and
+are not absolutely necessary for booting in the field.
+
+Run-time configuration
+^^^^^^^^^^^^^^^^^^^^^^
+
+It's sometimes desirable to retain some ability to debug locked down systems.
+While attractive, it's not recommended to retain an insecure bootloader for
+the purposes of debugging due to the risk of this bootloader being leaked.
+
+Instead, it's recommended that debugging images are signed specifically to
+target only a specific board.
+
+This is sometimes supported out-of-the-box by the SoC like with the HABv4
+field return feature.
+
+In the generic case, barebox supports verification of JSON Web Tokens against
+a compiled-in RSA public key. Board code should read the JSON Web Token
+(e.g., from a raw partition on a USB mass storage device), verify the
+serial number claim within against the board's actual serial number and only
+then unlock any debugging functionality.
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 06:27:51 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 15:27:51 +0100
Subject: [PATCH] fixup! Documentation: user: add security consideration for using barebox
In-Reply-To: <20250214142356.3624561-3-a.fatoum@pengutronix.de>
References: <20250214142356.3624561-3-a.fatoum@pengutronix.de>
Message-ID: <20250214142751.3629723-1-a.fatoum@pengutronix.de>

Actually reference the file...

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/user/user-manual.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst
index 565e6c11f82f..83ba9e4c3505 100644
--- a/Documentation/user/user-manual.rst
+++ b/Documentation/user/user-manual.rst
@@ -28,6 +28,7 @@ Contents:
    booting-linux
    bootchooser
    remote-control
+   security
    system-setup
    reset-reason
    system-reset
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 07:46:22 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 16:46:22 +0100
Subject: [PATCH] bootm: change default verification mode from hash to available
Message-ID: <20250214154622.235998-1-a.fatoum@pengutronix.de>

The default of global.bootm.verify=hash means that barebox will refuse
to boot images without hashes, but won't bother verifying the signature.

For verified boot setups, this parameter needs to be set to signature,
preferably enforced via CONFIG_BOOTM_FORCE_SIGNED_IMAGES.

For everything else, it's better user experience if barebox would just
verify what's available instead of refusing to boot images without hashes,
like the image.fit that Linux can now generate as part of its build.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/bootm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/bootm.c b/common/bootm.c
index 80905d4cf1ce..dd9ba2eae3b2 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -87,7 +87,7 @@ void bootm_data_restore_defaults(const struct bootm_data *data)
 	bootm_dryrun = data->dryrun;
 }
 
-static enum bootm_verify bootm_verify_mode = BOOTM_VERIFY_HASH;
+static enum bootm_verify bootm_verify_mode = BOOTM_VERIFY_AVAILABLE;
 
 enum bootm_verify bootm_get_verify_mode(void)
 {
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 11:15:39 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 20:15:39 +0100
Subject: [PATCH] ARM: zii-imx8mq-dev: fix warnings about missing #address-/#size-cells
Message-ID: <20250214191539.1399572-1-a.fatoum@pengutronix.de>

Upstream has recently dropped the #address-cells and #size-cells
properties, because there are no child nodes upstream.

Add them in barebox and fix the warnings.

Fixes: 57b3c5bd0a0c ("dts: update to v6.14-rc1")
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/arm/dts/imx8mq-zii-ultra.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/dts/imx8mq-zii-ultra.dtsi b/arch/arm/dts/imx8mq-zii-ultra.dtsi
index d45c24302799..9993ee969e4a 100644
--- a/arch/arm/dts/imx8mq-zii-ultra.dtsi
+++ b/arch/arm/dts/imx8mq-zii-ultra.dtsi
@@ -70,6 +70,9 @@ &i210 {
 };
 
 &{uart2/mcu/eeprom at a4} {
+	#address-cells = <1>;
+	#size-cells = <1>;
+
 	lru_part_number: lru-part-number at 21 {
 		reg = <0x21 15>;
 		read-only;
-- 
2.39.5



From a.fatoum at pengutronix.de  Fri Feb 14 12:02:08 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 14 Feb 2025 21:02:08 +0100
Subject: [PATCH] fixup! bootm: retire bootm_has_initrd
In-Reply-To: <20250214104817.2975052-7-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-7-a.fatoum@pengutronix.de>
Message-ID: <20250214200208.1479918-1-a.fatoum@pengutronix.de>

CI noticed correctly that ret is used uninitialized here.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/kvx/lib/bootm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/kvx/lib/bootm.c b/arch/kvx/lib/bootm.c
index 6c35b68f3d5d..42c15ff27351 100644
--- a/arch/kvx/lib/bootm.c
+++ b/arch/kvx/lib/bootm.c
@@ -70,7 +70,7 @@ static int do_boot_elf(struct image_data *data, struct elf_image *elf)
 	initrd_res = bootm_load_initrd(data, initrd_address);
 	if (IS_ERR(initrd_res)) {
 		printf("Failed to load initrd\n");
-		return ret;
+		return PTR_ERR(initrd_res);
 	} else if (initrd_res) {
 		printf("Loading initrd at 0x%lx\n", initrd_address);
 		if (data->initrd_address == UIMAGE_INVALID_ADDRESS) {
-- 
2.39.5



From a.fatoum at pengutronix.de  Sat Feb 15 04:29:02 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sat, 15 Feb 2025 13:29:02 +0100
Subject: [PATCH] fixup! commands: boot: add support for overriding boot artifacts
In-Reply-To: <20250214104817.2975052-8-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-8-a.fatoum@pengutronix.de>
Message-ID: <20250215122902.2858449-1-a.fatoum@pengutronix.de>

This allows e.g. adding an initrd, when none was specified before.
Otherwise, we would run into a NULL pointer exception.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/bootm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/bootm.c b/common/bootm.c
index dd9ba2eae3b2..fe4d51681d73 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -152,7 +152,7 @@ static bool bootm_get_override(char **oldpath, const char *newpath)
 	if (!newpath)
 		return false;
 
-	if (oldpath && strcmp(*oldpath, newpath)) {
+	if (oldpath && !streq_ptr(*oldpath, newpath)) {
 		free(*oldpath);
 		*oldpath = *newpath ? xstrdup(newpath) : NULL;
 	}
-- 
2.39.5



From a.fatoum at pengutronix.de  Sun Feb 16 07:07:17 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sun, 16 Feb 2025 16:07:17 +0100
Subject: [PATCH 1/2] cdev: merge identical partitions despite DEVFS_PARTITION_CAN_OVERLAP
Message-ID: <20250216150718.2348520-1-a.fatoum@pengutronix.de>

When a partition is created that's exactly the same size and offset as
an existing partition, barebox will create the new partition as link to
the existing partition.

Maintain this behavior, even if DEVFS_PARTITION_CAN_OVERLAP is set.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 fs/devfs-core.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/fs/devfs-core.c b/fs/devfs-core.c
index 133fd9ec026a..c9313ed73167 100644
--- a/fs/devfs-core.c
+++ b/fs/devfs-core.c
@@ -440,7 +440,7 @@ int devfs_remove(struct cdev *cdev)
 /**
  * check_overlap() - check overlap with existing partitions
  * @cdev: parent cdev
- * @name: partition name for informational purposes on conflict
+ * @partinfo: partition information
  * @offset: offset of new partition to be added
  * @size: size of new partition to be added
  *
@@ -448,7 +448,9 @@ int devfs_remove(struct cdev *cdev)
  *         partition if and only if it's identical in offset and size
  *         to an existing partition. Otherwise, PTR_ERR(-EINVAL).
  */
-static struct cdev *check_overlap(struct cdev *cdev, const char *name, loff_t offset, loff_t size)
+static struct cdev *check_overlap(struct cdev *cdev,
+				  const struct devfs_partition *partinfo,
+				  loff_t offset, loff_t size)
 {
 	struct cdev *cpart;
 	loff_t cpart_offset;
@@ -471,6 +473,8 @@ static struct cdev *check_overlap(struct cdev *cdev, const char *name, loff_t of
 		}
 
 		if (region_overlap_size(cpart_offset, cpart->size, offset, size)) {
+			if (partinfo->flags & DEVFS_PARTITION_CAN_OVERLAP)
+				return NULL;
 			ret = -EINVAL;
 			goto conflict;
 		}
@@ -483,7 +487,7 @@ static struct cdev *check_overlap(struct cdev *cdev, const char *name, loff_t of
 	__pr_printk(ret ? MSG_WARNING : MSG_DEBUG,
 		    "New partition %s (0x%08llx-0x%08llx) on %s "
 		    "%s with partition %s (0x%08llx-0x%08llx), not creating it\n",
-		    name, offset, offset + size - 1, cdev->name,
+		    partinfo->name, offset, offset + size - 1, cdev->name,
 		    ret ? "conflicts" : "identical",
 		    cpart->name, cpart_offset, cpart_offset + cpart->size - 1);
 
@@ -530,16 +534,14 @@ static struct cdev *__devfs_add_partition(struct cdev *cdev,
 		return ERR_PTR(-EINVAL);
 	}
 
-	if (!(partinfo->flags & DEVFS_PARTITION_CAN_OVERLAP)) {
-		overlap = check_overlap(cdev, partinfo->name, offset, size);
-		if (overlap) {
-			if (!IS_ERR(overlap)) {
-				/* only fails with -EEXIST, which is fine */
-				(void)devfs_create_link(overlap, partinfo->name);
-			}
-
-			return overlap;
+	overlap = check_overlap(cdev, partinfo, offset, size);
+	if (overlap) {
+		if (!IS_ERR(overlap)) {
+			/* only fails with -EEXIST, which is fine */
+			(void)devfs_create_link(overlap, partinfo->name);
 		}
+
+		return overlap;
 	}
 
 	/* Filter flags that we want to pass along to children */
-- 
2.39.5



From a.fatoum at pengutronix.de  Sun Feb 16 07:07:18 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Sun, 16 Feb 2025 16:07:18 +0100
Subject: [PATCH 2/2] cmdlinepart: refuse partitions with empty name
In-Reply-To: <20250216150718.2348520-1-a.fatoum@pengutronix.de>
References: <20250216150718.2348520-1-a.fatoum@pengutronix.de>
Message-ID: <20250216150718.2348520-2-a.fatoum@pengutronix.de>

Running addpart /dev/mmc3 0xe0000 at 0 currently creates a partition with a
zero-sized name. Check for this condition and throw an error.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 lib/cmdlinepart.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lib/cmdlinepart.c b/lib/cmdlinepart.c
index afba544965b4..3e8c415c7ea6 100644
--- a/lib/cmdlinepart.c
+++ b/lib/cmdlinepart.c
@@ -30,6 +30,7 @@ int cmdlinepart_do_parse_one(const char *devname, const char *partstr,
 	char *end;
 	char buf[PATH_MAX] = {};
 	unsigned long flags = DEVFS_PARTITION_FOR_FIXUP;
+	size_t partname_len = 0;
 	struct cdev *cdev;
 
 	memset(buf, 0, PATH_MAX);
@@ -60,7 +61,8 @@ int cmdlinepart_do_parse_one(const char *devname, const char *partstr,
 		if ((partition_flags & CMDLINEPART_ADD_DEVNAME) &&
 				strncmp(devname, partstr, strlen(devname)))
 			sprintf(buf, "%s.", devname);
-		memcpy(buf + strlen(buf), partstr, end - partstr);
+		partname_len = end - partstr;
+		memcpy(buf + strlen(buf), partstr, partname_len);
 
 		end++;
 	}
@@ -85,6 +87,11 @@ int cmdlinepart_do_parse_one(const char *devname, const char *partstr,
 
 	*retsize = size;
 
+	if (!partname_len) {
+		printf("partition name can't be empty\n");
+		return -EINVAL;
+	}
+
 	cdev = devfs_add_partition(devname, *offset, size, flags, buf);
 	if (IS_ERR(cdev)) {
 		printf("cannot create %s: %pe\n", buf, cdev);
-- 
2.39.5



From s.hauer at pengutronix.de  Sun Feb 16 23:36:30 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 08:36:30 +0100
Subject: [PATCH 1/2] cdev: merge identical partitions despite
 DEVFS_PARTITION_CAN_OVERLAP
In-Reply-To: <20250216150718.2348520-1-a.fatoum@pengutronix.de>
References: <20250216150718.2348520-1-a.fatoum@pengutronix.de>
Message-ID: <173977779001.2224086.13654280587771881132.b4-ty@pengutronix.de>


On Sun, 16 Feb 2025 16:07:17 +0100, Ahmad Fatoum wrote:
> When a partition is created that's exactly the same size and offset as
> an existing partition, barebox will create the new partition as link to
> the existing partition.
> 
> Maintain this behavior, even if DEVFS_PARTITION_CAN_OVERLAP is set.
> 
> 
> [...]

Applied, thanks!

[1/2] cdev: merge identical partitions despite DEVFS_PARTITION_CAN_OVERLAP
      https://git.pengutronix.de/cgit/barebox/commit/?id=f7c38bec5baf (link may not be stable)
[2/2] cmdlinepart: refuse partitions with empty name
      https://git.pengutronix.de/cgit/barebox/commit/?id=1d81df84033c (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Sun Feb 16 23:37:31 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 08:37:31 +0100
Subject: [PATCH] ARM: zii-imx8mq-dev: fix warnings about missing
 #address-/#size-cells
In-Reply-To: <20250214191539.1399572-1-a.fatoum@pengutronix.de>
References: <20250214191539.1399572-1-a.fatoum@pengutronix.de>
Message-ID: <173977785141.2243055.13253405806756476051.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 20:15:39 +0100, Ahmad Fatoum wrote:
> Upstream has recently dropped the #address-cells and #size-cells
> properties, because there are no child nodes upstream.
> 
> Add them in barebox and fix the warnings.
> 
> 

Applied, thanks!

[1/1] ARM: zii-imx8mq-dev: fix warnings about missing #address-/#size-cells
      https://git.pengutronix.de/cgit/barebox/commit/?id=e96aeee6f32a (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Sun Feb 16 23:39:14 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 08:39:14 +0100
Subject: [PATCH] bootm: change default verification mode from hash to
 available
In-Reply-To: <20250214154622.235998-1-a.fatoum@pengutronix.de>
References: <20250214154622.235998-1-a.fatoum@pengutronix.de>
Message-ID: <173977795416.2272737.5888670013880262381.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 16:46:22 +0100, Ahmad Fatoum wrote:
> The default of global.bootm.verify=hash means that barebox will refuse
> to boot images without hashes, but won't bother verifying the signature.
> 
> For verified boot setups, this parameter needs to be set to signature,
> preferably enforced via CONFIG_BOOTM_FORCE_SIGNED_IMAGES.
> 
> For everything else, it's better user experience if barebox would just
> verify what's available instead of refusing to boot images without hashes,
> like the image.fit that Linux can now generate as part of its build.
> 
> [...]

Applied, thanks!

[1/1] bootm: change default verification mode from hash to available
      https://git.pengutronix.de/cgit/barebox/commit/?id=824314cbade2 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 00:58:19 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 09:58:19 +0100
Subject: [PATCH master 3/3] Documentation: user: add security
 consideration for using barebox
In-Reply-To: <20250214142356.3624561-3-a.fatoum@pengutronix.de>
References: <20250214142356.3624561-1-a.fatoum@pengutronix.de>
 <20250214142356.3624561-3-a.fatoum@pengutronix.de>
Message-ID: <Z7L6K5DIwG-dpBEr@pengutronix.de>

Hi Ahmad,

Great stuff, thank you for writing this up.

On Fri, Feb 14, 2025 at 03:23:56PM +0100, Ahmad Fatoum wrote:
> There are implicit assumptions around use of barebox in secure systems,
> which isn't spelt out anywhere, e.g. that FIT images should be located
> in raw partitions.
> 
> Let's start by writing down these security considerations.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  Documentation/boards/imx.rst    |   2 +
>  Documentation/user/security.rst | 160 ++++++++++++++++++++++++++++++++
>  2 files changed, 162 insertions(+)
>  create mode 100644 Documentation/user/security.rst
> 
> diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst
> index 13246599838b..b4adb55d1bea 100644
> --- a/Documentation/boards/imx.rst
> +++ b/Documentation/boards/imx.rst
> @@ -119,6 +119,8 @@ correspond directly to the boot fusemap settings.
>  
>  See the section on :ref:`Reboot modes<reboot_mode>` for general information.
>  
> +.. _hab:
> +
>  High Assurance Boot
>  ^^^^^^^^^^^^^^^^^^^
>  
> diff --git a/Documentation/user/security.rst b/Documentation/user/security.rst
> new file mode 100644
> index 000000000000..507df9a79e84
> --- /dev/null
> +++ b/Documentation/user/security.rst
> @@ -0,0 +1,160 @@
> +.. _security:
> +
> +Security Considerations
> +=======================
> +
> +As bootloader, barebox is often used as part of a cryptographically verified
> +boot chain. Such a boot chain is only as secure as its weakest link and
> +special care needs to be taken while configuring and deploying barebox.
> +
> +Verified Boot
> +-------------
> +
> +In a cryptographically verified boot chain (henceforth termed "Verified Boot"),
> +each boot stage must be verified by the previous boot stage before execution.
> +
> +At the start of the verification chain lies some hardware root of trust, most
> +often a public key (or its hash) that's programmed into one-time-programmable
> +(OTP) eFuses while the board is still in the factory.
> +
> +The SoC's mask ROM (sometime called BootROM) will consult the eFuses and
> +use them to verify the first stage bootloader image. From there on, it's
> +expected that every boot stage will only boot the next one after verification.
> +
> +Verification can take many forms:
> +
> +- The mask ROM provides an API to verify later images against the same key
> +  used to verify the first boot stage.
> +
> +- If both first stage and second stage result from the same build, the first
> +  stage can embed the hash of the second stage.
> +
> +- The boot stage has an embedded public key which is used to verify the
> +  signature of the later boot stage.
> +
> +Verifying barebox itself
> +------------------------
> +
> +The way that barebox is verified is highly SoC-specific as it's usually done
> +by the SoC mask ROM and in some cases by a different first stage bootloader
> +like ARM Trusted Firmware.
> +
> +For some SoCs, like i.MX :ref:`High Assurance Boot <hab>`, the barebox
> +build system has built-in support for invoking the necessary external tools
> +to sign the boot images.  In the general case however, the signing happens
> +outside the barebox build system and the integrator needs to ensure that
> +the images are signed with the correct keys.
> +
> +In any case, each individual board must be locked down, i.e., configured to
> +only boot correctly signed images.
> +
> +The latter is often done by writing a different set of eFuses, see for
> +example the barebox :ref:`hab command <command_hab>` which does the necessary
> +fusing for both HABv4 and AHAB.
> +
> +.. warning:: barebox commands likes :ref:`hab command <command_hab>` do only

s/likes/like/

> +   touch the subset of fuses relevant to most users. It's up to the integrators
> +   to fuse away unneeded functionality like USB recovery or JTAG as needed.
> +
> +Loading firmware
> +----------------
> +
> +In systems utilizing the ARM TrustZone, barebox is often tasked with loading
> +the secure OS (Usually OP-TEE). After OP-TEE is loaded, the rest of the
> +software runs in a less-privileged non-secure or "normal" world.
> +
> +The installation of OP-TEE (and any higher privileged firmware like ARM Trusted
> +Firmware) should happen as early as possible, i.e., within the barebox
> +:ref:`prebootloader <pbl>`. Delaying installation of OP-TEE means that most of
> +barebox will run with elevated permission, which greatly increases the attack
> +surface.
> +
> +In concrete terms, the deprecated ``CONFIG_BOOTM_OPTEE`` option should be
> +disabled in favor of :ref:`loading OP-TEE early <optee_early_loading>`.
> +
> +Verifying the kernel by barebox
> +-------------------------------
> +
> +barebox can embed one or more RSA or ECDSA public keys that it will use to
> +verify signed FIT images. In a verified boot system, barebox should not
> +be allowed to boot any images that have not been signed by the correct key.
> +This can be enforced by setting ``CONFIG_BOOTM_FORCE_SIGNED_IMAGES=y``
> +and disabling any ways that could use used to override this, e.g.:
> +
> +- While useful for development, the barebox shell can be used in creative
> +  ways to circumvent boot restrictions. It's thus advisable to disable
> +  the shell completely (``CONFIG_SHELL_NONE=y``) or make it non-interactive
> +  (``CONSOLE_DISABLE_INPUT=y``). This may be coupled with muxing UART RX
> +  pin as GPIO for maximum effectiveness.
> +
> +- Anything done interactively by the shell can also be done automatically by
> +  means of init scripts in the environment. A secure barebox should only
> +  consult the environment that it has built in and not parse an externally
> +  located environment.
> +  This can be enforced by disabling ``CONFIG_ENV_HANDLING``.
> +  This does not preclude the use of :ref:`Bootchooser` as the
> +  :ref:`barebox-state framework <state_framework>` can be used independently.
> +
> +- There are alternative methods of accessing the shell like netconsole,
> +  or fastboot. These should preferably be disabled or at least not activated
> +  by default.

As the role of the shell in a verified boot scenario is quite big maybe
put this under an extra headline?

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Mon Feb 17 01:00:18 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 10:00:18 +0100
Subject: [PATCH master 1/2] FIT: factor out fit_fdt_is_compatible for
 readability
In-Reply-To: <20250214112343.3076535-1-a.fatoum@pengutronix.de>
References: <20250214112343.3076535-1-a.fatoum@pengutronix.de>
Message-ID: <173978281845.3830924.6474920489633581807.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 12:23:42 +0100, Ahmad Fatoum wrote:
> This introduces no functional change, but makes the code inside
> fit_find_compatible_unit() more readable.
> 
> 

Applied, thanks!

[1/2] FIT: factor out fit_fdt_is_compatible for readability
      https://git.pengutronix.de/cgit/barebox/commit/?id=272c1900d073 (link may not be stable)
[2/2] FIT: do not decompress device trees to find compatible
      https://git.pengutronix.de/cgit/barebox/commit/?id=5d7d60c4961c (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From eagle.alexander923 at gmail.com  Mon Feb 17 01:24:18 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Mon, 17 Feb 2025 12:24:18 +0300
Subject: [PATCH 1/7] net: davinci_mdio: separate driver
In-Reply-To: <20241108-network-k3-v1-1-ee71bff15eb7@pengutronix.de>
References: <20241108-network-k3-v1-0-ee71bff15eb7@pengutronix.de> <20241108-network-k3-v1-1-ee71bff15eb7@pengutronix.de>
Message-ID: <CAP1tNvRqjVvAiGj-=G5B4PsY21EAeQ3RsOA1T04MrS8mr+TXcg@mail.gmail.com>

Hello.

This patch caused a build conflict with ARCH_AM33XX.
Probably ARCH_OMAP3 should be replaced with ARCH_OMAP.

PATH=$PATH:/usr/local/usr5/bin CROSS_COMPILE=arm-buildroot-linux-gnueabihf- make
ARCH=arm mm_am335x_defconfig

WARNING: unmet direct dependencies detected for DRIVER_NET_TI_DAVINCI_MDIO
 Depends on [n]: NET [=y] && (ARCH_OMAP3 [=n] || ARCH_K3 [=n] || COMPILE_TEST [
=n])
 Selected by [y]:
 - DRIVER_NET_CPSW [=y] && NET [=y] && ARCH_OMAP [=y]

WARNING: unmet direct dependencies detected for DRIVER_NET_TI_DAVINCI_MDIO
 Depends on [n]: NET [=y] && (ARCH_OMAP3 [=n] || ARCH_K3 [=n] || COMPILE_TEST [
=n])
 Selected by [y]:
 - DRIVER_NET_CPSW [=y] && NET [=y] && ARCH_OMAP [=y]

??, 8 ????. 2024??. ? 16:15, Sascha Hauer <s.hauer at pengutronix.de>:
>
> The davinci MDIO driver can be reused for the CPSW found on TI K3 SoCs
> which needs a new ethernet driver. Separate the MDIO driver from the
> CPSW driver to make it usable with other ethernet drivers.
>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
>  drivers/net/Kconfig        |   5 ++
>  drivers/net/Makefile       |   1 +
>  drivers/net/cpsw.c         | 178 ------------------------------------------
>  drivers/net/davinci_mdio.c | 188 +++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 194 insertions(+), 178 deletions(-)
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 13e9ff6924..7f0d277548 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -53,8 +53,13 @@ config DRIVER_NET_CS8900
>  config DRIVER_NET_CPSW
>         bool "CPSW ethernet driver"
>         depends on ARCH_OMAP
> +       select DRIVER_NET_TI_DAVINCI_MDIO
>         select PHYLIB
>
> +config DRIVER_NET_TI_DAVINCI_MDIO
> +       bool "TI Davinci MDIO driver"
> +       depends on ARCH_OMAP3 || COMPILE_TEST
> +
>  config DRIVER_NET_DAVINCI_EMAC
>         bool "TI Davinci/OMAP EMAC ethernet driver"
>         depends on ARCH_OMAP3
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 207345cfa3..b451813f7c 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_DRIVER_NET_BCMGENET)     += bcmgenet.o
>  obj-$(CONFIG_DRIVER_NET_CS8900)                += cs8900.o
>  obj-$(CONFIG_DRIVER_NET_CPSW)          += cpsw.o
>  obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC)  += davinci_emac.o
> +obj-$(CONFIG_DRIVER_NET_TI_DAVINCI_MDIO) += davinci_mdio.o
>  obj-$(CONFIG_DRIVER_NET_DESIGNWARE)    += designware.o
>  obj-$(CONFIG_DRIVER_NET_DESIGNWARE_GENERIC) += designware_generic.o
>  obj-$(CONFIG_DRIVER_NET_DESIGNWARE_SOCFPGA) += designware_socfpga.o
> diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
> index 3e4f6502f9..b11930fdd0 100644
> --- a/drivers/net/cpsw.c
> +++ b/drivers/net/cpsw.c
> @@ -28,8 +28,6 @@
>  #define CPSW_VERSION_2         0x19010c
>
>  #define BITMASK(bits)          ((1 << (bits)) - 1)
> -#define PHY_REG_MASK           0x1f
> -#define PHY_ID_MASK            0x1f
>  #define NUM_DESCS              (PKTBUFSRX * 2)
>  #define PKT_MIN                        60
>  #define PKT_MAX                        (1500 + 14 + 4 + 4)
> @@ -60,34 +58,6 @@
>
>  #define SLIVER_SIZE            0x40
>
> -struct cpsw_mdio_regs {
> -       u32     version;
> -       u32     control;
> -#define CONTROL_IDLE           (1 << 31)
> -#define CONTROL_ENABLE         (1 << 30)
> -
> -       u32     alive;
> -       u32     link;
> -       u32     linkintraw;
> -       u32     linkintmasked;
> -       u32     __reserved_0[2];
> -       u32     userintraw;
> -       u32     userintmasked;
> -       u32     userintmaskset;
> -       u32     userintmaskclr;
> -       u32     __reserved_1[20];
> -
> -       struct {
> -               u32 access;
> -               u32 physel;
> -#define USERACCESS_GO          (1 << 31)
> -#define USERACCESS_WRITE       (1 << 30)
> -#define USERACCESS_ACK         (1 << 29)
> -#define USERACCESS_READ                (0)
> -#define USERACCESS_DATA                (0xffff)
> -       } user[0];
> -};
> -
>  struct cpsw_regs {
>         u32     id_ver;
>         u32     control;
> @@ -226,12 +196,6 @@ struct cpsw_priv {
>         struct cpsw_slave               *slaves;
>  };
>
> -struct cpsw_mdio_priv {
> -       struct device                   *dev;
> -       struct mii_bus                  miibus;
> -       struct cpsw_mdio_regs           *mdio_regs;
> -};
> -
>  static int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits)
>  {
>         int idx;
> @@ -524,148 +488,6 @@ static inline void cpsw_ale_port_state(struct cpsw_priv *priv, int port,
>         writel(tmp, priv->ale_regs + offset);
>  }
>
> -/* wait until hardware is ready for another user access */
> -static u32 wait_for_user_access(struct cpsw_mdio_priv *priv)
> -{
> -       struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs;
> -       u32 tmp;
> -       uint64_t start = get_time_ns();
> -
> -       do {
> -               tmp = readl(&mdio_regs->user[0].access);
> -
> -               if (!(tmp & USERACCESS_GO))
> -                       break;
> -
> -               if (is_timeout(start, 100 * MSECOND)) {
> -                       dev_err(priv->dev, "timeout waiting for user access\n");
> -                       break;
> -               }
> -       } while (1);
> -
> -       return tmp;
> -}
> -
> -static int cpsw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
> -{
> -       struct cpsw_mdio_priv *priv = bus->priv;
> -       struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs;
> -
> -       u32 tmp;
> -
> -       if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
> -               return -EINVAL;
> -
> -       wait_for_user_access(priv);
> -
> -       tmp = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
> -              (phy_id << 16));
> -       writel(tmp, &mdio_regs->user[0].access);
> -
> -       tmp = wait_for_user_access(priv);
> -
> -       return (tmp & USERACCESS_ACK) ? (tmp & USERACCESS_DATA) : -1;
> -}
> -
> -static int cpsw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, u16 value)
> -{
> -       struct cpsw_mdio_priv *priv = bus->priv;
> -       struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs;
> -       u32 tmp;
> -
> -       if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
> -               return -EINVAL;
> -
> -       wait_for_user_access(priv);
> -       tmp = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
> -                  (phy_id << 16) | (value & USERACCESS_DATA));
> -       writel(tmp, &mdio_regs->user[0].access);
> -       wait_for_user_access(priv);
> -
> -       return 0;
> -}
> -
> -static int cpsw_mdio_probe(struct device *dev)
> -{
> -       struct resource *iores;
> -       struct cpsw_mdio_priv *priv;
> -       uint64_t start;
> -       uint32_t phy_mask;
> -       int ret;
> -
> -       priv = xzalloc(sizeof(*priv));
> -
> -       /* If we can't request I/O memory region, we'll assume parent did
> -        * it for us
> -        */
> -       iores = dev_request_mem_resource(dev, 0);
> -       if (IS_ERR(iores) && PTR_ERR(iores) == -EBUSY)
> -               iores = dev_get_resource(dev, IORESOURCE_MEM, 0);
> -       if (IS_ERR(iores))
> -               return PTR_ERR(iores);
> -       priv->mdio_regs = IOMEM(iores->start);
> -       priv->miibus.read = cpsw_mdio_read;
> -       priv->miibus.write = cpsw_mdio_write;
> -       priv->miibus.priv = priv;
> -       priv->miibus.parent = dev;
> -
> -       /*
> -        * set enable and clock divider
> -        *
> -        * FIXME: Use a clock to calculate the divider
> -        */
> -       writel(0xff | CONTROL_ENABLE, &priv->mdio_regs->control);
> -
> -       /*
> -        * wait for scan logic to settle:
> -        * the scan time consists of (a) a large fixed component, and (b) a
> -        * small component that varies with the mii bus frequency.  These
> -        * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
> -        * silicon.  Since the effect of (b) was found to be largely
> -        * negligible, we keep things simple here.
> -        */
> -       udelay(2000);
> -
> -       start = get_time_ns();
> -       while (1) {
> -               phy_mask = readl(&priv->mdio_regs->alive);
> -               if (phy_mask) {
> -                       dev_info(dev, "detected phy mask 0x%x\n", phy_mask);
> -                       phy_mask = ~phy_mask;
> -                       break;
> -               }
> -               if (is_timeout(start, 256 * MSECOND)) {
> -                       dev_err(dev, "no live phy, scanning all\n");
> -                       phy_mask = 0;
> -                       break;
> -               }
> -       }
> -
> -       priv->miibus.phy_mask = phy_mask;
> -
> -       ret = mdiobus_register(&priv->miibus);
> -       if (ret)
> -               return ret;
> -
> -       return 0;
> -}
> -
> -static __maybe_unused struct of_device_id cpsw_mdio_dt_ids[] = {
> -       {
> -               .compatible = "ti,cpsw-mdio",
> -       }, {
> -               /* sentinel */
> -       }
> -};
> -MODULE_DEVICE_TABLE(of, cpsw_mdio_dt_ids);
> -
> -static struct driver cpsw_mdio_driver = {
> -       .name   = "cpsw-mdio",
> -       .probe  = cpsw_mdio_probe,
> -       .of_compatible = DRV_OF_COMPAT(cpsw_mdio_dt_ids),
> -};
> -coredevice_platform_driver(cpsw_mdio_driver);
> -
>  static inline void soft_reset(struct cpsw_priv *priv, void *reg)
>  {
>         int ret;
> diff --git a/drivers/net/davinci_mdio.c b/drivers/net/davinci_mdio.c
> new file mode 100644
> index 0000000000..c5cd28fba4
> --- /dev/null
> +++ b/drivers/net/davinci_mdio.c
> @@ -0,0 +1,188 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * DaVinci MDIO Module driver
> + */
> +#include <driver.h>
> +#include <linux/phy.h>
> +#include <clock.h>
> +#include <xfuncs.h>
> +#include <io.h>
> +
> +#define PHY_REG_MASK           0x1f
> +#define PHY_ID_MASK            0x1f
> +
> +struct cpsw_mdio_regs {
> +       u32     version;
> +       u32     control;
> +#define CONTROL_IDLE           (1 << 31)
> +#define CONTROL_ENABLE         (1 << 30)
> +
> +       u32     alive;
> +       u32     link;
> +       u32     linkintraw;
> +       u32     linkintmasked;
> +       u32     __reserved_0[2];
> +       u32     userintraw;
> +       u32     userintmasked;
> +       u32     userintmaskset;
> +       u32     userintmaskclr;
> +       u32     __reserved_1[20];
> +
> +       struct {
> +               u32 access;
> +               u32 physel;
> +#define USERACCESS_GO          (1 << 31)
> +#define USERACCESS_WRITE       (1 << 30)
> +#define USERACCESS_ACK         (1 << 29)
> +#define USERACCESS_READ                (0)
> +#define USERACCESS_DATA                (0xffff)
> +       } user[0];
> +};
> +
> +struct cpsw_mdio_priv {
> +       struct device                   *dev;
> +       struct mii_bus                  miibus;
> +       struct cpsw_mdio_regs           *mdio_regs;
> +};
> +
> +/* wait until hardware is ready for another user access */
> +static u32 wait_for_user_access(struct cpsw_mdio_priv *priv)
> +{
> +       struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs;
> +       u32 tmp;
> +       uint64_t start = get_time_ns();
> +
> +       do {
> +               tmp = readl(&mdio_regs->user[0].access);
> +
> +               if (!(tmp & USERACCESS_GO))
> +                       break;
> +
> +               if (is_timeout(start, 100 * MSECOND)) {
> +                       dev_err(priv->dev, "timeout waiting for user access\n");
> +                       break;
> +               }
> +       } while (1);
> +
> +       return tmp;
> +}
> +
> +static int cpsw_mdio_read(struct mii_bus *bus, int phy_id, int phy_reg)
> +{
> +       struct cpsw_mdio_priv *priv = bus->priv;
> +       struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs;
> +
> +       u32 tmp;
> +
> +       if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
> +               return -EINVAL;
> +
> +       wait_for_user_access(priv);
> +
> +       tmp = (USERACCESS_GO | USERACCESS_READ | (phy_reg << 21) |
> +              (phy_id << 16));
> +       writel(tmp, &mdio_regs->user[0].access);
> +
> +       tmp = wait_for_user_access(priv);
> +
> +       return (tmp & USERACCESS_ACK) ? (tmp & USERACCESS_DATA) : -1;
> +}
> +
> +static int cpsw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, u16 value)
> +{
> +       struct cpsw_mdio_priv *priv = bus->priv;
> +       struct cpsw_mdio_regs *mdio_regs = priv->mdio_regs;
> +       u32 tmp;
> +
> +       if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK)
> +               return -EINVAL;
> +
> +       wait_for_user_access(priv);
> +       tmp = (USERACCESS_GO | USERACCESS_WRITE | (phy_reg << 21) |
> +                  (phy_id << 16) | (value & USERACCESS_DATA));
> +       writel(tmp, &mdio_regs->user[0].access);
> +       wait_for_user_access(priv);
> +
> +       return 0;
> +}
> +
> +static int cpsw_mdio_probe(struct device *dev)
> +{
> +       struct resource *iores;
> +       struct cpsw_mdio_priv *priv;
> +       uint64_t start;
> +       uint32_t phy_mask;
> +       int ret;
> +
> +       priv = xzalloc(sizeof(*priv));
> +
> +       /* If we can't request I/O memory region, we'll assume parent did
> +        * it for us
> +        */
> +       iores = dev_request_mem_resource(dev, 0);
> +       if (IS_ERR(iores) && PTR_ERR(iores) == -EBUSY)
> +               iores = dev_get_resource(dev, IORESOURCE_MEM, 0);
> +       if (IS_ERR(iores))
> +               return PTR_ERR(iores);
> +       priv->mdio_regs = IOMEM(iores->start);
> +       priv->miibus.read = cpsw_mdio_read;
> +       priv->miibus.write = cpsw_mdio_write;
> +       priv->miibus.priv = priv;
> +       priv->miibus.parent = dev;
> +
> +       /*
> +        * set enable and clock divider
> +        *
> +        * FIXME: Use a clock to calculate the divider
> +        */
> +       writel(0xff | CONTROL_ENABLE, &priv->mdio_regs->control);
> +
> +       /*
> +        * wait for scan logic to settle:
> +        * the scan time consists of (a) a large fixed component, and (b) a
> +        * small component that varies with the mii bus frequency.  These
> +        * were estimated using measurements at 1.1 and 2.2 MHz on tnetv107x
> +        * silicon.  Since the effect of (b) was found to be largely
> +        * negligible, we keep things simple here.
> +        */
> +       udelay(2000);
> +
> +       start = get_time_ns();
> +       while (1) {
> +               phy_mask = readl(&priv->mdio_regs->alive);
> +               if (phy_mask) {
> +                       dev_info(dev, "detected phy mask 0x%x\n", phy_mask);
> +                       phy_mask = ~phy_mask;
> +                       break;
> +               }
> +               if (is_timeout(start, 256 * MSECOND)) {
> +                       dev_err(dev, "no live phy, scanning all\n");
> +                       phy_mask = 0;
> +                       break;
> +               }
> +       }
> +
> +       priv->miibus.phy_mask = phy_mask;
> +
> +       ret = mdiobus_register(&priv->miibus);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static __maybe_unused struct of_device_id cpsw_mdio_dt_ids[] = {
> +       {
> +               .compatible = "ti,cpsw-mdio",
> +       }, {
> +               /* sentinel */
> +       }
> +};
> +MODULE_DEVICE_TABLE(of, cpsw_mdio_dt_ids);
> +
> +static struct driver cpsw_mdio_driver = {
> +       .name   = "cpsw-mdio",
> +       .probe  = cpsw_mdio_probe,
> +       .of_compatible = DRV_OF_COMPAT(cpsw_mdio_dt_ids),
> +};
> +coredevice_platform_driver(cpsw_mdio_driver);
>
> --
> 2.39.5
>
>


From s.hauer at pengutronix.de  Mon Feb 17 01:27:22 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 10:27:22 +0100
Subject: [PATCH 0/7] commands: boot: add support for overriding boot
 artifacts
In-Reply-To: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
References: <20250214104817.2975052-1-a.fatoum@pengutronix.de>
Message-ID: <173978444252.160382.13997161609509522745.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 11:48:10 +0100, Ahmad Fatoum wrote:
> Replacing part of the boot artifacts is a common development use case,
> e.g. to load the kernel from the network, but otherwise boot the
> bootloader spec file as-is or to inject an initrd into an existing boot
> flow (e.g. rsinit to enable usb9pfs boot).
> 
> This series adds a simple to use way to achieve that.
> 
> [...]

Applied, thanks!

[1/7] bootm: add helper functions for checking if FIT image is used
      https://git.pengutronix.de/cgit/barebox/commit/?id=6244bcb9db80 (link may not be stable)
[2/7] boot: move global.linux.bootargs.dyn. to common code
      https://git.pengutronix.de/cgit/barebox/commit/?id=1072e8421458 (link may not be stable)
[3/7] blspec: don't clobber bootm.image on boot attempt
      https://git.pengutronix.de/cgit/barebox/commit/?id=f2c284fa14d6 (link may not be stable)
[4/7] fastboot: drop useless bootm.image clobber
      https://git.pengutronix.de/cgit/barebox/commit/?id=3a07779b01e6 (link may not be stable)
[5/7] bootm: don't clobber global.bootm. variables after script boot fails
      https://git.pengutronix.de/cgit/barebox/commit/?id=926985a74ee0 (link may not be stable)
[6/7] bootm: retire bootm_has_initrd
      https://git.pengutronix.de/cgit/barebox/commit/?id=e86606dd2065 (link may not be stable)
[7/7] commands: boot: add support for overriding boot artifacts
      https://git.pengutronix.de/cgit/barebox/commit/?id=a5e4c4340ef6 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 01:33:24 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 10:33:24 +0100
Subject: [PATCH] mount: support specifying mount -o options more than
 once
In-Reply-To: <20250214103114.2900899-1-a.fatoum@pengutronix.de>
References: <20250214103114.2900899-1-a.fatoum@pengutronix.de>
Message-ID: <173978480466.264173.2782075133124227046.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 11:31:14 +0100, Ahmad Fatoum wrote:
> Specifying -o more than once is useful for scripts: A mount.9P script
> for example can specify some default options and the caller of the
> script can specify an extra -o to add extra options.
> 
> This is supported by normal mount(1), but wasn't so far in the barebox
> variant. Remedy that.
> 
> [...]

Applied, thanks!

[1/1] mount: support specifying mount -o options more than once
      https://git.pengutronix.de/cgit/barebox/commit/?id=2d3f9bf831f1 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 01:48:20 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 10:48:20 +0100
Subject: [PATCH 1/3] lib: add scatterlist abstraction
In-Reply-To: <20250214101206.2876051-1-a.fatoum@pengutronix.de>
References: <20250214101206.2876051-1-a.fatoum@pengutronix.de>
Message-ID: <173978570052.551144.12311101416064673133.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 11:12:04 +0100, Ahmad Fatoum wrote:
> With barebox using 1:1 memory mapping whenever possible, scatter-gather
> DMA seems not that important. Many Linux APIs use struct scatterlist
> as parameters though, so adding a basic support in barebox will make
> easier to port these drivers.
> 
> 

Applied, thanks!

[1/3] lib: add scatterlist abstraction
      https://git.pengutronix.de/cgit/barebox/commit/?id=118ef08339cc (link may not be stable)
[2/3] virtio: replace virtio_sg with common scatterlist
      https://git.pengutronix.de/cgit/barebox/commit/?id=2336406d2b91 (link may not be stable)
[3/3] virtio: add token data parameter to virtqueue_add_sgs
      https://git.pengutronix.de/cgit/barebox/commit/?id=2bafe34d2f68 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 01:49:32 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 10:49:32 +0100
Subject: [PATCH] boot: omit menu freeing loop when CONFIG_MENU is
 disabled
In-Reply-To: <20250214095412.2852561-1-a.fatoum@pengutronix.de>
References: <20250214095412.2852561-1-a.fatoum@pengutronix.de>
Message-ID: <173978577242.594783.15301060220289503148.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 10:54:12 +0100, Ahmad Fatoum wrote:
> While free() can handle NULL pointers, it's better to not even call
> free() when we know at compile-time that the pointers are NULL.
> 
> 

Applied, thanks!

[1/1] boot: omit menu freeing loop when CONFIG_MENU is disabled
      https://git.pengutronix.de/cgit/barebox/commit/?id=b75e35471167 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From a.fatoum at pengutronix.de  Mon Feb 17 01:59:21 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 10:59:21 +0100
Subject: [PATCH] usb: dwc3: fix use of bool for prompt choice
Message-ID: <20250217095921.1622983-1-a.fatoum@pengutronix.de>

A choice has a prompt, but no type. Newer versions of Kconfig will
start throwing an error if this is violated, so fix it in anticipation.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/usb/dwc3/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index ef1f83bef7aa..de5f0ef6f3eb 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -15,7 +15,7 @@ config USB_DWC3
 if USB_DWC3
 
 choice
-	bool "DWC3 Mode Selection"
+	prompt "DWC3 Mode Selection"
 
 config USB_DWC3_HOST
 	bool "Host only mode"
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 02:02:13 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 11:02:13 +0100
Subject: [PATCH] kbuild: export HOSTPKG_CONFIG like Linux does
Message-ID: <20250217100213.1637911-1-a.fatoum@pengutronix.de>

Since Linux commit d5ea4fece450 ("kbuild: Allow kernel installation packaging
to override pkg-config"), Linux supports overriding the pkg-config
executable via the HOSTPKG_CONFIG variable.

barebox already had that support, but with a differently named PKG_CONFIG
variable. For compatibility with build systems assuming Linux Kbuild and
to allow easier sharing of code (e.g. scripts/kconfig), define
HOSTPKG_CONFIG for barebox as well.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 3d2abbbcbcab..b5a7d0b9918b 100644
--- a/Makefile
+++ b/Makefile
@@ -371,9 +371,10 @@ endif
 KCONFIG_CONFIG	?= .config
 
 PKG_CONFIG ?= pkg-config
+HOSTPKG_CONFIG = $(PKG_CONFIG)
 CROSS_PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config
 
-export KCONFIG_CONFIG CROSS_PKG_CONFIG PKG_CONFIG
+export KCONFIG_CONFIG CROSS_PKG_CONFIG PKG_CONFIG HOSTPKG_CONFIG
 
 # SHELL used by kbuild
 CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
-- 
2.39.5



From s.hauer at pengutronix.de  Mon Feb 17 02:26:50 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 11:26:50 +0100
Subject: [PATCH 1/3] fs: move fs_driver open/close into struct
 file_operations
In-Reply-To: <20250214095157.2850839-1-a.fatoum@pengutronix.de>
References: <20250214095157.2850839-1-a.fatoum@pengutronix.de>
Message-ID: <173978801098.1325040.4745009863210752449.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 10:51:55 +0100, Ahmad Fatoum wrote:
> Linux places open and close (called release) in struct file_operations
> and thereby allows implementing them differently depending on inode type.
> 
> So far, not being able to do that in barebox didn't bother us much, but
> some kernel file systems depend on the directories to be opened before
> they are iterated through and barebox will start supporting that in the
> later commit.
> 
> [...]

Applied, thanks!

[1/3] fs: move fs_driver open/close into struct file_operations
      https://git.pengutronix.de/cgit/barebox/commit/?id=e31ca2eea7be (link may not be stable)
[2/3] fs: remove unused members in struct file_operations
      https://git.pengutronix.de/cgit/barebox/commit/?id=88798bebccd7 (link may not be stable)
[3/3] fs: drop unused FS_DRIVER_NO_DEV flag
      https://git.pengutronix.de/cgit/barebox/commit/?id=a92e661073ff (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 02:32:01 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 11:32:01 +0100
Subject: [PATCH] nfs: add $global.net.nfsport override
In-Reply-To: <20250214095050.2849460-1-a.fatoum@pengutronix.de>
References: <20250214095050.2849460-1-a.fatoum@pengutronix.de>
Message-ID: <173978832139.1413739.233111689850722695.b4-ty@pengutronix.de>


On Fri, 14 Feb 2025 10:50:50 +0100, Ahmad Fatoum wrote:
> Since commit 3ea30d9ce892 ("nfs: parse nfsport and mount port from file
> system options"), it's possible to hard code the ports used for NFS,
> which is especially useful when talking to a non-kernel NFS daemon
> like unfsd.
> 
> Add a way to change the NFS port for the /mnt/nfs automount automount to
> make this feature more accessible.
> 
> [...]

Applied, thanks!

[1/1] nfs: add $global.net.nfsport override
      https://git.pengutronix.de/cgit/barebox/commit/?id=a32e6ac4afd3 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From m.felsch at pengutronix.de  Mon Feb 17 02:32:33 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 17 Feb 2025 11:32:33 +0100
Subject: [PATCH master 3/3] Documentation: user: add security
 consideration for using barebox
In-Reply-To: <20250214142356.3624561-3-a.fatoum@pengutronix.de>
References: <20250214142356.3624561-1-a.fatoum@pengutronix.de>
 <20250214142356.3624561-3-a.fatoum@pengutronix.de>
Message-ID: <20250217103233.mrqqadj7qqedus2e@pengutronix.de>

Hi Ahmad,

thanks for your patches!

On 25-02-14, Ahmad Fatoum wrote:
> There are implicit assumptions around use of barebox in secure systems,
> which isn't spelt out anywhere, e.g. that FIT images should be located
> in raw partitions.
> 
> Let's start by writing down these security considerations.
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

you can add my

Reviewed-by: Marco Felsch <m.felsch at pengutronix.de>

for the whole series.

Regards,
  Marco


> ---
>  Documentation/boards/imx.rst    |   2 +
>  Documentation/user/security.rst | 160 ++++++++++++++++++++++++++++++++
>  2 files changed, 162 insertions(+)
>  create mode 100644 Documentation/user/security.rst
> 
> diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst
> index 13246599838b..b4adb55d1bea 100644
> --- a/Documentation/boards/imx.rst
> +++ b/Documentation/boards/imx.rst
> @@ -119,6 +119,8 @@ correspond directly to the boot fusemap settings.
>  
>  See the section on :ref:`Reboot modes<reboot_mode>` for general information.
>  
> +.. _hab:
> +
>  High Assurance Boot
>  ^^^^^^^^^^^^^^^^^^^
>  
> diff --git a/Documentation/user/security.rst b/Documentation/user/security.rst
> new file mode 100644
> index 000000000000..507df9a79e84
> --- /dev/null
> +++ b/Documentation/user/security.rst
> @@ -0,0 +1,160 @@
> +.. _security:
> +
> +Security Considerations
> +=======================
> +
> +As bootloader, barebox is often used as part of a cryptographically verified
> +boot chain. Such a boot chain is only as secure as its weakest link and
> +special care needs to be taken while configuring and deploying barebox.
> +
> +Verified Boot
> +-------------
> +
> +In a cryptographically verified boot chain (henceforth termed "Verified Boot"),
> +each boot stage must be verified by the previous boot stage before execution.
> +
> +At the start of the verification chain lies some hardware root of trust, most
> +often a public key (or its hash) that's programmed into one-time-programmable
> +(OTP) eFuses while the board is still in the factory.
> +
> +The SoC's mask ROM (sometime called BootROM) will consult the eFuses and
> +use them to verify the first stage bootloader image. From there on, it's
> +expected that every boot stage will only boot the next one after verification.
> +
> +Verification can take many forms:
> +
> +- The mask ROM provides an API to verify later images against the same key
> +  used to verify the first boot stage.
> +
> +- If both first stage and second stage result from the same build, the first
> +  stage can embed the hash of the second stage.
> +
> +- The boot stage has an embedded public key which is used to verify the
> +  signature of the later boot stage.
> +
> +Verifying barebox itself
> +------------------------
> +
> +The way that barebox is verified is highly SoC-specific as it's usually done
> +by the SoC mask ROM and in some cases by a different first stage bootloader
> +like ARM Trusted Firmware.
> +
> +For some SoCs, like i.MX :ref:`High Assurance Boot <hab>`, the barebox
> +build system has built-in support for invoking the necessary external tools
> +to sign the boot images.  In the general case however, the signing happens
> +outside the barebox build system and the integrator needs to ensure that
> +the images are signed with the correct keys.
> +
> +In any case, each individual board must be locked down, i.e., configured to
> +only boot correctly signed images.
> +
> +The latter is often done by writing a different set of eFuses, see for
> +example the barebox :ref:`hab command <command_hab>` which does the necessary
> +fusing for both HABv4 and AHAB.
> +
> +.. warning:: barebox commands likes :ref:`hab command <command_hab>` do only
> +   touch the subset of fuses relevant to most users. It's up to the integrators
> +   to fuse away unneeded functionality like USB recovery or JTAG as needed.
> +
> +Loading firmware
> +----------------
> +
> +In systems utilizing the ARM TrustZone, barebox is often tasked with loading
> +the secure OS (Usually OP-TEE). After OP-TEE is loaded, the rest of the
> +software runs in a less-privileged non-secure or "normal" world.
> +
> +The installation of OP-TEE (and any higher privileged firmware like ARM Trusted
> +Firmware) should happen as early as possible, i.e., within the barebox
> +:ref:`prebootloader <pbl>`. Delaying installation of OP-TEE means that most of
> +barebox will run with elevated permission, which greatly increases the attack
> +surface.
> +
> +In concrete terms, the deprecated ``CONFIG_BOOTM_OPTEE`` option should be
> +disabled in favor of :ref:`loading OP-TEE early <optee_early_loading>`.
> +
> +Verifying the kernel by barebox
> +-------------------------------
> +
> +barebox can embed one or more RSA or ECDSA public keys that it will use to
> +verify signed FIT images. In a verified boot system, barebox should not
> +be allowed to boot any images that have not been signed by the correct key.
> +This can be enforced by setting ``CONFIG_BOOTM_FORCE_SIGNED_IMAGES=y``
> +and disabling any ways that could use used to override this, e.g.:
> +
> +- While useful for development, the barebox shell can be used in creative
> +  ways to circumvent boot restrictions. It's thus advisable to disable
> +  the shell completely (``CONFIG_SHELL_NONE=y``) or make it non-interactive
> +  (``CONSOLE_DISABLE_INPUT=y``). This may be coupled with muxing UART RX
> +  pin as GPIO for maximum effectiveness.
> +
> +- Anything done interactively by the shell can also be done automatically by
> +  means of init scripts in the environment. A secure barebox should only
> +  consult the environment that it has built in and not parse an externally
> +  located environment.
> +  This can be enforced by disabling ``CONFIG_ENV_HANDLING``.
> +  This does not preclude the use of :ref:`Bootchooser` as the
> +  :ref:`barebox-state framework <state_framework>` can be used independently.
> +
> +- There are alternative methods of accessing the shell like netconsole,
> +  or fastboot. These should preferably be disabled or at least not activated
> +  by default.
> +
> +Note that any list here is bound to be incomplete. The barebox configuration
> +needs to be vetted individually according to threat model.
> +
> +Use of file systems
> +^^^^^^^^^^^^^^^^^^^
> +
> +File systems are among the most complex parser code in barebox and a common
> +source of bugs.
> +Unlike Linux with its dm-verity support, barebox currently has no way to
> +verify a file system before mounting it.
> +
> +The consequence is that in a verified boot setup, barebox should **never**
> +be allowed to mount file systems.
> +Especially, :ref:`bootloader spec files <bootloader_spec>` should not be used
> +in verified boot setups and signed FIT images **must** be located outside
> +a file system and directly in a raw partition.
> +
> +Configuring barebox
> +-------------------
> +
> +To aid identification of security impact of config options, barebox provides
> +two top-level security-related options:
> +
> +- ``CONFIG_INSECURE``: This enables convenient, but insecure, defaults.
> +  Any secure system should disable this option.
> +
> +- ``CONFIG_HAS_INSECURE_DEFAULT``: This is selected by options that have
> +  an outsized potential of compromising security. It's recommended that
> +  all configuration options that select ``CONFIG_HAS_INSECURE_DEFAULT``
> +  are disabled.
> +  If not possible, special care needs to be taken in vetting the insecure
> +  defaults in question.
> +
> +Compile-time configuration
> +^^^^^^^^^^^^^^^^^^^^^^^^^^
> +
> +Any code that's eliminated at compile-time is code that can't be exploited by
> +an attacker. It's thus strongly advisable to keep a separate secure
> +configuration that disables all features that are used for development and
> +are not absolutely necessary for booting in the field.
> +
> +Run-time configuration
> +^^^^^^^^^^^^^^^^^^^^^^
> +
> +It's sometimes desirable to retain some ability to debug locked down systems.
> +While attractive, it's not recommended to retain an insecure bootloader for
> +the purposes of debugging due to the risk of this bootloader being leaked.
> +
> +Instead, it's recommended that debugging images are signed specifically to
> +target only a specific board.
> +
> +This is sometimes supported out-of-the-box by the SoC like with the HABv4
> +field return feature.
> +
> +In the generic case, barebox supports verification of JSON Web Tokens against
> +a compiled-in RSA public key. Board code should read the JSON Web Token
> +(e.g., from a raw partition on a USB mass storage device), verify the
> +serial number claim within against the board's actual serial number and only
> +then unlock any debugging functionality.
> -- 
> 2.39.5
> 
> 
> 


From a.fatoum at pengutronix.de  Mon Feb 17 02:46:08 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 11:46:08 +0100
Subject: [PATCH 1/4] sandbox: make CC_HAS_LINUX_I386_SUPPORT depend on GCC
Message-ID: <20250217104611.1836442-1-a.fatoum@pengutronix.de>

CC_HAS_LINUX_I386_SUPPORT enables build for 32-bit with a 64-bit GCC
toolchain. This seems not to work correctly on clang:

  CC      arch/sandbox/os/common.o
  In file included from arch/sandbox/os/common.c:23:
  In file included from /usr/lib/llvm-16/lib/clang/16/include/limits.h:21:
  /usr/include/limits.h:26:10: fatal error:
                               'bits/libc-header-start.h' file not found
  #include <bits/libc-header-start.h>

So disable it for now.

Fixes: f41c4d7c5649 ("Makefile: add LLVM/clang support")
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/sandbox/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/sandbox/Kconfig b/arch/sandbox/Kconfig
index 0b6cc75098be..c1a51d4f021d 100644
--- a/arch/sandbox/Kconfig
+++ b/arch/sandbox/Kconfig
@@ -40,6 +40,7 @@ config CC_IS_64BIT
 
 config CC_HAS_LINUX_I386_SUPPORT
 	def_bool $(cc-option,-m32) && $(ld-option,-m elf_i386)
+	depends on CC_IS_GCC
 
 config 64BIT
 	bool
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 02:46:11 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 11:46:11 +0100
Subject: [PATCH 4/4] Makefile: clang: fail non-sandbox LLVM builds early
In-Reply-To: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
References: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
Message-ID: <20250217104611.1836442-4-a.fatoum@pengutronix.de>

The sandbox architecture is the only architecture so far that has been
validated to build to completion with clang and function correctly
afterwards.

Until other architectures follow suit, fail the build gracefully for them.

Note that in Linux, CLANG_TARGET_FLAGS_sandbox expands to
$(CLANG_TARGET_FLAGS_$(SRCARCH)). This requires that we have support for
non-sandbox architectures in the first place. Until we do, just make it
a no-op by setting CLANG_TARGET_FLAGS to the same target triple that's used
by default anyway.

Reported-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 scripts/Makefile.clang | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/scripts/Makefile.clang b/scripts/Makefile.clang
index 874110ea83ad..7e4dfb8622d3 100644
--- a/scripts/Makefile.clang
+++ b/scripts/Makefile.clang
@@ -1,4 +1,14 @@
 # SPDX-License-Identifier: GPL-2.0-only
+
+CLANG_TARGET_FLAGS_sandbox	:= $(shell $(CC) -print-target-triple)
+CLANG_TARGET_FLAGS		:= $(CLANG_TARGET_FLAGS_$(SRCARCH))
+
+ifeq ($(CLANG_TARGET_FLAGS),)
+$(error add '--target=' option to scripts/Makefile.clang)
+else
+CLANG_FLAGS	+= --target=$(CLANG_TARGET_FLAGS)
+endif
+
 CLANG_FLAGS	+= -Wno-typedef-redefinition
 CLANG_FLAGS	+= -Werror=unknown-warning-option
 CLANG_FLAGS	+= -Werror=ignored-optimization-argument
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 02:46:09 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 11:46:09 +0100
Subject: [PATCH 2/4] Makefile: clang: fix typo in -Wno-typdef-redefinition flag
In-Reply-To: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
References: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
Message-ID: <20250217104611.1836442-2-a.fatoum@pengutronix.de>

The file was not used so far, so the typo wasn't noticed. A later
commit is going to change that, so prepare for it by fixing the typo.

Fixes: f41c4d7c5649 ("Makefile: add LLVM/clang support")
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 scripts/Makefile.clang | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/Makefile.clang b/scripts/Makefile.clang
index c0302ff82670..874110ea83ad 100644
--- a/scripts/Makefile.clang
+++ b/scripts/Makefile.clang
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-CLANG_FLAGS	+= -Wno-typdef-redefinition
+CLANG_FLAGS	+= -Wno-typedef-redefinition
 CLANG_FLAGS	+= -Werror=unknown-warning-option
 CLANG_FLAGS	+= -Werror=ignored-optimization-argument
 CLANG_FLAGS	+= -Werror=option-ignored
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 02:46:10 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 11:46:10 +0100
Subject: [PATCH 3/4] kbuild: actually include Makefile.clang for clang builds
In-Reply-To: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
References: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
Message-ID: <20250217104611.1836442-3-a.fatoum@pengutronix.de>

Makefile.clang is included depending on CONFIG_CC_IS_CLANG, but its
location in the Makefile was before the config variables are included.

Instead of moving it farther down and risk it being included too late,
let's do as Linux does and consult CC_VERSION_TEXT instead of any
config variables.

Fixes: f41c4d7c5649 ("Makefile: add LLVM/clang support")
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Makefile | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index b5a7d0b9918b..a80e1b60d534 100644
--- a/Makefile
+++ b/Makefile
@@ -563,7 +563,13 @@ ifdef building_out_of_srctree
 	{ echo "# this is build directory, ignore it"; echo "*"; } > .gitignore
 endif
 
-ifeq ($(CONFIG_CC_IS_CLANG),y)
+# The expansion should be delayed until arch/$(SRCARCH)/Makefile is included.
+# Some architectures define CROSS_COMPILE in arch/$(SRCARCH)/Makefile.
+# CC_VERSION_TEXT is referenced from Kconfig (so it needs export),
+# and from include/config/auto.conf.cmd to detect the compiler upgrade.
+CC_VERSION_TEXT = $(subst $(pound),,$(shell LC_ALL=C $(CC) --version 2>/dev/null | head -n 1))
+
+ifneq ($(findstring clang,$(CC_VERSION_TEXT)),)
 include $(srctree)/scripts/Makefile.clang
 endif
 
@@ -578,7 +584,7 @@ include $(srctree)/scripts/Makefile.defconf
 # KBUILD_DEFCONFIG may point out an alternative default configuration
 # used for 'make defconfig'
 include $(srctree)/arch/$(SRCARCH)/Makefile
-export KBUILD_DEFCONFIG
+export KBUILD_DEFCONFIG CC_VERSION_TEXT
 
 config: outputmakefile scripts_basic FORCE
 	$(Q)$(MAKE) $(build)=scripts/kconfig $@
-- 
2.39.5



From s.hauer at pengutronix.de  Mon Feb 17 02:53:42 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 11:53:42 +0100
Subject: [PATCH 1/2] mci: core: import Linux logic for higher preferred
 erase size
In-Reply-To: <20250214094850.2847143-1-a.fatoum@pengutronix.de>
References: <20250214094850.2847143-1-a.fatoum@pengutronix.de>
Message-ID: <Z7MVNjkJiDazmLpc@pengutronix.de>

On Fri, Feb 14, 2025 at 10:48:49AM +0100, Ahmad Fatoum wrote:
> As a comment in the file notes, doing too small a granularity for erases
> has considerable effect on performance:
> 
>   > Example Samsung eMMC 8GTF4:
>   >
>   >   time erase /dev/mmc2.part_of_512m # 1024 trims
>   >   time: 2849ms
>   >
>   >   time erase /dev/mmc2.part_of_512m # single trim
>   >   time: 56ms
> 
> This was deemed acceptable at first, because 3 seconds is still
> tolerable.
> 
> On a SkyHigh S40004, an erase of the whole 3728 MiB ended up
> taking longer than 400s in barebox, but only 4s in Linux, which
> dwarfs the time actually needed for writing.
> 
> Linux has some rather complicated logic to compute a higher erase size
> granularity, which still fits in the max busy timeout that a controller
> may require. Until that's support in barebox, we import a simpler
> heuristic that Linux uses to compute
> 
>   /sys/class/mmc_host/*/*/preferred_erase_size
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
>  drivers/mci/mci-core.c | 105 ++++++++++++++++++++++++++---------------
>  include/mci.h          |   1 +
>  2 files changed, 69 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
> index cc3c6fba3653..6d55eb8305b9 100644
> --- a/drivers/mci/mci-core.c
> +++ b/drivers/mci/mci-core.c
> @@ -1774,6 +1774,70 @@ static int mci_startup_mmc(struct mci *mci)
>  	return ret >= MMC_BUS_WIDTH_1 ? 0 : ret;
>  }
>  
> +static void mci_init_erase(struct mci *card)
> +{
> +	unsigned int sz;
> +
> +	if (!IS_ENABLED(CONFIG_MCI_ERASE))
> +		return;
> +
> +	/* TODO: While it's possible to clear many erase groups at once
> +	 * and it greatly improves throughput, drivers need adjustment:
> +	 *
> +	 * Many drivers hardcode a maximal wait time before aborting
> +	 * the wait for R1b and returning -ETIMEDOUT. With long
> +	 * erases/trims, we are bound to run into this timeout, so for now
> +	 * we just split into sufficiently small erases that are unlikely
> +	 * to trigger the timeout.
> +	 *
> +	 * What Linux does and what we should be doing in barebox is:
> +	 *
> +	 *  - add a struct mci_cmd::busy_timeout member that drivers should
> +	 *    use instead of hardcoding their own timeout delay. The busy
> +	 *    timeout length can be calculated by the MCI core after
> +	 *    consulting the appropriate CSD/EXT_CSD/SSR registers.
> +	 *
> +	 *  - add a struct mci_host::max_busy_timeout member, where drivers
> +	 *    can indicate the maximum timeout they are able to support.
> +	 *    The MCI core will never set a busy_timeout that exceeds this
> +	 *    value.
> +	 *
> +	 *  Example Samsung eMMC 8GTF4:
> +	 *
> +	 *    time erase /dev/mmc2.part_of_512m # 1024 trims
> +	 *    time: 2849ms
> +	 *
> +	 *    time erase /dev/mmc2.part_of_512m # single trim
> +	 *    time: 56ms
> +	 */
> +	if (IS_SD(card) && card->ssr.au) {
> +		card->pref_erase = card->ssr.au;
> +	} else if (card->erase_grp_size) {
> +		sz = card->capacity >> 11;
> +		if (sz < 128)
> +			card->pref_erase = 512 * 1024 / 512;
> +		else if (sz < 512)
> +			card->pref_erase = 1024 * 1024 / 512;
> +		else if (sz < 1024)
> +			card->pref_erase = 2 * 1024 * 1024 / 512;
> +		else
> +			card->pref_erase = 4 * 1024 * 1024 / 512;

card->capacity is in bytes, so you are falling into the last case for
cards bigger than 512Kib. Did you mean to right shift by 21 or even 31
instead?

I would prefer using SZ_* and SECTOR_SIZE/SHIFT defines to make this more
readable.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Mon Feb 17 02:56:10 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 11:56:10 +0100
Subject: [PATCH] usb: dwc3: fix use of bool for prompt choice
In-Reply-To: <20250217095921.1622983-1-a.fatoum@pengutronix.de>
References: <20250217095921.1622983-1-a.fatoum@pengutronix.de>
Message-ID: <173978977088.1507439.14672706622177184571.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 10:59:21 +0100, Ahmad Fatoum wrote:
> A choice has a prompt, but no type. Newer versions of Kconfig will
> start throwing an error if this is violated, so fix it in anticipation.
> 
> 

Applied, thanks!

[1/1] usb: dwc3: fix use of bool for prompt choice
      https://git.pengutronix.de/cgit/barebox/commit/?id=c6b42a370d22 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 02:56:39 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 11:56:39 +0100
Subject: [PATCH] kbuild: export HOSTPKG_CONFIG like Linux does
In-Reply-To: <20250217100213.1637911-1-a.fatoum@pengutronix.de>
References: <20250217100213.1637911-1-a.fatoum@pengutronix.de>
Message-ID: <173978979980.1518006.3734495929155437641.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 11:02:13 +0100, Ahmad Fatoum wrote:
> Since Linux commit d5ea4fece450 ("kbuild: Allow kernel installation packaging
> to override pkg-config"), Linux supports overriding the pkg-config
> executable via the HOSTPKG_CONFIG variable.
> 
> barebox already had that support, but with a differently named PKG_CONFIG
> variable. For compatibility with build systems assuming Linux Kbuild and
> to allow easier sharing of code (e.g. scripts/kconfig), define
> HOSTPKG_CONFIG for barebox as well.
> 
> [...]

Applied, thanks!

[1/1] kbuild: export HOSTPKG_CONFIG like Linux does
      https://git.pengutronix.de/cgit/barebox/commit/?id=4e48ddac370c (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 03:05:48 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 12:05:48 +0100
Subject: [PATCH] net: Fix DRIVER_NET_TI_DAVINCI_MDIO dependency
Message-ID: <20250217110548.1695938-1-s.hauer@pengutronix.de>

The davinci-mdio driver was factored out from DRIVER_NET_CPSW which
depends on ARCH_OMAP, so DRIVER_NET_TI_DAVINCI_MDIO should depend
on the same symbol, not ARCH_OMAP3.

Fixes: f703666dd1 ("net: davinci_mdio: separate driver")
Reported-by: Alexander Shiyan <eagle.alexander923 at gmail.com>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/net/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0e78579250..5c436a05cc 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -58,7 +58,7 @@ config DRIVER_NET_CPSW
 
 config DRIVER_NET_TI_DAVINCI_MDIO
 	bool "TI Davinci MDIO driver"
-	depends on ARCH_OMAP3 || ARCH_K3 || COMPILE_TEST
+	depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST
 
 config DRIVER_NET_DAVINCI_EMAC
 	bool "TI Davinci/OMAP EMAC ethernet driver"
-- 
2.39.5



From s.hauer at pengutronix.de  Mon Feb 17 03:10:23 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 12:10:23 +0100
Subject: [PATCH] environment: fix free() of unitialized variable
In-Reply-To: <20250205094832.3576556-1-s.hauer@pengutronix.de>
References: <20250205094832.3576556-1-s.hauer@pengutronix.de>
Message-ID: <173979062379.1805746.12085164732940759491.b4-ty@pengutronix.de>


On Wed, 05 Feb 2025 10:48:32 +0100, Sascha Hauer wrote:
> of_find_path() doesn't initialize the outpath on error. In order to
> free() it in the error path we have to initialize devpath.
> 
> 

Applied, thanks!

[1/1] environment: fix free() of unitialized variable
      https://git.pengutronix.de/cgit/barebox/commit/?id=7221acb2f030 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 03:14:06 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 12:14:06 +0100
Subject: [PATCH v2 00/20] ARM: K3 updates
In-Reply-To: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
References: <20250212-k3-emmc-v2-0-8dd1bb0ce60a@pengutronix.de>
Message-ID: <173979084646.1871665.10273647272633691865.b4-ty@pengutronix.de>


On Wed, 12 Feb 2025 15:09:13 +0100, Sascha Hauer wrote:
> This series has some updates for the TI K3 architecture.
> 
> We add support for bootstrapping boards via USB DFU. This has been sent
> earlier, this time booting from eMMC is added as well.
> 
> On K3 SoCs we need a bunch of images after the first stage has been
> loaded: OP-TEE, ti-dm firmware, TF-A binary and finally a barebox
> binary. Until now these are expected as distinct images on the SD cards
> FAT partition. This is impractical for booting from eMMC boot partitions
> and also DFU boot, so this series adds support for handling a FIP image
> containing these binaries.
> 
> [...]

Applied, thanks!

[01/20] ARM: k3: Add function to enable 32k crystal
        https://git.pengutronix.de/cgit/barebox/commit/?id=f8488603862b (link may not be stable)
[02/20] ARM: k3: add function to detect eMMC boot
        https://git.pengutronix.de/cgit/barebox/commit/?id=4a3eac7dbaa1 (link may not be stable)
[03/20] ARM: k3: do not mount /boot when booting from eMMC
        https://git.pengutronix.de/cgit/barebox/commit/?id=def806a40287 (link may not be stable)
[04/20] fip: drop typedefs
        https://git.pengutronix.de/cgit/barebox/commit/?id=30c35fedb7ba (link may not be stable)
[05/20] fip: use linux list implementation
        https://git.pengutronix.de/cgit/barebox/commit/?id=bc79141e65cc (link may not be stable)
[06/20] fip: use uuid_equal() and uuid_is_null()
        https://git.pengutronix.de/cgit/barebox/commit/?id=e8074b140a14 (link may not be stable)
[07/20] fiptool: do not typedef structs
        https://git.pengutronix.de/cgit/barebox/commit/?id=d58d0997b8b7 (link may not be stable)
[08/20] fip: add fip_ prefix
        https://git.pengutronix.de/cgit/barebox/commit/?id=33ac1e970bc0 (link may not be stable)
[09/20] fip: add fip_image_open()
        https://git.pengutronix.de/cgit/barebox/commit/?id=72d281a4711b (link may not be stable)
[10/20] ARM: k3: r5: add USB DFU and eMMC boot support
        https://git.pengutronix.de/cgit/barebox/commit/?id=9124e7c0b563 (link may not be stable)
[11/20] ARM: am625-sk: enable 32k crystal
        https://git.pengutronix.de/cgit/barebox/commit/?id=63a39df42e94 (link may not be stable)
[12/20] mci: am654: parse generic mmc node properties
        https://git.pengutronix.de/cgit/barebox/commit/?id=10870f73f2fe (link may not be stable)
[13/20] ARM: k3: limit eMMC frequency to 26MHz
        https://git.pengutronix.de/cgit/barebox/commit/?id=b6099d814075 (link may not be stable)
[14/20] ARM: k3: add eMMC barebox update handler
        https://git.pengutronix.de/cgit/barebox/commit/?id=e7fc40adf484 (link may not be stable)
[15/20] ARM: am625-sk: put environment on eMMC when booting from it
        https://git.pengutronix.de/cgit/barebox/commit/?id=4458a181046d (link may not be stable)
[16/20] serial: omap: Use ttyS as Linux console name
        https://git.pengutronix.de/cgit/barebox/commit/?id=6ed7c03d3fb3 (link may not be stable)
[17/20] ARM: k3: remove beagleplay FIT image
        https://git.pengutronix.de/cgit/barebox/commit/?id=874477b04d02 (link may not be stable)
[18/20] ARM: am625-sk: cleanup board entry
        https://git.pengutronix.de/cgit/barebox/commit/?id=57e67d421450 (link may not be stable)
[19/20] ARM: beagleplay: cleanup board entry
        https://git.pengutronix.de/cgit/barebox/commit/?id=b4f14eebf1ec (link may not be stable)
[20/20] ARM: k3: Add k3-r5_defconfig
        https://git.pengutronix.de/cgit/barebox/commit/?id=49556447bca7 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 03:19:10 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 12:19:10 +0100
Subject: [PATCH 1/4] sandbox: make CC_HAS_LINUX_I386_SUPPORT depend on
 GCC
In-Reply-To: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
References: <20250217104611.1836442-1-a.fatoum@pengutronix.de>
Message-ID: <173979115074.1960646.7559186033947300422.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 11:46:08 +0100, Ahmad Fatoum wrote:
> CC_HAS_LINUX_I386_SUPPORT enables build for 32-bit with a 64-bit GCC
> toolchain. This seems not to work correctly on clang:
> 
>   CC      arch/sandbox/os/common.o
>   In file included from arch/sandbox/os/common.c:23:
>   In file included from /usr/lib/llvm-16/lib/clang/16/include/limits.h:21:
>   /usr/include/limits.h:26:10: fatal error:
>                                'bits/libc-header-start.h' file not found
>   #include <bits/libc-header-start.h>
> 
> [...]

Applied, thanks!

[1/4] sandbox: make CC_HAS_LINUX_I386_SUPPORT depend on GCC
      https://git.pengutronix.de/cgit/barebox/commit/?id=15af5003ba06 (link may not be stable)
[2/4] Makefile: clang: fix typo in -Wno-typdef-redefinition flag
      https://git.pengutronix.de/cgit/barebox/commit/?id=35309a815da3 (link may not be stable)
[3/4] kbuild: actually include Makefile.clang for clang builds
      https://git.pengutronix.de/cgit/barebox/commit/?id=c5370032370a (link may not be stable)
[4/4] Makefile: clang: fail non-sandbox LLVM builds early
      https://git.pengutronix.de/cgit/barebox/commit/?id=aaea175ad00f (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From a.fatoum at pengutronix.de  Mon Feb 17 03:33:55 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 12:33:55 +0100
Subject: [PATCH v2 2/2] mci: core: reset ERASE_GRP_DEF on startup
In-Reply-To: <20250217113355.2099178-1-a.fatoum@pengutronix.de>
References: <20250217113355.2099178-1-a.fatoum@pengutronix.de>
Message-ID: <20250217113355.2099178-2-a.fatoum@pengutronix.de>

EXT_CSD register EXT_CSD_ERASE_GROUP_DEF loses its value after power
cycles and needs to be reset. Quoting the eMMC 5.1 standard[1]:

  After every power-up, when the host uses a device that partition(s)
  are configured, it must set the ERASE_GROUP_DEF bit to high before
  issuing read, write, erase and write protect commands, because this
  bit is reset after power-up. Otherwise, these may not work correctly
  and it may leave the stored data in an unknown state.

[1]: JESD84-B51

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/mci/mci-core.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 13306d78dcfe..e6e23b566a44 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1218,11 +1218,24 @@ static void mci_extract_block_lengths_from_csd(struct mci *mci)
 }
 
 /**
- * Extract erase group size
+ * Configure erase group size
  * @param mci MCI instance
  */
-static void mci_extract_erase_group_size(struct mci *mci)
+static void mci_configure_erase_group_size(struct mci *mci)
 {
+	/* Enable ERASE_GRP_DEF. This bit is lost after a reset or power off.
+	 * This needs to happen even if we don't have erase support compiled-in.
+	 */
+	if (!IS_SD(mci) && mci->version >= MMC_VERSION_4_3) { 
+		int err;
+
+		err = mci_switch(mci, EXT_CSD_ERASE_GROUP_DEF, 1);
+		if (err)
+			dev_warn(&mci->dev, "failed erase group switch\n");
+		else
+			mci->ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+	}
+
 	if (!IS_ENABLED(CONFIG_MCI_ERASE) ||
 	    !(UNSTUFF_BITS(mci->csd, 84, 12) & CCC_ERASE))
 		return;
@@ -1954,7 +1967,7 @@ static int mci_startup(struct mci *mci)
 	dev_info(&mci->dev, "detected %s card version %s\n", IS_SD(mci) ? "SD" : "MMC",
 		mci_version_string(mci));
 	mci_extract_card_capacity_from_csd(mci);
-	mci_extract_erase_group_size(mci);
+	mci_configure_erase_group_size(mci);
 
 	if (IS_SD(mci))
 		err = mci_startup_sd(mci);
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 03:33:54 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 12:33:54 +0100
Subject: [PATCH v2 1/2] mci: core: import Linux logic for higher preferred erase size
Message-ID: <20250217113355.2099178-1-a.fatoum@pengutronix.de>

As a comment in the file notes, doing too small a granularity for erases
has considerable effect on performance:

  > Example Samsung eMMC 8GTF4:
  >
  >   time erase /dev/mmc2.part_of_512m # 1024 trims
  >   time: 2849ms
  >
  >   time erase /dev/mmc2.part_of_512m # single trim
  >   time: 56ms

This was deemed acceptable at first, because 3 seconds is still
tolerable.

On a SkyHigh S40004, an erase of the whole 3728 MiB ended up
taking longer than 400s in barebox, but only 4s in Linux, which
dwarfs the time actually needed for writing.

Linux has some rather complicated logic to compute a higher erase size
granularity, which still fits in the max busy timeout that a controller
may require. Until that's support in barebox, we import a simpler
heuristic that Linux uses to compute

  /sys/class/mmc_host/*/*/preferred_erase_size

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - replace wrong 11 bit right shift with more descriptive and correct
    division by SZ_1M (Sascha)
---
 drivers/mci/mci-core.c | 105 ++++++++++++++++++++++++++---------------
 include/mci.h          |   1 +
 2 files changed, 69 insertions(+), 37 deletions(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 7ec2643b8d7f..13306d78dcfe 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1774,6 +1774,70 @@ static int mci_startup_mmc(struct mci *mci)
 	return ret >= MMC_BUS_WIDTH_1 ? 0 : ret;
 }
 
+static void mci_init_erase(struct mci *card)
+{
+	if (!IS_ENABLED(CONFIG_MCI_ERASE))
+		return;
+
+	/* TODO: While it's possible to clear many erase groups at once
+	 * and it greatly improves throughput, drivers need adjustment:
+	 *
+	 * Many drivers hardcode a maximal wait time before aborting
+	 * the wait for R1b and returning -ETIMEDOUT. With long
+	 * erases/trims, we are bound to run into this timeout, so for now
+	 * we just split into sufficiently small erases that are unlikely
+	 * to trigger the timeout.
+	 *
+	 * What Linux does and what we should be doing in barebox is:
+	 *
+	 *  - add a struct mci_cmd::busy_timeout member that drivers should
+	 *    use instead of hardcoding their own timeout delay. The busy
+	 *    timeout length can be calculated by the MCI core after
+	 *    consulting the appropriate CSD/EXT_CSD/SSR registers.
+	 *
+	 *  - add a struct mci_host::max_busy_timeout member, where drivers
+	 *    can indicate the maximum timeout they are able to support.
+	 *    The MCI core will never set a busy_timeout that exceeds this
+	 *    value.
+	 *
+	 *  Example Samsung eMMC 8GTF4:
+	 *
+	 *    time erase /dev/mmc2.part_of_512m # 1024 trims
+	 *    time: 2849ms
+	 *
+	 *    time erase /dev/mmc2.part_of_512m # single trim
+	 *    time: 56ms
+	 */
+	if (IS_SD(card) && card->ssr.au) {
+		card->pref_erase = card->ssr.au;
+	} else if (card->erase_grp_size) {
+		unsigned int sz;
+
+		sz = card->capacity / SZ_1M;
+		if (sz < 128)
+			card->pref_erase = 512 * 1024 / 512;
+		else if (sz < 512)
+			card->pref_erase = 1024 * 1024 / 512;
+		else if (sz < 1024)
+			card->pref_erase = 2 * 1024 * 1024 / 512;
+		else
+			card->pref_erase = 4 * 1024 * 1024 / 512;
+		if (card->pref_erase < card->erase_grp_size)
+			card->pref_erase = card->erase_grp_size;
+		else {
+			sz = card->pref_erase % card->erase_grp_size;
+			if (sz)
+				card->pref_erase += card->erase_grp_size - sz;
+		}
+	} else {
+		card->pref_erase = 0;
+		return;
+	}
+
+	dev_add_param_uint32_fixed(&card->dev, "preferred_erase_size",
+				   card->pref_erase * 512, "%u");
+}
+
 /**
  * Scan the given host interfaces and detect connected MMC/SD cards
  * @param mci MCI instance
@@ -1903,6 +1967,8 @@ static int mci_startup(struct mci *mci)
 	/* we setup the blocklength only one times for all accesses to this media  */
 	err = mci_set_blocklen(mci, mci->read_bl_len);
 
+	mci_init_erase(mci);
+
 	mci_part_add(mci, mci->capacity, 0,
 			mci->cdevname, NULL, 0, true,
 			MMC_BLK_DATA_AREA_MAIN);
@@ -2080,7 +2146,7 @@ static int mci_sd_erase(struct block_device *blk, sector_t from,
 	struct mci *mci = part->mci;
 	sector_t i = 0;
 	unsigned arg;
-	sector_t blk_max, to = from + blkcnt;
+	sector_t to = from + blkcnt;
 	int rc;
 
 	mci_blk_part_switch(part);
@@ -2106,45 +2172,10 @@ static int mci_sd_erase(struct block_device *blk, sector_t from,
 	/* 'from' and 'to' are inclusive */
 	to -= 1;
 
-	/* TODO: While it's possible to clear many erase groups at once
-	 * and it greatly improves throughput, drivers need adjustment:
-	 *
-	 * Many drivers hardcode a maximal wait time before aborting
-	 * the wait for R1b and returning -ETIMEDOUT. With long
-	 * erases/trims, we are bound to run into this timeout, so for now
-	 * we just split into sufficiently small erases that are unlikely
-	 * to trigger the timeout.
-	 *
-	 * What Linux does and what we should be doing in barebox is:
-	 *
-	 *  - add a struct mci_cmd::busy_timeout member that drivers should
-	 *    use instead of hardcoding their own timeout delay. The busy
-	 *    timeout length can be calculated by the MCI core after
-	 *    consulting the appropriate CSD/EXT_CSD/SSR registers.
-	 *
-	 *  - add a struct mci_host::max_busy_timeout member, where drivers
-	 *    can indicate the maximum timeout they are able to support.
-	 *    The MCI core will never set a busy_timeout that exceeds this
-	 *    value.
-	 *
-	 *  Example Samsung eMMC 8GTF4:
-	 *
-	 *    time erase /dev/mmc2.part_of_512m # 1024 trims
-	 *    time: 2849ms
-	 *
-	 *    time erase /dev/mmc2.part_of_512m # single trim
-	 *    time: 56ms
-	 */
-
-	if (IS_SD(mci) && mci->ssr.au)
-		blk_max = mci->ssr.au;
-	else
-		blk_max = mci->erase_grp_size;
-
 	while (i < blkcnt) {
 		sector_t blk_r;
 
-		blk_r = min(blkcnt - i, blk_max);
+		blk_r = min_t(blkcnt_t, blkcnt - i, mci->pref_erase);
 
 		rc =  mci_block_erase(mci, from + i, blk_r, arg);
 		if (rc)
diff --git a/include/mci.h b/include/mci.h
index 1e3757027406..15fc0f22088f 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -647,6 +647,7 @@ struct mci {
 	/** currently used data block length for write accesses */
 	unsigned write_bl_len;
 	unsigned erase_grp_size;
+	unsigned pref_erase;	/**< preferred erase granularity in blocks */
 	uint64_t capacity;	/**< Card's data capacity in bytes */
 	int ready_for_use;	/** true if already probed */
 	int dsr_imp;		/**< DSR implementation state from CSD */
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 03:36:53 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 12:36:53 +0100
Subject: [PATCH 1/2] mci: core: import Linux logic for higher preferred
 erase size
In-Reply-To: <Z7MVNjkJiDazmLpc@pengutronix.de>
References: <20250214094850.2847143-1-a.fatoum@pengutronix.de>
 <Z7MVNjkJiDazmLpc@pengutronix.de>
Message-ID: <6d8c8fb9-128b-475b-9ae1-7dc5d943b22e@pengutronix.de>

Hello Sascha,

On 17.02.25 11:53, Sascha Hauer wrote:
> On Fri, Feb 14, 2025 at 10:48:49AM +0100, Ahmad Fatoum wrote:
>> As a comment in the file notes, doing too small a granularity for erases
>> has considerable effect on performance:
>>
>>   > Example Samsung eMMC 8GTF4:
>>   >
>>   >   time erase /dev/mmc2.part_of_512m # 1024 trims
>>   >   time: 2849ms
>>   >
>>   >   time erase /dev/mmc2.part_of_512m # single trim
>>   >   time: 56ms
>>
>> This was deemed acceptable at first, because 3 seconds is still
>> tolerable.
>>
>> On a SkyHigh S40004, an erase of the whole 3728 MiB ended up
>> taking longer than 400s in barebox, but only 4s in Linux, which
>> dwarfs the time actually needed for writing.
>>
>> Linux has some rather complicated logic to compute a higher erase size
>> granularity, which still fits in the max busy timeout that a controller
>> may require. Until that's support in barebox, we import a simpler
>> heuristic that Linux uses to compute
>>
>>   /sys/class/mmc_host/*/*/preferred_erase_size
>>
>> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
>> ---
>>  drivers/mci/mci-core.c | 105 ++++++++++++++++++++++++++---------------
>>  include/mci.h          |   1 +
>>  2 files changed, 69 insertions(+), 37 deletions(-)
>>
>> diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
>> index cc3c6fba3653..6d55eb8305b9 100644
>> --- a/drivers/mci/mci-core.c
>> +++ b/drivers/mci/mci-core.c
>> @@ -1774,6 +1774,70 @@ static int mci_startup_mmc(struct mci *mci)
>>  	return ret >= MMC_BUS_WIDTH_1 ? 0 : ret;
>>  }
>>  
>> +static void mci_init_erase(struct mci *card)
>> +{
>> +	unsigned int sz;
>> +
>> +	if (!IS_ENABLED(CONFIG_MCI_ERASE))
>> +		return;
>> +
>> +	/* TODO: While it's possible to clear many erase groups at once
>> +	 * and it greatly improves throughput, drivers need adjustment:
>> +	 *
>> +	 * Many drivers hardcode a maximal wait time before aborting
>> +	 * the wait for R1b and returning -ETIMEDOUT. With long
>> +	 * erases/trims, we are bound to run into this timeout, so for now
>> +	 * we just split into sufficiently small erases that are unlikely
>> +	 * to trigger the timeout.
>> +	 *
>> +	 * What Linux does and what we should be doing in barebox is:
>> +	 *
>> +	 *  - add a struct mci_cmd::busy_timeout member that drivers should
>> +	 *    use instead of hardcoding their own timeout delay. The busy
>> +	 *    timeout length can be calculated by the MCI core after
>> +	 *    consulting the appropriate CSD/EXT_CSD/SSR registers.
>> +	 *
>> +	 *  - add a struct mci_host::max_busy_timeout member, where drivers
>> +	 *    can indicate the maximum timeout they are able to support.
>> +	 *    The MCI core will never set a busy_timeout that exceeds this
>> +	 *    value.
>> +	 *
>> +	 *  Example Samsung eMMC 8GTF4:
>> +	 *
>> +	 *    time erase /dev/mmc2.part_of_512m # 1024 trims
>> +	 *    time: 2849ms
>> +	 *
>> +	 *    time erase /dev/mmc2.part_of_512m # single trim
>> +	 *    time: 56ms
>> +	 */
>> +	if (IS_SD(card) && card->ssr.au) {
>> +		card->pref_erase = card->ssr.au;
>> +	} else if (card->erase_grp_size) {
>> +		sz = card->capacity >> 11;
>> +		if (sz < 128)
>> +			card->pref_erase = 512 * 1024 / 512;
>> +		else if (sz < 512)
>> +			card->pref_erase = 1024 * 1024 / 512;
>> +		else if (sz < 1024)
>> +			card->pref_erase = 2 * 1024 * 1024 / 512;
>> +		else
>> +			card->pref_erase = 4 * 1024 * 1024 / 512;
> 
> card->capacity is in bytes, so you are falling into the last case for
> cards bigger than 512Kib. Did you mean to right shift by 21 or even 31
> instead?

Yes, this was indeed wrong. csd.capacity in Linux is in units of sectors.

(x / SECTOR_SHIFT) >> 11 -> x / SZ_1M.

I fixed that in v2.

> I would prefer using SZ_* and SECTOR_SIZE/SHIFT defines to make this more
> readable.

I'd prefer to keep the rest as-is as it's a verbatim copy from Linux
mmc_init_erase() in drivers/mmc/core/core.c.

Thanks,
Ahmad

> 
> Sascha
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Mon Feb 17 03:58:01 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 12:58:01 +0100
Subject: [PATCH v2 1/2] mci: core: import Linux logic for higher
 preferred erase size
In-Reply-To: <20250217113355.2099178-1-a.fatoum@pengutronix.de>
References: <20250217113355.2099178-1-a.fatoum@pengutronix.de>
Message-ID: <173979348166.2688784.6728682678487701.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 12:33:54 +0100, Ahmad Fatoum wrote:
> As a comment in the file notes, doing too small a granularity for erases
> has considerable effect on performance:
> 
>   > Example Samsung eMMC 8GTF4:
>   >
>   >   time erase /dev/mmc2.part_of_512m # 1024 trims
>   >   time: 2849ms
>   >
>   >   time erase /dev/mmc2.part_of_512m # single trim
>   >   time: 56ms
> 
> [...]

Applied, thanks!

[1/2] mci: core: import Linux logic for higher preferred erase size
      https://git.pengutronix.de/cgit/barebox/commit/?id=cffa32cbd510 (link may not be stable)
[2/2] mci: core: reset ERASE_GRP_DEF on startup
      https://git.pengutronix.de/cgit/barebox/commit/?id=b2c8b27dd73d (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Mon Feb 17 04:25:38 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 13:25:38 +0100
Subject: [PATCH 2/2] fip: add function to parse FIP from a buffer
In-Reply-To: <20250217122538.3216703-1-s.hauer@pengutronix.de>
References: <20250217122538.3216703-1-s.hauer@pengutronix.de>
Message-ID: <20250217122538.3216703-2-s.hauer@pengutronix.de>

So far we can only parse a FIP image from a file. Provide fip_parse_buf()
to open a FIP image from a buffer.
The bulk of fip_parse() can be re-used for that. While at it use
read_file_2() to read in the FIP image.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 include/fiptool.h |  4 +++
 lib/fip.c         | 92 ++++++++++++++++++++++++++---------------------
 2 files changed, 56 insertions(+), 40 deletions(-)

diff --git a/include/fiptool.h b/include/fiptool.h
index bc42f7edd6..bb63a79c16 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -38,6 +38,7 @@ struct fip_state {
 	size_t nr_image_descs;
 	int verbose;
 	void *buffer;
+	bool buf_no_free;
 };
 
 #define pr_verbose(...) do { \
@@ -68,6 +69,9 @@ struct fip_image_desc *fip_lookup_image_desc_from_uuid(struct fip_state *fip,
 
 struct fip_image_desc *fip_lookup_image_desc_from_opt(struct fip_state *fip, char **arg);
 
+int fip_parse_buf(struct fip_state *fip, void *buf, size_t size,
+		  fip_toc_header_t *toc_header_out);
+
 int fip_parse(struct fip_state *fip,
 		     const char *filename, fip_toc_header_t *toc_header_out);
 
diff --git a/lib/fip.c b/lib/fip.c
index 806f172318..23e82098da 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <libfile.h>
+#include <fs.h>
 
 #include <fip.h>
 #include <fiptool.h>
@@ -93,7 +94,9 @@ void fip_free(struct fip_state *fip)
 
 	ASSERT(fip->nr_image_descs == 0);
 
-	free(fip->buffer);
+	if (!fip->buf_no_free)
+		free(fip->buffer);
+
 	free(fip);
 }
 
@@ -155,44 +158,20 @@ struct fip_image_desc *fip_lookup_image_desc_from_opt(struct fip_state *fip, cha
 	return NULL;
 }
 
-int fip_parse(struct fip_state *fip,
-		     const char *filename, fip_toc_header_t *toc_header_out)
+static int fip_do_parse_buf(struct fip_state *fip, void *buf, size_t size,
+			    fip_toc_header_t *toc_header_out)
 {
-	struct stat st;
-	int fd;
 	char *bufend;
 	fip_toc_header_t *toc_header;
 	fip_toc_entry_t *toc_entry;
 	int terminated = 0;
-	size_t st_size;
-
-	if (fip->buffer)
-		return -EBUSY;
-
-	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		pr_err("open %s: %m\n", filename);
-		return -errno;
-	}
-
-	if (fstat(fd, &st) == -1) {
-		pr_err("fstat %s: %m\n", filename);
-		return -errno;
-	}
-
-	st_size = st.st_size;
 
-	fip->buffer = xmalloc(st_size);
-	if (read_full(fd, fip->buffer, st_size) != st_size) {
-		pr_err("Failed to read %s: %m\n", filename);
-		return -errno;
-	}
+	fip->buffer = buf;
 
-	bufend = fip->buffer + st_size;
-	close(fd);
+	bufend = fip->buffer + size;
 
-	if (st_size < sizeof(fip_toc_header_t)) {
-		pr_err("FIP %s is truncated\n", filename);
+	if (size < sizeof(fip_toc_header_t)) {
+		pr_err("FIP is truncated\n");
 		return -ENODATA;
 	}
 
@@ -200,8 +179,8 @@ int fip_parse(struct fip_state *fip,
 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
 
 	if (toc_header->name != TOC_HEADER_NAME) {
-		pr_err("%s is not a FIP file: unknown magic = 0x%08x\n",
-		       filename, toc_header->name);
+		pr_err("not a FIP file: unknown magic = 0x%08x\n",
+		       toc_header->name);
 		return -EINVAL;
 	}
 
@@ -230,13 +209,12 @@ int fip_parse(struct fip_state *fip,
 		image->buf_no_free = true;
 		/* Overflow checks before memory copy. */
 		if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) {
-			pr_err("FIP %s is corrupted: entry size exceeds 64 bit address space\n",
-			       filename);
+			pr_err("FIP is corrupted: entry size exceeds 64 bit address space\n");
 			return -EINVAL;
 		}
-		if (toc_entry->size + toc_entry->offset_address > st_size) {
-			pr_err("FIP %s is corrupted: entry size (0x%llx) exceeds FIP file size (0x%zx)\n",
-				filename, toc_entry->size + toc_entry->offset_address, st_size);
+		if (toc_entry->size + toc_entry->offset_address > size) {
+			pr_err("FIP is corrupted: entry size (0x%llx) exceeds FIP file size (0x%zx)\n",
+				toc_entry->size + toc_entry->offset_address, size);
 			return -EINVAL;
 		}
 
@@ -261,14 +239,48 @@ int fip_parse(struct fip_state *fip,
 	}
 
 	if (terminated == 0) {
-		pr_err("FIP %s does not have a ToC terminator entry\n",
-		    filename);
+		pr_err("FIP does not have a ToC terminator entry\n");
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
+int fip_parse_buf(struct fip_state *fip, void *buf, size_t size,
+			    fip_toc_header_t *toc_header_out)
+{
+	if (fip->buffer)
+		return -EBUSY;
+
+	fip->buf_no_free = true;
+
+	return fip_do_parse_buf(fip, buf, size, toc_header_out);
+}
+
+int fip_parse(struct fip_state *fip,
+		     const char *filename, fip_toc_header_t *toc_header_out)
+{
+	size_t size;
+	int ret;
+	void *buf;
+
+	if (fip->buffer)
+		return -EBUSY;
+
+	ret = read_file_2(filename, &size, &buf, FILESIZE_MAX);
+	if (ret) {
+		pr_err("open %s: %m\n", filename);
+		return ret;
+	}
+
+	ret = fip_parse_buf(fip, buf, size, toc_header_out);
+
+	if (ret)
+		free(buf);
+
+	return ret;
+}
+
 static struct fip_image *fip_read_image_from_file(const uuid_t *uuid, const char *filename)
 {
 	struct stat st;
-- 
2.39.5



From s.hauer at pengutronix.de  Mon Feb 17 04:25:37 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 13:25:37 +0100
Subject: [PATCH 1/2] fip: Store image data in single buffer
Message-ID: <20250217122538.3216703-1-s.hauer@pengutronix.de>

Right now in fip_parse() we read the whole FIP image into an allocated
buffer, then allocate buffers for the different blobs contained in the
FIP image and memcpy the blobs there from the full buffer. Let's
optimize this a bit by keeping the full buffer. Instead of allocating
separate buffers for the blobs, just put pointers to the full buffers
into struct fip_image and set the buf_no_free flag indicating that they
should not be freed.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 lib/fip.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/lib/fip.c b/lib/fip.c
index 39b0fd20aa..806f172318 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -160,12 +160,15 @@ int fip_parse(struct fip_state *fip,
 {
 	struct stat st;
 	int fd;
-	char *buf, *bufend;
+	char *bufend;
 	fip_toc_header_t *toc_header;
 	fip_toc_entry_t *toc_entry;
 	int terminated = 0;
 	size_t st_size;
 
+	if (fip->buffer)
+		return -EBUSY;
+
 	fd = open(filename, O_RDONLY);
 	if (fd < 0) {
 		pr_err("open %s: %m\n", filename);
@@ -179,13 +182,13 @@ int fip_parse(struct fip_state *fip,
 
 	st_size = st.st_size;
 
-	buf = xmalloc(st_size);
-	if (read_full(fd, buf, st_size) != st_size) {
+	fip->buffer = xmalloc(st_size);
+	if (read_full(fd, fip->buffer, st_size) != st_size) {
 		pr_err("Failed to read %s: %m\n", filename);
 		return -errno;
 	}
 
-	bufend = buf + st_size;
+	bufend = fip->buffer + st_size;
 	close(fd);
 
 	if (st_size < sizeof(fip_toc_header_t)) {
@@ -193,7 +196,7 @@ int fip_parse(struct fip_state *fip,
 		return -ENODATA;
 	}
 
-	toc_header = (fip_toc_header_t *)buf;
+	toc_header = (fip_toc_header_t *)fip->buffer;
 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
 
 	if (toc_header->name != TOC_HEADER_NAME) {
@@ -223,7 +226,8 @@ int fip_parse(struct fip_state *fip,
 		 */
 		image = xzalloc(sizeof(*image));
 		image->toc_e = *toc_entry;
-		image->buffer = xmalloc(toc_entry->size);
+		image->buffer = fip->buffer + toc_entry->offset_address;
+		image->buf_no_free = true;
 		/* Overflow checks before memory copy. */
 		if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) {
 			pr_err("FIP %s is corrupted: entry size exceeds 64 bit address space\n",
@@ -236,9 +240,6 @@ int fip_parse(struct fip_state *fip,
 			return -EINVAL;
 		}
 
-		memcpy(image->buffer, buf + toc_entry->offset_address,
-		    toc_entry->size);
-
 		/* If this is an unknown image, create a descriptor for it. */
 		desc = fip_lookup_image_desc_from_uuid(fip, &toc_entry->uuid);
 		if (desc == NULL) {
@@ -264,7 +265,7 @@ int fip_parse(struct fip_state *fip,
 		    filename);
 		return -EINVAL;
 	}
-	free(buf);
+
 	return 0;
 }
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 06:34:16 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 15:34:16 +0100
Subject: [PATCH] usb: dwc3: add am62 support
In-Reply-To: <20250108153216.484573-1-s.hauer@pengutronix.de>
References: <20250108153216.484573-1-s.hauer@pengutronix.de>
Message-ID: <a06cfea0-5584-4173-ae9b-aafa2f5d0142@pengutronix.de>

Hello Sascha,

On 08.01.25 16:32, Sascha Hauer wrote:
> This adds the glue code necessary for the DWC3 controller on TI AM62x
> SoCs. The code is based on the corresponding Linux driver as of
> Linux-6.13-rc1.
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>

Sorry for the late review, but I have a question.

> +	/* Calculate the rate code */
> +	rate = clk_get_rate(am62->usb2_refclk);
> +	rate /= 1000;	// To KHz

Nitpick: We have HZ_PER_KHZ, which would save you a comment.

> +	ret = of_platform_populate(node, NULL, dev);
> +	if (ret) {
> +		dev_err_probe(dev, ret, "failed to create dwc3 core\n");
> +		goto err_pm_disable;
> +	}
> +
> +	/* Set mode valid bit to indicate role is valid */
> +	reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
> +	reg |= USBSS_MODE_VALID;
> +	dwc3_ti_writel(am62, USBSS_MODE_CONTROL, reg);

It's odd to do this after of_platform_populate. A deep probe
system would always try to initialize DWC3 without this
set, wouldn't it?

Cheers,
Ahmad

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Mon Feb 17 06:45:42 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 15:45:42 +0100
Subject: [PATCH 1/2] usb: dwc3: am62: Use HZ_PER_KHZ
Message-ID: <20250217144543.1777605-1-s.hauer@pengutronix.de>

Use HZ_PER_KHZ to make intention clear and drop now unnecessary comment.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/usb/dwc3/dwc3-am62.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c
index fd7f5e54d2..7dac8981fb 100644
--- a/drivers/usb/dwc3/dwc3-am62.c
+++ b/drivers/usb/dwc3/dwc3-am62.c
@@ -203,7 +203,7 @@ static int dwc3_ti_probe(struct device *dev)
 
 	/* Calculate the rate code */
 	rate = clk_get_rate(am62->usb2_refclk);
-	rate /= 1000;	// To KHz
+	rate /= HZ_PER_KHZ;
 	for (i = 0; i < ARRAY_SIZE(dwc3_ti_rate_table); i++) {
 		if (dwc3_ti_rate_table[i] == rate)
 			break;
-- 
2.39.5



From s.hauer at pengutronix.de  Mon Feb 17 06:45:43 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 15:45:43 +0100
Subject: [PATCH 2/2] usb: dwc3: am62: set mode valid bit before probing children
In-Reply-To: <20250217144543.1777605-1-s.hauer@pengutronix.de>
References: <20250217144543.1777605-1-s.hauer@pengutronix.de>
Message-ID: <20250217144543.1777605-2-s.hauer@pengutronix.de>

We should fully configure the desired register settings before calling
of_platform_populate() to make sure they actually have an effect.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/usb/dwc3/dwc3-am62.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c
index 7dac8981fb..848549fbf6 100644
--- a/drivers/usb/dwc3/dwc3-am62.c
+++ b/drivers/usb/dwc3/dwc3-am62.c
@@ -240,17 +240,17 @@ static int dwc3_ti_probe(struct device *dev)
 
 	clk_prepare_enable(am62->usb2_refclk);
 
+	/* Set mode valid bit to indicate role is valid */
+	reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
+	reg |= USBSS_MODE_VALID;
+	dwc3_ti_writel(am62, USBSS_MODE_CONTROL, reg);
+
 	ret = of_platform_populate(node, NULL, dev);
 	if (ret) {
 		dev_err_probe(dev, ret, "failed to create dwc3 core\n");
 		goto err_pm_disable;
 	}
 
-	/* Set mode valid bit to indicate role is valid */
-	reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
-	reg |= USBSS_MODE_VALID;
-	dwc3_ti_writel(am62, USBSS_MODE_CONTROL, reg);
-
 	return 0;
 
 err_pm_disable:
-- 
2.39.5



From s.hauer at pengutronix.de  Mon Feb 17 06:46:22 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 17 Feb 2025 15:46:22 +0100
Subject: [PATCH] usb: dwc3: add am62 support
In-Reply-To: <a06cfea0-5584-4173-ae9b-aafa2f5d0142@pengutronix.de>
References: <20250108153216.484573-1-s.hauer@pengutronix.de>
 <a06cfea0-5584-4173-ae9b-aafa2f5d0142@pengutronix.de>
Message-ID: <Z7NLvn7piJFNmuqz@pengutronix.de>

On Mon, Feb 17, 2025 at 03:34:16PM +0100, Ahmad Fatoum wrote:
> Hello Sascha,
> 
> On 08.01.25 16:32, Sascha Hauer wrote:
> > This adds the glue code necessary for the DWC3 controller on TI AM62x
> > SoCs. The code is based on the corresponding Linux driver as of
> > Linux-6.13-rc1.
> > 
> > Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> 
> Sorry for the late review, but I have a question.
> 
> > +	/* Calculate the rate code */
> > +	rate = clk_get_rate(am62->usb2_refclk);
> > +	rate /= 1000;	// To KHz
> 
> Nitpick: We have HZ_PER_KHZ, which would save you a comment.
> 
> > +	ret = of_platform_populate(node, NULL, dev);
> > +	if (ret) {
> > +		dev_err_probe(dev, ret, "failed to create dwc3 core\n");
> > +		goto err_pm_disable;
> > +	}
> > +
> > +	/* Set mode valid bit to indicate role is valid */
> > +	reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
> > +	reg |= USBSS_MODE_VALID;
> > +	dwc3_ti_writel(am62, USBSS_MODE_CONTROL, reg);
> 
> It's odd to do this after of_platform_populate. A deep probe
> system would always try to initialize DWC3 without this
> set, wouldn't it?

Copied from the Kernel driver. But right, I just sent a patch to change
it.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Mon Feb 17 10:08:27 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:08:27 +0100
Subject: [PATCH 0/6] of: partition: add Linux CONFIG_OF_PARTITION-compatible adaptive fixup mode
Message-ID: <20250217180833.3955657-1-a.fatoum@pengutronix.de>

barebox has for many years supported a superset of the upstream OF
partitions binding by parsing partitions out of SD/eMMC and EEPROM
in addition to MTD.

Unfortunately, we didn't upstream our binding and a different binding
went upstream into Linux v6.13-rc1 along with Linux commit
2e3a191e89f9 ("block: add support for partition table defined in OF").

Since then, if CONFIG_OF_PARTITION, which is disabled by default, is
enabled, Linux will ignore any GPT/MBR if an SD/eMMC node has a
fixed-partitions compatible subnode.

This is different from the barebox behavior, which allows both OF
partitions and GPT/MBR to co-exist as long as they don't conflict.

As many barebox boards:

  - Place the environment in non-partitioned space prior to the first
    partition

  - Fixup all fixed-partitions into the kernel device tree by default

this can result in breakage if a newer kernel is booted with
CONFIG_OF_PARTITION enabled.

To resolve this, this series introduces the barebox,fixed-partitions
compatible and uses that in Linux device tree fixups for SD/eMMC
by default.

Ahmad Fatoum (6):
  of: factor out of_node_is_fixed_partitions check
  of: of_path: support barebox,fixed-partitions
  ARM: IMX8MP: var-dart-dt8mcustomboard.dts: use new-style partition
    binding
  ARM: dts: prefix all non-MTD fixed-partitions with barebox,
  of: partition: refactor of_partition_binding checks into switch
  of: partition: add Linux CONFIG_OF_PARTITION-compatible adaptive fixup
    mode

 .../devicetree/bindings/mtd/partition.rst     | 27 +++++++-
 Documentation/user/state.rst                  |  4 +-
 arch/arm/dts/am335x-phytec-state.dtsi         |  2 +-
 .../dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts  |  2 +-
 arch/arm/dts/imx50-kindle-common.dtsi         |  2 +-
 arch/arm/dts/imx51-zii-rdu1.dts               |  2 +-
 arch/arm/dts/imx6dl-colibri-iris.dts          |  2 +-
 arch/arm/dts/imx6qdl-phytec-mira.dtsi         |  2 +-
 arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi  |  2 +-
 arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi  |  2 +-
 arch/arm/dts/imx6qdl-phytec-state.dtsi        |  2 +-
 arch/arm/dts/imx6qdl-zii-rdu2.dtsi            |  2 +-
 arch/arm/dts/imx6ul-liteboard.dts             |  4 +-
 arch/arm/dts/imx6ul-phytec-state.dtsi         |  2 +-
 arch/arm/dts/imx6ul-tqma6ul-common.dtsi       |  4 +-
 arch/arm/dts/imx6ul-webasto-ccbv2.dts         |  2 +-
 arch/arm/dts/imx6ul-webasto-marvel.dts        |  2 +-
 arch/arm/dts/imx7d-ac-sxb.dtsi                |  4 +-
 arch/arm/dts/imx7d-flex-concentrator-mfg.dts  |  2 +-
 arch/arm/dts/imx7d-gome-e143_01.dts           |  2 +-
 arch/arm/dts/imx7d-phyboard-zeta.dts          |  2 +-
 arch/arm/dts/imx7s-warp.dts                   |  2 +-
 arch/arm/dts/imx8mm-innocomm-wb15-evk.dts     |  4 +-
 arch/arm/dts/imx8mm-phyboard-polis-rdk.dts    |  4 +-
 arch/arm/dts/imx8mp-debix-model-a.dts         |  4 +-
 arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts    |  4 +-
 arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi       |  2 +-
 .../dts/imx8mp-var-dart-dt8mcustomboard.dts   | 25 ++++----
 arch/arm/dts/rk3566-cm3-io.dts                |  4 +-
 arch/arm/dts/rk3566-pinetab2.dtsi             |  4 +-
 arch/arm/dts/rk3568-bpi-r2-pro.dts            |  4 +-
 arch/arm/dts/rk3568-evb1-v10.dts              |  4 +-
 arch/arm/dts/rk3568-mecsbc.dts                |  4 +-
 arch/arm/dts/rk3568-rock-3a.dts               |  4 +-
 arch/arm/dts/rk3568-wolfvision-pf5.dts        |  2 +-
 arch/arm/dts/rk3588-orangepi-5-plus.dts       |  4 +-
 arch/arm/dts/rk3588-rock-5b.dts               |  4 +-
 arch/arm/dts/socfpga_arria10_achilles.dts     |  2 +-
 arch/arm/dts/socfpga_arria10_mercury_aa1.dts  |  2 +-
 arch/arm/dts/state-example.dtsi               |  4 +-
 drivers/of/base.c                             |  6 +-
 drivers/of/of_path.c                          |  9 ++-
 drivers/of/partition.c                        | 62 ++++++++++++-------
 include/of.h                                  |  6 ++
 44 files changed, 149 insertions(+), 96 deletions(-)

-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:08:29 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:08:29 +0100
Subject: [PATCH 2/6] of: of_path: support barebox,fixed-partitions
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180833.3955657-3-a.fatoum@pengutronix.de>

barebox has for many years supported a superset of the upstream OF
partitions binding by parsing partitions out of SD/eMMC and EEPROM
in addition to MTD.

Unfortunately, we didn't upstream our binding and a different binding
went upstream into Linux v6.13-rc1 along with Linux commit
2e3a191e89f9 ("block: add support for partition table defined in OF").

Since then, if CONFIG_OF_PARTITION, which is disabled by default, is
enabled, Linux will ignore any GPT/MBR if an SD/eMMC node has a
fixed-partitions compatible subnode.

This is different from the barebox behavior, which allows both OF
partitions and GPT/MBR to co-exist as long as they don't conflict.

As many barebox boards:

  - Place the environment in non-partitioned space prior to the first
    partition

  - Fixup all fixed-partitions into the kernel device tree by default

this results in breakage if a newer kernel is booted with
CONFIG_OF_PARTITION enabled.

As first step towards resolving this, teach barebox to parse
barebox,fixed-partitions the same way it parses fixed-partitions.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/of/of_path.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c
index b3feaa07e39d..57bd82a741ba 100644
--- a/drivers/of/of_path.c
+++ b/drivers/of/of_path.c
@@ -14,7 +14,9 @@
 
 bool of_node_is_fixed_partitions(const struct device_node *np)
 {
-	return of_device_is_compatible(np, "fixed-partitions");
+	return of_device_is_compatible(np, "fixed-partitions") ||
+		of_device_is_compatible(np, "barebox,fixed-partitions");
+
 }
 
 struct device *of_find_device_by_node_path(const char *path)
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:08:30 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:08:30 +0100
Subject: [PATCH 3/6] ARM: IMX8MP: var-dart-dt8mcustomboard.dts: use new-style partition binding
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180833.3955657-4-a.fatoum@pengutronix.de>

The fixed-partitions compatible is meant to be used for the partitions
container holding the individual partitions and not for every individual
partition.

This didn't lead to problems so far, because barebox ignored the
compatible and parsed them as legacy partitions.

Resolve the confusion by changing the description to use the new-style
binding correctly.

While at it, we also drop some leading zeroes for readability's sake.

Cc: Michael Kopfensteiner <michael.kopfensteiner at vahle.com>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 .../dts/imx8mp-var-dart-dt8mcustomboard.dts   | 23 ++++++++++---------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts b/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts
index ab4c5790cf15..f11218c904f5 100644
--- a/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts
+++ b/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts
@@ -356,9 +356,6 @@ &usb_dwc3_1 {
 };
 
 &usdhc2 {
-	#address-cells = <2>;
-	#size-cells = <1>;
-
 	pinctrl-names = "default", "state_100mhz", "state_200mhz";
 	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
 	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
@@ -368,16 +365,20 @@ &usdhc2 {
 	bus-width = <4>;
 	status = "okay";
 
-	partition at 0 {
+	partitions {
 		compatible = "fixed-partitions";
-		label = "barebox";
-		reg = <0x00000000 0x00000000 0x000e0000>;
-	};
+		#size-cells = <2>;
+		#address-cells = <1>;
 
-	env_sd: partition at e0000 {
-		compatible = "fixed-partitions";
-		label = "barebox-environment";
-		reg = <0x00000000 0x000e0000 0x00020000>;
+		partition at 0 {
+			label = "barebox";
+			reg = <0x0 0x0 0xe0000>;
+		};
+
+		env_sd: partition at e0000 {
+			label = "barebox-environment";
+			reg = <0x0 0xe0000 0x20000>;
+		};
 	};
 };
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:08:32 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:08:32 +0100
Subject: [PATCH 5/6] of: partition: refactor of_partition_binding checks into switch
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180833.3955657-6-a.fatoum@pengutronix.de>

We are going to add a new fixup mode to enum of_binding_name in the next
commit. For readability's sake, refactor the existing code to make it
easier to extend.

No functional change.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/of/partition.c | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/drivers/of/partition.c b/drivers/of/partition.c
index 4f966d900f1f..fa4847e20a2b 100644
--- a/drivers/of/partition.c
+++ b/drivers/of/partition.c
@@ -18,6 +18,14 @@
 
 static unsigned int of_partition_binding;
 
+/**
+ * enum of_binding_name - Name of binding to use for OF partition fixup
+ * @MTD_OF_BINDING_NEW:		Fix up new-style partition bindings
+ *				with compatible = "fixed-partitions" container
+ * @MTD_OF_BINDING_LEGACY:	Fix up legacy partition bindings
+ *				directly into the parent node without container
+ * @MTD_OF_BINDING_DONTTOUCH:	Don't touch partition nodes at all - no fixups
+ */
 enum of_binding_name {
 	MTD_OF_BINDING_NEW,
 	MTD_OF_BINDING_LEGACY,
@@ -185,28 +193,26 @@ int of_fixup_partitions(struct device_node *np, struct cdev *cdev)
 		n_cells = 1;
 
 	partnode = of_get_child_by_name(np, "partitions");
-	if (partnode) {
-		if (of_partition_binding == MTD_OF_BINDING_LEGACY) {
-			of_delete_node(partnode);
-			partnode = np;
-		}
-		delete_subnodes(partnode);
-	} else {
-		delete_subnodes(np);
 
-		if (of_partition_binding == MTD_OF_BINDING_LEGACY)
-			partnode = np;
-		else
-			partnode = of_new_node(np, "partitions");
-	}
-
-	if (of_partition_binding == MTD_OF_BINDING_NEW) {
+	switch (of_partition_binding) {
+	case MTD_OF_BINDING_LEGACY:
+		of_delete_node(partnode);
+		partnode = np;
+		break;
+	case MTD_OF_BINDING_NEW:
+		partnode = partnode ?: of_new_node(np, "partitions");
 		ret = of_property_write_string(partnode, "compatible",
 					       "fixed-partitions");
 		if (ret)
 			return ret;
+		break;
 	}
 
+	if (partnode)
+		delete_subnodes(partnode);
+	else
+		delete_subnodes(np);
+
 	ret = of_property_write_u32(partnode, "#size-cells", n_cells);
 	if (ret)
 		return ret;
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:08:31 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:08:31 +0100
Subject: [PATCH 4/6] ARM: dts: prefix all non-MTD fixed-partitions with barebox,
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180833.3955657-5-a.fatoum@pengutronix.de>

While it's generally advisable to boot Linux with a Linux device tree
from the same release, barebox device trees should nevertheless be
usable to boot Linux.

For many barebox device trees, this was no longer the case since Linux
v6.13-rc1 with CONFIG_OF_PARTITION enabled, as Linux commit 2e3a191e89f9
("block: add support for partition table defined in OF") will result
in Linux ignoring the GPT/MBR if fixed-partitions are specified.

To resolve this, replace all fixed-partitions we have for SD/MMC and
EEPROMs devices with barebox,fixed-partitions instead.

Changes to the EEPROM nodes could've been omitted, but they are included
anyway as partitioning EEPROMs isn't supported by Linux upstream and to
anticipate any breakage that may result if a different binding goes
upstream first.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Documentation/user/state.rst                      | 4 ++--
 arch/arm/dts/am335x-phytec-state.dtsi             | 2 +-
 arch/arm/dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts | 2 +-
 arch/arm/dts/imx50-kindle-common.dtsi             | 2 +-
 arch/arm/dts/imx51-zii-rdu1.dts                   | 2 +-
 arch/arm/dts/imx6dl-colibri-iris.dts              | 2 +-
 arch/arm/dts/imx6qdl-phytec-mira.dtsi             | 2 +-
 arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi      | 2 +-
 arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi      | 2 +-
 arch/arm/dts/imx6qdl-phytec-state.dtsi            | 2 +-
 arch/arm/dts/imx6qdl-zii-rdu2.dtsi                | 2 +-
 arch/arm/dts/imx6ul-liteboard.dts                 | 4 ++--
 arch/arm/dts/imx6ul-phytec-state.dtsi             | 2 +-
 arch/arm/dts/imx6ul-tqma6ul-common.dtsi           | 4 ++--
 arch/arm/dts/imx6ul-webasto-ccbv2.dts             | 2 +-
 arch/arm/dts/imx6ul-webasto-marvel.dts            | 2 +-
 arch/arm/dts/imx7d-ac-sxb.dtsi                    | 4 ++--
 arch/arm/dts/imx7d-flex-concentrator-mfg.dts      | 2 +-
 arch/arm/dts/imx7d-gome-e143_01.dts               | 2 +-
 arch/arm/dts/imx7d-phyboard-zeta.dts              | 2 +-
 arch/arm/dts/imx7s-warp.dts                       | 2 +-
 arch/arm/dts/imx8mm-innocomm-wb15-evk.dts         | 4 ++--
 arch/arm/dts/imx8mm-phyboard-polis-rdk.dts        | 4 ++--
 arch/arm/dts/imx8mp-debix-model-a.dts             | 4 ++--
 arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts        | 4 ++--
 arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi           | 2 +-
 arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts  | 2 +-
 arch/arm/dts/rk3566-cm3-io.dts                    | 4 ++--
 arch/arm/dts/rk3566-pinetab2.dtsi                 | 4 ++--
 arch/arm/dts/rk3568-bpi-r2-pro.dts                | 4 ++--
 arch/arm/dts/rk3568-evb1-v10.dts                  | 4 ++--
 arch/arm/dts/rk3568-mecsbc.dts                    | 4 ++--
 arch/arm/dts/rk3568-rock-3a.dts                   | 4 ++--
 arch/arm/dts/rk3568-wolfvision-pf5.dts            | 2 +-
 arch/arm/dts/rk3588-orangepi-5-plus.dts           | 4 ++--
 arch/arm/dts/rk3588-rock-5b.dts                   | 4 ++--
 arch/arm/dts/socfpga_arria10_achilles.dts         | 2 +-
 arch/arm/dts/socfpga_arria10_mercury_aa1.dts      | 2 +-
 arch/arm/dts/state-example.dtsi                   | 4 ++--
 39 files changed, 56 insertions(+), 56 deletions(-)

diff --git a/Documentation/user/state.rst b/Documentation/user/state.rst
index 75352302c7ff..d97ba4e9f157 100644
--- a/Documentation/user/state.rst
+++ b/Documentation/user/state.rst
@@ -639,7 +639,7 @@ above:
 
 	&mmc1 {
 		partitions {
-			compatible = "fixed-partitions";
+			compatible = "barebox,fixed-partitions";
 			#address-cells = <1>;
 			#size-cells = <1>;
 			[?]
@@ -723,7 +723,7 @@ within the EEPROM.
 
 	eeprom at 50 {
 		partitions {
-			compatible = "fixed-partitions";
+			compatible = "barebox,fixed-partitions";
 			#size-cells = <1>;
 			#address-cells = <1>;
 			backend_state_eeprom: eeprom_state_memory at 400 {
diff --git a/arch/arm/dts/am335x-phytec-state.dtsi b/arch/arm/dts/am335x-phytec-state.dtsi
index af4da4ea6469..b6ae82b6b24a 100644
--- a/arch/arm/dts/am335x-phytec-state.dtsi
+++ b/arch/arm/dts/am335x-phytec-state.dtsi
@@ -93,7 +93,7 @@ priority {
 &eeprom {
 	status = "okay";
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <1>;
 		#address-cells = <1>;
 		backend_state_mac_eeprom: state at 0 {
diff --git a/arch/arm/dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts b/arch/arm/dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts
index 787a85394c8a..61ac294c0a36 100644
--- a/arch/arm/dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts
+++ b/arch/arm/dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts
@@ -29,7 +29,7 @@ partitions {
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 
 		partition at 1000 {
 			label = "barebox";
diff --git a/arch/arm/dts/imx50-kindle-common.dtsi b/arch/arm/dts/imx50-kindle-common.dtsi
index c286dcb2e91f..2ef32da80fa6 100644
--- a/arch/arm/dts/imx50-kindle-common.dtsi
+++ b/arch/arm/dts/imx50-kindle-common.dtsi
@@ -138,7 +138,7 @@ &esdhc3 {
 	status = "okay";
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx51-zii-rdu1.dts b/arch/arm/dts/imx51-zii-rdu1.dts
index 6bb491ec3b0a..99da52858f4f 100644
--- a/arch/arm/dts/imx51-zii-rdu1.dts
+++ b/arch/arm/dts/imx51-zii-rdu1.dts
@@ -83,7 +83,7 @@ env_spinor: partition at e0000 {
 
 &esdhc1 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6dl-colibri-iris.dts b/arch/arm/dts/imx6dl-colibri-iris.dts
index 0e10b34cf71c..0986aa6067a5 100644
--- a/arch/arm/dts/imx6dl-colibri-iris.dts
+++ b/arch/arm/dts/imx6dl-colibri-iris.dts
@@ -17,7 +17,7 @@ barebox-environment {
 
 &usdhc3 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/imx6qdl-phytec-mira.dtsi b/arch/arm/dts/imx6qdl-phytec-mira.dtsi
index bcda7dd82a9c..d1fd7dfaf080 100644
--- a/arch/arm/dts/imx6qdl-phytec-mira.dtsi
+++ b/arch/arm/dts/imx6qdl-phytec-mira.dtsi
@@ -27,7 +27,7 @@ &pwm1 {
 
 &usdhc1 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
                 #address-cells = <1>;
                 #size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi b/arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi
index 6cdf82e2cdbf..361c106034cb 100644
--- a/arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi
+++ b/arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi
@@ -157,7 +157,7 @@ &usdhc3 {
         status = "disabled";
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi b/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi
index f244a82270f0..7b77a22ec31e 100644
--- a/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi
+++ b/arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi
@@ -109,7 +109,7 @@ partition at 140000 {
 
 &usdhc4 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6qdl-phytec-state.dtsi b/arch/arm/dts/imx6qdl-phytec-state.dtsi
index 1522b92be15b..5423c3d4f20f 100644
--- a/arch/arm/dts/imx6qdl-phytec-state.dtsi
+++ b/arch/arm/dts/imx6qdl-phytec-state.dtsi
@@ -71,7 +71,7 @@ ok {
 &eeprom {
 	status = "okay";
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <1>;
 		#address-cells = <1>;
 		backend_update_eeprom: state at 0 {
diff --git a/arch/arm/dts/imx6qdl-zii-rdu2.dtsi b/arch/arm/dts/imx6qdl-zii-rdu2.dtsi
index a01962d0e689..402d2f8b9d2d 100644
--- a/arch/arm/dts/imx6qdl-zii-rdu2.dtsi
+++ b/arch/arm/dts/imx6qdl-zii-rdu2.dtsi
@@ -247,7 +247,7 @@ &usbotg {
 
 &usdhc4 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6ul-liteboard.dts b/arch/arm/dts/imx6ul-liteboard.dts
index f9ea9fc0234d..2b9a817a955c 100644
--- a/arch/arm/dts/imx6ul-liteboard.dts
+++ b/arch/arm/dts/imx6ul-liteboard.dts
@@ -62,7 +62,7 @@ environment-emmc {
 
 &usdhc1 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -80,7 +80,7 @@ environment_sd: partition at e0000 {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6ul-phytec-state.dtsi b/arch/arm/dts/imx6ul-phytec-state.dtsi
index d0cad1b5166a..bdaf88082517 100644
--- a/arch/arm/dts/imx6ul-phytec-state.dtsi
+++ b/arch/arm/dts/imx6ul-phytec-state.dtsi
@@ -69,7 +69,7 @@ ok at 18 {
 
 &eeprom {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <1>;
 		#address-cells = <1>;
 		backend_update_eeprom: state at 0 {
diff --git a/arch/arm/dts/imx6ul-tqma6ul-common.dtsi b/arch/arm/dts/imx6ul-tqma6ul-common.dtsi
index 5ff318fcfc58..a22b842a2881 100644
--- a/arch/arm/dts/imx6ul-tqma6ul-common.dtsi
+++ b/arch/arm/dts/imx6ul-tqma6ul-common.dtsi
@@ -23,7 +23,7 @@ environment-emmc {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
@@ -36,7 +36,7 @@ environment_emmc: partition at e0000 {
 
 &usdhc1 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6ul-webasto-ccbv2.dts b/arch/arm/dts/imx6ul-webasto-ccbv2.dts
index 198088bd44b0..517d1a343b51 100644
--- a/arch/arm/dts/imx6ul-webasto-ccbv2.dts
+++ b/arch/arm/dts/imx6ul-webasto-ccbv2.dts
@@ -86,7 +86,7 @@ last_chosen at 10 {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx6ul-webasto-marvel.dts b/arch/arm/dts/imx6ul-webasto-marvel.dts
index 7b5641afbc94..7571923b5551 100644
--- a/arch/arm/dts/imx6ul-webasto-marvel.dts
+++ b/arch/arm/dts/imx6ul-webasto-marvel.dts
@@ -550,7 +550,7 @@ &usdhc2 {
 	status = "okay";
 	/* bootloader specific */
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx7d-ac-sxb.dtsi b/arch/arm/dts/imx7d-ac-sxb.dtsi
index 7154508d071d..5483dbe11c13 100644
--- a/arch/arm/dts/imx7d-ac-sxb.dtsi
+++ b/arch/arm/dts/imx7d-ac-sxb.dtsi
@@ -42,7 +42,7 @@ &usdhc1 {
 	status = "okay";
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -63,7 +63,7 @@ &usdhc3 {
 	status = "okay";
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/imx7d-flex-concentrator-mfg.dts b/arch/arm/dts/imx7d-flex-concentrator-mfg.dts
index 4b150ba48cd0..3b176587ee5f 100644
--- a/arch/arm/dts/imx7d-flex-concentrator-mfg.dts
+++ b/arch/arm/dts/imx7d-flex-concentrator-mfg.dts
@@ -79,7 +79,7 @@ last_chosen at 10 {
 /* eMMC */
 &usdhc3 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx7d-gome-e143_01.dts b/arch/arm/dts/imx7d-gome-e143_01.dts
index ed7f3cfa216b..88034609e4e3 100644
--- a/arch/arm/dts/imx7d-gome-e143_01.dts
+++ b/arch/arm/dts/imx7d-gome-e143_01.dts
@@ -83,7 +83,7 @@ &usdhc3 {
 	partitions {
 		#address-cells = <1>;
 		#size-cells = <1>;
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 
 		/** original storage layout:
 		offset     size  label
diff --git a/arch/arm/dts/imx7d-phyboard-zeta.dts b/arch/arm/dts/imx7d-phyboard-zeta.dts
index 211c72604edb..0725a186ec6b 100644
--- a/arch/arm/dts/imx7d-phyboard-zeta.dts
+++ b/arch/arm/dts/imx7d-phyboard-zeta.dts
@@ -38,7 +38,7 @@ &usdhc3 {
 	status = "okay";
 
 	partitions-boot1 {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx7s-warp.dts b/arch/arm/dts/imx7s-warp.dts
index d84b9ed4342b..e6a99cae4f95 100644
--- a/arch/arm/dts/imx7s-warp.dts
+++ b/arch/arm/dts/imx7s-warp.dts
@@ -22,7 +22,7 @@ environment {
 
 &usdhc3 {
 	partitions-boot1 {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <1>;
 		#size-cells = <1>;
 
diff --git a/arch/arm/dts/imx8mm-innocomm-wb15-evk.dts b/arch/arm/dts/imx8mm-innocomm-wb15-evk.dts
index ac7e5a1cb193..85f346884280 100644
--- a/arch/arm/dts/imx8mm-innocomm-wb15-evk.dts
+++ b/arch/arm/dts/imx8mm-innocomm-wb15-evk.dts
@@ -25,7 +25,7 @@ &ocotp {
 
 &usdhc1 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -43,7 +43,7 @@ env_sd1: partition at 100000 {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/imx8mm-phyboard-polis-rdk.dts b/arch/arm/dts/imx8mm-phyboard-polis-rdk.dts
index 0a6183f092dc..3d1c74562ea8 100644
--- a/arch/arm/dts/imx8mm-phyboard-polis-rdk.dts
+++ b/arch/arm/dts/imx8mm-phyboard-polis-rdk.dts
@@ -96,7 +96,7 @@ &ocotp {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -114,7 +114,7 @@ env_sd2: partition at 100000 {
 
 &usdhc3 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/imx8mp-debix-model-a.dts b/arch/arm/dts/imx8mp-debix-model-a.dts
index a58b40ec8652..4bb5ebf106dd 100644
--- a/arch/arm/dts/imx8mp-debix-model-a.dts
+++ b/arch/arm/dts/imx8mp-debix-model-a.dts
@@ -33,7 +33,7 @@ environment-emmc {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -51,7 +51,7 @@ env_sd: partition at 100000 {
 
 &usdhc3 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts b/arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts
index 88ad897f3429..5f1c76d435b9 100644
--- a/arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts
+++ b/arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts
@@ -28,7 +28,7 @@ &usb_hub_2_x {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -46,7 +46,7 @@ env_sd: partition at 100000 {
 
 &usdhc3 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi b/arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi
index e47623a1a5ef..aac264daab71 100644
--- a/arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi
+++ b/arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi
@@ -95,7 +95,7 @@ &usdhc2 {
 
 &usdhc3 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts b/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts
index f11218c904f5..02bcb6ec29a2 100644
--- a/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts
+++ b/arch/arm/dts/imx8mp-var-dart-dt8mcustomboard.dts
@@ -366,7 +366,7 @@ &usdhc2 {
 	status = "okay";
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <2>;
 		#address-cells = <1>;
 
diff --git a/arch/arm/dts/rk3566-cm3-io.dts b/arch/arm/dts/rk3566-cm3-io.dts
index 39cef5e79799..17033edb78e2 100644
--- a/arch/arm/dts/rk3566-cm3-io.dts
+++ b/arch/arm/dts/rk3566-cm3-io.dts
@@ -25,7 +25,7 @@ &sdhci {
 	no-sd;
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -38,7 +38,7 @@ environment_emmc: partition at 408000 {
 
 &sdmmc0 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3566-pinetab2.dtsi b/arch/arm/dts/rk3566-pinetab2.dtsi
index 47ac12384d37..112acffc36b4 100644
--- a/arch/arm/dts/rk3566-pinetab2.dtsi
+++ b/arch/arm/dts/rk3566-pinetab2.dtsi
@@ -21,7 +21,7 @@ environment-emmc {
 
 &sdhci {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -34,7 +34,7 @@ environment_emmc: partition at 408000 {
 
 &sdmmc0 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3568-bpi-r2-pro.dts b/arch/arm/dts/rk3568-bpi-r2-pro.dts
index 58a2bc442fdf..39ad25a7632b 100644
--- a/arch/arm/dts/rk3568-bpi-r2-pro.dts
+++ b/arch/arm/dts/rk3568-bpi-r2-pro.dts
@@ -31,7 +31,7 @@ &sdhci {
 	no-sd;
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -44,7 +44,7 @@ environment_emmc: partition at 408000 {
 
 &sdmmc0 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3568-evb1-v10.dts b/arch/arm/dts/rk3568-evb1-v10.dts
index 82186ff86ead..c9466d9caf6c 100644
--- a/arch/arm/dts/rk3568-evb1-v10.dts
+++ b/arch/arm/dts/rk3568-evb1-v10.dts
@@ -34,7 +34,7 @@ &sdhci {
 	no-sd;
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -47,7 +47,7 @@ environment_emmc: partition at 408000 {
 
 &sdmmc0 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3568-mecsbc.dts b/arch/arm/dts/rk3568-mecsbc.dts
index c9bab7f36e2f..d63386012377 100644
--- a/arch/arm/dts/rk3568-mecsbc.dts
+++ b/arch/arm/dts/rk3568-mecsbc.dts
@@ -104,7 +104,7 @@ &sdhci {
 	no-sd;
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -124,7 +124,7 @@ state_backend_emmc: partition at 7c0000 {
 
 &sdmmc0 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3568-rock-3a.dts b/arch/arm/dts/rk3568-rock-3a.dts
index 25a0c05737d0..927eb8eb63ae 100644
--- a/arch/arm/dts/rk3568-rock-3a.dts
+++ b/arch/arm/dts/rk3568-rock-3a.dts
@@ -30,7 +30,7 @@ &sdhci {
 	no-sd;
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -43,7 +43,7 @@ environment_emmc: partition at 408000 {
 
 &sdmmc0 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3568-wolfvision-pf5.dts b/arch/arm/dts/rk3568-wolfvision-pf5.dts
index e214842ee40b..9ce24dfc6236 100644
--- a/arch/arm/dts/rk3568-wolfvision-pf5.dts
+++ b/arch/arm/dts/rk3568-wolfvision-pf5.dts
@@ -31,7 +31,7 @@ memory at a00000 {
 
 &sdhci {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3588-orangepi-5-plus.dts b/arch/arm/dts/rk3588-orangepi-5-plus.dts
index 8c765a853c6e..8bafbbd7f2bf 100644
--- a/arch/arm/dts/rk3588-orangepi-5-plus.dts
+++ b/arch/arm/dts/rk3588-orangepi-5-plus.dts
@@ -23,7 +23,7 @@ environment-sd {
 
 &sdhci {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -36,7 +36,7 @@ environment_emmc: partition at 408000 {
 
 &sdmmc {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/rk3588-rock-5b.dts b/arch/arm/dts/rk3588-rock-5b.dts
index 0af544287022..67fc39557400 100644
--- a/arch/arm/dts/rk3588-rock-5b.dts
+++ b/arch/arm/dts/rk3588-rock-5b.dts
@@ -29,7 +29,7 @@ environment-sd {
 
 &sdhci {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
@@ -42,7 +42,7 @@ environment_emmc: partition at 408000 {
 
 &sdmmc {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#address-cells = <2>;
 		#size-cells = <2>;
 
diff --git a/arch/arm/dts/socfpga_arria10_achilles.dts b/arch/arm/dts/socfpga_arria10_achilles.dts
index fbfdc9a8822c..c36912f30eac 100644
--- a/arch/arm/dts/socfpga_arria10_achilles.dts
+++ b/arch/arm/dts/socfpga_arria10_achilles.dts
@@ -201,7 +201,7 @@ &mmc {
 	status = "okay";
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <1>;
 		#address-cells = <1>;
 
diff --git a/arch/arm/dts/socfpga_arria10_mercury_aa1.dts b/arch/arm/dts/socfpga_arria10_mercury_aa1.dts
index 84d4534cc629..b3cd37ed393d 100644
--- a/arch/arm/dts/socfpga_arria10_mercury_aa1.dts
+++ b/arch/arm/dts/socfpga_arria10_mercury_aa1.dts
@@ -44,7 +44,7 @@ &mmc {
 	no-sd;
 
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <1>;
 		#address-cells = <1>;
 
diff --git a/arch/arm/dts/state-example.dtsi b/arch/arm/dts/state-example.dtsi
index 4572168336ae..bd3fe2b1d4df 100644
--- a/arch/arm/dts/state-example.dtsi
+++ b/arch/arm/dts/state-example.dtsi
@@ -106,7 +106,7 @@ backend_state_nand: partition at f00000 {
 
 &som_eeprom { /* On I2C1 */
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <1>;
 		#address-cells = <1>;
 		backend_state_eeprom: state at 400 {
@@ -118,7 +118,7 @@ backend_state_eeprom: state at 400 {
 
 &usdhc2 {
 	partitions {
-		compatible = "fixed-partitions";
+		compatible = "barebox,fixed-partitions";
 		#size-cells = <1>;
 		#address-cells = <1>;
 		backend_state_usdhc: state at 0x80000 {
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:08:28 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:08:28 +0100
Subject: [PATCH 1/6] of: factor out of_node_is_fixed_partitions check
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180833.3955657-2-a.fatoum@pengutronix.de>

We have a number of places where we check if a node is compatible with
"fixed-partitions". In preparation for supporting
"barebox,fixed-partitions" as well, factor out the existing compatible
check into a new of_node_is_fixed_partitions() function.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 drivers/of/base.c      | 6 ++----
 drivers/of/of_path.c   | 7 ++++++-
 drivers/of/partition.c | 4 ++--
 include/of.h           | 6 ++++++
 4 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 125f24056eec..dfe4861c9eb6 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -351,7 +351,7 @@ static const char *of_get_partition_device_alias(struct device_node *np)
 		return alias;
 
 	np = of_get_parent(np);
-	if (np && of_device_is_compatible(np, "fixed-partitions"))
+	if (np && of_node_is_fixed_partitions(np))
 		np = of_get_parent(np);
 
 	return of_alias_get(np);
@@ -3271,10 +3271,8 @@ char *of_get_reproducible_name(struct device_node *node)
 	 * "fixed-partitions" compatible. We skip this extra subnode from the
 	 * reproducible name to get the same name for both bindings.
 	 */
-	if (node->parent &&
-	    of_device_is_compatible(node->parent, "fixed-partitions")) {
+	if (node->parent && of_node_is_fixed_partitions(node->parent))
 		node = node->parent;
-	}
 
 	offset = of_read_number(reg, na);
 
diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c
index 42efb1ad1dbf..b3feaa07e39d 100644
--- a/drivers/of/of_path.c
+++ b/drivers/of/of_path.c
@@ -12,6 +12,11 @@
 
 #include <linux/mtd/mtd.h>
 
+bool of_node_is_fixed_partitions(const struct device_node *np)
+{
+	return of_device_is_compatible(np, "fixed-partitions");
+}
+
 struct device *of_find_device_by_node_path(const char *path)
 {
 	struct device *dev;
@@ -55,7 +60,7 @@ static struct cdev *__of_cdev_find(struct device_node *node, const char *part)
 		const char *uuid;
 		struct device_node *devnode = node->parent;
 
-		if (of_device_is_compatible(devnode, "fixed-partitions")) {
+		if (of_node_is_fixed_partitions(devnode)) {
 			devnode = devnode->parent;
 
 			/* when partuuid is specified short-circuit the search for the cdev */
diff --git a/drivers/of/partition.c b/drivers/of/partition.c
index 56933cc958f7..4f966d900f1f 100644
--- a/drivers/of/partition.c
+++ b/drivers/of/partition.c
@@ -93,7 +93,7 @@ int of_parse_partitions(struct cdev *cdev, struct device_node *node)
 
 	subnode = of_get_child_by_name(node, "partitions");
 	if (subnode) {
-		if (!of_device_is_compatible(subnode, "fixed-partitions"))
+		if (!of_node_is_fixed_partitions(subnode))
 			return -EINVAL;
 		node = subnode;
 	}
@@ -125,7 +125,7 @@ int of_partition_ensure_probed(struct device_node *np)
 		return -EINVAL;
 
 	/* Check if modern partitions binding */
-	if (of_device_is_compatible(parent, "fixed-partitions")) {
+	if (of_node_is_fixed_partitions(parent)) {
 		parent = of_get_parent(parent);
 
 		/*
diff --git a/include/of.h b/include/of.h
index a83663c602b1..985f0195b2aa 100644
--- a/include/of.h
+++ b/include/of.h
@@ -204,6 +204,7 @@ extern const char *of_get_machine_compatible(void);
 extern int of_machine_is_compatible(const char *compat);
 extern int of_device_is_compatible(const struct device_node *device,
 		const char *compat);
+extern bool of_node_is_fixed_partitions(const struct device_node *np);
 extern int of_device_is_available(const struct device_node *device);
 extern bool of_device_is_big_endian(const struct device_node *device);
 
@@ -916,6 +917,11 @@ static inline int of_device_is_compatible(const struct device_node *device,
 	return 0;
 }
 
+static inline bool of_node_is_fixed_partitions(const struct device_node *device)
+{
+	return false;
+}
+
 static inline int of_device_is_available(const struct device_node *device)
 {
 	return 0;
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:08:33 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:08:33 +0100
Subject: [PATCH 6/6] of: partition: add Linux CONFIG_OF_PARTITION-compatible adaptive fixup mode
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180833.3955657-7-a.fatoum@pengutronix.de>

Linux supports OF partitions for MMC since Linux v6.13-rc1 with commit
2e3a191e89f9 ("block: add support for partition table defined in OF"),
but in a manner incompatible to barebox:

If CONFIG_OF_PARTITION is enabled and a fixed-partitions node exists,
the EFI/MBR partition table is completely ignored.
In barebox, they are allowed to coexist, as long as they don't conflict.

To resolve this conflict, we change the default fixup scheme to an
"adaptive" scheme that uses new-style fixups, but with the compatible
depending on the parent device:

  - If the partitions node in the kernel DT already has a compatible,
    use the same compatible as not to clobber new Linux OF partitions,
    which would be parsed by CONFIG_OF_PARTITION
  - If the device is an MTD device, use "fixed-partitions", so Linux
    sees the same partitions and to maintain backwards compatibility
  - For everything else (i.e. EEPROMs and SD/eMMC), use
    "barebox,fixed-partitions"

This scheme is fully backwards-compatible with older kernels and
userspace:

  - barebox,fixed-partitions replaces fixed-partitions only
    for nodes that Linux didn't parse before anyway

  - fixed-partitions will continue to be emitted for MTD,
    which Linux did parse before

  - barebox-state doesn't actually look for the "fixed-partitions"
    compatible to find out if a patition is in a container.
    Instead it checks the parent node name to be equal
    to "partitions"...

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 .../devicetree/bindings/mtd/partition.rst     | 27 +++++++++++++++++--
 drivers/of/partition.c                        | 22 +++++++++++----
 2 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/mtd/partition.rst b/Documentation/devicetree/bindings/mtd/partition.rst
index fb228c63a344..33b8a207f177 100644
--- a/Documentation/devicetree/bindings/mtd/partition.rst
+++ b/Documentation/devicetree/bindings/mtd/partition.rst
@@ -3,9 +3,16 @@
 Representing flash partitions in devicetree
 ===========================================
 
-In addition to the upstream binding, another property is added:
+In addition to the upstream binding, barebox supports parsing OF partitions
+for EEPROMs and for SD/MMC as well. SD/MMC OF partitions in barebox are
+allowed to co-exist with GPT/MBR partitions as long as they don't overlap.
 
-Optional properties:
+This is different from the Linux behavior where OF partitions have precedence
+over GPT/MBR. For this reason, barebox also accepts the compatible
+``barebox,fixed-partitions``, which is handled inside barebox identically to
+``fixed-partitions``, but is ignored by Linux.
+
+Additionally, barebox supports an extra optional property:
 
 * ``partuuid``: The global partition UUID for this partition.
   For GPT partitions, the partuuid is the 16-byte GPT Partition UUID (e.g.
@@ -26,6 +33,9 @@ the partition table node is named appropriately:
 ``boot0-partitions`` and ``boot1-partitions`` are deprecated. Use ``partitions-boot1``
 and ``partitions-boot2`` instead which is supported under Linux as well.
 
+In addition to the upstream ``fixed-partitions`` compatible binding,
+barebox also supports a ``barebox,fixed-partitions`` binding.
+
 Examples:
 
 .. code-block:: none
@@ -54,3 +64,16 @@ Examples:
   		};
   	};
   };
+
+  sd {
+  	partitions {
+  		compatible = "barebox,fixed-partitions";
+  		#address-cells = <1>;
+  		#size-cells = <1>;
+
+  		barebox-env at 1000 {
+  			label = "barebox-environment";
+  			reg = <0x1000 0x20000>;
+  		};
+  	};
+  };
diff --git a/drivers/of/partition.c b/drivers/of/partition.c
index fa4847e20a2b..a0890bfcdef0 100644
--- a/drivers/of/partition.c
+++ b/drivers/of/partition.c
@@ -16,8 +16,6 @@
 #include <init.h>
 #include <globalvar.h>
 
-static unsigned int of_partition_binding;
-
 /**
  * enum of_binding_name - Name of binding to use for OF partition fixup
  * @MTD_OF_BINDING_NEW:		Fix up new-style partition bindings
@@ -25,13 +23,20 @@ static unsigned int of_partition_binding;
  * @MTD_OF_BINDING_LEGACY:	Fix up legacy partition bindings
  *				directly into the parent node without container
  * @MTD_OF_BINDING_DONTTOUCH:	Don't touch partition nodes at all - no fixups
+ * @MTD_OF_BINDING_ADAPTIVE:	Do a new-style fixup with compatible being either:
+ *				- the same compatible as in the kernel DT if available
+ *				- "fixed-partitions" for MTD
+ *				- "barebox,fixed-partitions" otherwise
  */
 enum of_binding_name {
 	MTD_OF_BINDING_NEW,
 	MTD_OF_BINDING_LEGACY,
 	MTD_OF_BINDING_DONTTOUCH,
+	MTD_OF_BINDING_ADAPTIVE,
 };
 
+static unsigned int of_partition_binding = MTD_OF_BINDING_ADAPTIVE;
+
 struct cdev *of_parse_partition(struct cdev *cdev, struct device_node *node)
 {
 	struct devfs_partition partinfo = {};
@@ -172,6 +177,7 @@ int of_fixup_partitions(struct device_node *np, struct cdev *cdev)
 {
 	struct cdev *partcdev;
 	struct device_node *part, *partnode;
+	const char *compat = "fixed-partitions";
 	int ret;
 	int n_cells, n_parts = 0;
 
@@ -199,10 +205,16 @@ int of_fixup_partitions(struct device_node *np, struct cdev *cdev)
 		of_delete_node(partnode);
 		partnode = np;
 		break;
+	case MTD_OF_BINDING_ADAPTIVE:
+		/* If there's already a compatible property, leave it as-is */
+		if (of_property_present(partnode, "compatible"))
+			break;
+		if (!cdev->mtd)
+			compat = "barebox,fixed-partitions";
+		fallthrough;
 	case MTD_OF_BINDING_NEW:
 		partnode = partnode ?: of_new_node(np, "partitions");
-		ret = of_property_write_string(partnode, "compatible",
-					       "fixed-partitions");
+		ret = of_property_write_string(partnode, "compatible", compat);
 		if (ret)
 			return ret;
 		break;
@@ -302,7 +314,7 @@ int of_partitions_register_fixup(struct cdev *cdev)
 }
 
 static const char *of_binding_names[] = {
-	"new", "legacy", "donttouch"
+	"new", "legacy", "donttouch", "adaptive"
 };
 
 static int of_partition_init(void)
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:09:48 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:09:48 +0100
Subject: [PATCH v2 2/3] Documentation: user: optee: bring up-to-date
In-Reply-To: <20250217180949.3961860-1-a.fatoum@pengutronix.de>
References: <20250217180949.3961860-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180949.3961860-2-a.fatoum@pengutronix.de>

Most platforms now use OP-TEE early loading and we have gained support
to communicate with OP-TEE and not only loading it.

Reflect that in the docs.

Reviewed-by: Marco Felsch <m.felsch at pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - Add Marco's R-b
---
 Documentation/user/optee.rst | 45 +++++++++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 11 deletions(-)

diff --git a/Documentation/user/optee.rst b/Documentation/user/optee.rst
index 950917b446ad..2729d21d2e44 100644
--- a/Documentation/user/optee.rst
+++ b/Documentation/user/optee.rst
@@ -4,20 +4,20 @@
 OP-TEE
 ======
 
-Barebox is able to start the Open Portable Trusted Execution Environment
-(OP-TEE) either before starting the linux kernel or during lowlevel board
-initialization in the Pre Bootloader ``PBL``.
+barebox has support for loading and communicating with the Open Portable Trusted
+Execution Environment (OP-TEE).
 
-Before Linux start
-------------------
-Enable the `CONFIG_BOOTM_OPTEE` configuration variable and configure the
-`CONFIG_OPTEE_SIZE` variable. This will reserve a memory area at the end
-of memory for OP-TEE to run, usually Barebox would relocate itself there. To
-load OP-TEE before the kernel is started, configure the global ``bootm.tee``
-variable to point to a valid OPTEE v1 binary.
+Loading OP-TEE
+--------------
+
+barebox can start OP-TEE either during lowlevel board initialization
+in the :ref:`prebootloader <pbl>` or prior to starting the linux kernel.
+
+.. _optee_early_loading:
 
 During the PBL
---------------
+^^^^^^^^^^^^^^
+
 To start OP-TEE during the lowlevel initialization of your board in the ``PBL``,
 enable the ``CONFIG_PBL_OPTEE`` configuration variable. your board should then
 call the function ``start_optee_early(void* tee, void* fdt)`` with a valid tee
@@ -27,3 +27,26 @@ Since OP-TEE in the default configuration also modifies the device tree, don't
 pass the barebox internal device tree, instead copy it into a different memory
 location and pass it to OP-TEE afterwards.
 The modified device tree can then be passed to the main barebox start function.
+
+Before Linux start
+^^^^^^^^^^^^^^^^^^
+
+.. warning:: Late loading of OP-TEE is deprecated, greatly increases the
+   attack surface and is only supported on 32-bit ARM systems.
+   Systems should prefer early loading OP-TEE whenever possible.
+
+Enable the `CONFIG_BOOTM_OPTEE` configuration variable and configure the
+`CONFIG_OPTEE_SIZE` variable. This will reserve a memory area at the end
+of memory for OP-TEE to run, usually Barebox would relocate itself there. To
+load OP-TEE before the kernel is started, configure the global ``bootm.tee``
+variable to point to a valid OPTEE v1 binary.
+
+Communication with OP-TEE
+-------------------------
+
+Controlled by the ``CONFIG_OPTEE`` option, barebox has support for
+communicating with OP-TEE via secure monitor calls and dynamic shared memory.
+This is possible independently of whether OP-TEE was loaded by barebox or not.
+
+The primary use cases currently is SCMI-over-OP-TEE, which is required on
+the STM32MP13.
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:09:49 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:09:49 +0100
Subject: [PATCH v2 3/3] Documentation: user: add security consideration for using barebox
In-Reply-To: <20250217180949.3961860-1-a.fatoum@pengutronix.de>
References: <20250217180949.3961860-1-a.fatoum@pengutronix.de>
Message-ID: <20250217180949.3961860-3-a.fatoum@pengutronix.de>

There are implicit assumptions around use of barebox in secure systems,
which isn't spelt out anywhere, e.g. that FIT images should be located
in raw partitions.

Let's start by writing down these security considerations.

Reviewed-by: Marco Felsch <m.felsch at pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - Add Marco's R-b
  - Fix typo in warning (Sascha)
  - Add heading for shell & environment (Sascha)
---
 Documentation/boards/imx.rst       |   2 +
 Documentation/user/security.rst    | 172 +++++++++++++++++++++++++++++
 Documentation/user/user-manual.rst |   1 +
 3 files changed, 175 insertions(+)
 create mode 100644 Documentation/user/security.rst

diff --git a/Documentation/boards/imx.rst b/Documentation/boards/imx.rst
index 13246599838b..b4adb55d1bea 100644
--- a/Documentation/boards/imx.rst
+++ b/Documentation/boards/imx.rst
@@ -119,6 +119,8 @@ correspond directly to the boot fusemap settings.
 
 See the section on :ref:`Reboot modes<reboot_mode>` for general information.
 
+.. _hab:
+
 High Assurance Boot
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/Documentation/user/security.rst b/Documentation/user/security.rst
new file mode 100644
index 000000000000..5beedfc9a5bf
--- /dev/null
+++ b/Documentation/user/security.rst
@@ -0,0 +1,172 @@
+.. _security:
+
+Security Considerations
+=======================
+
+As bootloader, barebox is often used as part of a cryptographically verified
+boot chain. Such a boot chain is only as secure as its weakest link and
+special care needs to be taken while configuring and deploying barebox.
+
+Verified Boot
+-------------
+
+In a cryptographically verified boot chain (henceforth termed "Verified Boot"),
+each boot stage must be verified by the previous boot stage before execution.
+
+At the start of the verification chain lies some hardware root of trust, most
+often a public key (or its hash) that's programmed into one-time-programmable
+(OTP) eFuses while the board is still in the factory.
+
+The SoC's mask ROM (sometime called BootROM) will consult the eFuses and
+use them to verify the first stage bootloader image. From there on, it's
+expected that every boot stage will only boot the next one after verification.
+
+Verification can take many forms:
+
+- The mask ROM provides an API to verify later images against the same key
+  used to verify the first boot stage.
+
+- If both first stage and second stage result from the same build, the first
+  stage can embed the hash of the second stage.
+
+- The boot stage has an embedded public key which is used to verify the
+  signature of the later boot stage.
+
+Ensuring barebox is verified
+----------------------------
+
+The way that barebox is verified is highly SoC-specific as it's usually done
+by the SoC mask ROM and in some cases by a different first stage bootloader
+like ARM Trusted Firmware.
+
+For some SoCs, like i.MX :ref:`High Assurance Boot <hab>`, the barebox
+build system has built-in support for invoking the necessary external tools
+to sign the boot images.  In the general case however, the signing happens
+outside the barebox build system and the integrator needs to ensure that
+the images are signed with the correct keys.
+
+In any case, each individual board must be locked down, i.e., configured to
+only boot correctly signed images.
+
+The latter is often done by writing a different set of eFuses, see for
+example the barebox :ref:`hab command <command_hab>` which does the necessary
+fusing for both HABv4 and AHAB.
+
+.. warning:: barebox commands like :ref:`hab command <command_hab>` do only
+   touch the subset of fuses relevant to most users. It's up to the integrators
+   to fuse away unneeded functionality like USB recovery or JTAG as needed.
+
+Loading firmware
+----------------
+
+In systems utilizing the ARM TrustZone, barebox is often tasked with loading
+the secure OS (Usually OP-TEE). After OP-TEE is loaded, the rest of the
+software runs in a less-privileged non-secure or "normal" world.
+
+The installation of OP-TEE (and any higher privileged firmware like ARM Trusted
+Firmware) should happen as early as possible, i.e., within the barebox
+:ref:`prebootloader <pbl>`. Delaying installation of OP-TEE means that most of
+barebox will run with elevated permission, which greatly increases the attack
+surface.
+
+In concrete terms, the deprecated ``CONFIG_BOOTM_OPTEE`` option should be
+disabled in favor of :ref:`loading OP-TEE early <optee_early_loading>`.
+
+Ensuring the kernel is verified
+-------------------------------
+
+barebox can embed one or more RSA or ECDSA public keys that it will use to
+verify signed FIT images. In a verified boot system, barebox should not
+be allowed to boot any images that have not been signed by the correct key.
+This can be enforced by setting ``CONFIG_BOOTM_FORCE_SIGNED_IMAGES=y``
+and disabling any ways that could use used to override this.
+
+Disabling the shell
+^^^^^^^^^^^^^^^^^^^
+
+While useful for development, the barebox shell can be used in creative
+ways to circumvent boot restrictions. It's thus advisable to disable
+the shell completely (``CONFIG_SHELL_NONE=y``) or make it non-interactive
+(``CONSOLE_DISABLE_INPUT=y``). This may be coupled with muxing UART RX
+pin as GPIO for maximum effectiveness.
+
+In addition, there are alternative methods of accessing the shell like
+netconsole, or fastboot. These should preferably be disabled or at least
+not activated by default.
+
+Disabling mutable environment handling
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Anything done interactively by the shell can also be done automatically by
+means of init scripts in the environment. Even without shell support, the
+non-volatile variables in the environment could be used to reconfigure
+barebox in an insecure manner.
+
+A secure barebox should thus only consult the environment that it has built
+in and not parse an externally located environment.
+
+This can be enforced by disabling ``CONFIG_ENV_HANDLING``.
+This does not preclude the use of :ref:`Bootchooser` as the
+:ref:`barebox-state framework <state_framework>` can be used independently.
+
+Avoiding use of file systems
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+File systems are among the most complex parser code in barebox and a common
+source of bugs.
+Unlike Linux with its dm-verity support, barebox currently has no way to
+verify a file system before mounting it.
+
+The consequence is that in a verified boot setup, barebox should **never**
+be allowed to mount file systems.
+Especially, :ref:`bootloader spec files <bootloader_spec>` should not be used
+in verified boot setups and signed FIT images **must** be located outside
+a file system and directly in a raw partition.
+
+Configuring barebox
+-------------------
+
+To aid identification of security impact of config options, barebox provides
+two top-level security-related options:
+
+- ``CONFIG_INSECURE``: This enables convenient, but insecure, defaults.
+  Any secure system should disable this option.
+
+- ``CONFIG_HAS_INSECURE_DEFAULTS``: This is selected by options that have
+  an outsized potential of compromising security. It's recommended that
+  all configuration options that select ``CONFIG_HAS_INSECURE_DEFAULTS``
+  are disabled.
+  If not possible, special care needs to be taken in vetting the insecure
+  defaults in question.
+
+.. note:: The barebox configuration must be vetted individually according
+ to threat model. Annotating options with HAS_INSECURE_DEFAULTS is
+ a work-in-progress and is bound to be incomplete, because there is
+ no security one-size-fits-all.
+
+Compile-time configuration
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Any code that's eliminated at compile-time is code that can't be exploited by
+an attacker. It's thus strongly advisable to keep a separate secure
+configuration that disables all features that are used for development and
+are not absolutely necessary for booting in the field.
+
+Run-time configuration
+^^^^^^^^^^^^^^^^^^^^^^
+
+It's sometimes desirable to retain some ability to debug locked down systems.
+While attractive, it's not recommended to retain an insecure bootloader for
+the purposes of debugging due to the risk of this bootloader being leaked.
+
+Instead, it's recommended that debugging images are signed specifically to
+target only a specific board.
+
+This is sometimes supported out-of-the-box by the SoC like with the HABv4
+field return feature.
+
+In the generic case, barebox supports verification of JSON Web Tokens against
+a compiled-in RSA public key. Board code should read the JSON Web Token
+(e.g., from a raw partition on a USB mass storage device), verify the
+serial number claim within against the board's actual serial number and only
+then unlock any debugging functionality.
diff --git a/Documentation/user/user-manual.rst b/Documentation/user/user-manual.rst
index 565e6c11f82f..83ba9e4c3505 100644
--- a/Documentation/user/user-manual.rst
+++ b/Documentation/user/user-manual.rst
@@ -28,6 +28,7 @@ Contents:
    booting-linux
    bootchooser
    remote-control
+   security
    system-setup
    reset-reason
    system-reset
-- 
2.39.5



From a.fatoum at pengutronix.de  Mon Feb 17 10:09:47 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 19:09:47 +0100
Subject: [PATCH v2 1/3] common: introduce CONFIG_HAS_INSECURE_DEFAULTS
Message-ID: <20250217180949.3961860-1-a.fatoum@pengutronix.de>

Unlike the functionality controlled by CONFIG_INSECURE, most
functionality in barebox is not as clear-cut: In secure systems, it's
better to turn off the option, but with enough care, board code may
disable the option later on.

To help with securing barebox, let's identify these options that need a
more thorough look by having them select HAS_INSECURE_DEFAULTS.

In the future, we will start selecting HAS_INSECURE_DEFAULTS when
hardening options are missing. We may also drop HAS_INSECURE_DEFAULTS
again from options that are changed to minimize potential for abuse.

Reviewed-by: Marco Felsch <m.felsch at pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
v1 -> v2:
  - Add Marco's R-b
  - rename CONFIG_HAS_INSECURE_DEFAULT to
           CONFIG_HAS_INSECURE_DEFAULTS
  - Fix typo in CONFIG_MODULES help text
---
 common/Kconfig        | 49 ++++++++++++++++++++++++++++++++++++++++---
 lib/Kconfig.hardening |  6 ++++++
 net/Kconfig           |  4 ++++
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/common/Kconfig b/common/Kconfig
index 0ce99e98286c..6ba5accad337 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -149,9 +149,20 @@ config LOCALVERSION_AUTO
 
 	  which is done within the script "scripts/setlocalversion".)
 
+config HAS_INSECURE_DEFAULTS
+	bool
+	help
+	  This is selected by options that have potentially insecure defaults.
+	  Extra care needs to be taken when these options are not disabled
+	  in secure booted systems.
+
+	  Any option selecting this should include in its help text
+	  an explanation of the security considerations.
+
 config INSECURE
 	bool "enable convenient defaults that are unsuitable for secure-booting systems"
 	default y
+	select HAS_INSECURE_DEFAULTS
 	help
 	  Say n here when barebox is part of a secure boot chain and you
 	  want to disable defaults that may compromise the boot chain.
@@ -344,13 +355,17 @@ endchoice
 config MODULES
 	depends on HAS_MODULES
 	depends on EXPERIMENTAL
+	select HAS_INSECURE_DEFAULTS
 	bool "module support"
 	modules
 	help
 	  This option enables support for loadable modules via insmod. Module
 	  support is quite experimental at the moment. There is no convenient
 	  way to compile modules and the list of exported symbols to actually
-	  make use of modules is short to nonexistent
+	  make use of modules is short to nonexistent.
+
+	  As modules can't be signed, loading external modules is not
+	  recommended for secure systems.
 
 config HAVE_MOD_ARCH_SPECIFIC
 	bool
@@ -750,6 +765,15 @@ config BOOTM_FORCE_SIGNED_IMAGES
 	  are refused to boot. Effectively this means only FIT images can be booted
 	  since they are the only supported image type that support signing.
 
+config BOOTM_OPTIONAL_SIGNED_IMAGES
+	def_bool !BOOTM_FORCE_SIGNED_IMAGES
+	select HAS_INSECURE_DEFAULTS
+	help
+	  With this option enabled, barebox can be reconfigured to not verify signed
+	  images. It's the board code's responsibility to call the function
+	  bootm_force_signed_images() when secure booted to ensure that runtime
+	  reconfiguration is no longer possible.
+
 config BLSPEC
 	depends on FLEXIBLE_BOOTARGS
 	depends on !SHELL_NONE
@@ -964,6 +988,7 @@ source "common/partitions/Kconfig"
 
 config ENV_HANDLING
 	select CRC32
+	select HAS_INSECURE_DEFAULTS
 	bool "Support environment files storage"
 	default y if !SHELL_NONE
 	help
@@ -972,6 +997,17 @@ config ENV_HANDLING
 	  the persistent environment, the "loadenv" command (also executed during
 	  startup) will bring them back. If unsure, say yes.
 
+	  As the environment is not cryptographically verified, an attacker with
+	  raw access to the environment storage may set any nv variable and
+	  inject shell scripts to be run by barebox.
+
+	  In general, secure systems should rely exclusively on the barebox
+	  built-in environment, disable the mutable environment and use the
+	  barebox-state framework for persisting a fixed set of variables.
+
+	  A safe use of the mutable environment may be possible if board code only
+	  mounts it after verifying a JSON Web Token that enables a debug mode.
+
 config DEFAULT_ENVIRONMENT
 	select CRC32
 	bool
@@ -1271,8 +1307,9 @@ config OPTEE_SHM_SIZE
 config BOOTM_OPTEE
 	bool
 	prompt "support booting OP-TEE"
-	depends on BOOTM && ARM && 32BIT
+	depends on BOOTM && ARM32
 	select HAVE_OPTEE
+	select HAS_INSECURE_DEFAULTS
 	help
 	  OP-TEE is a trusted execution environment (TEE). With this option
 	  enabled barebox supports starting optee_os as part of the bootm command.
@@ -1280,6 +1317,11 @@ config BOOTM_OPTEE
 	  the kernel in nonsecure mode. Pass the optee_os binary with the -t option
 	  or in the global.bootm.tee variable.
 
+	  This mode of late loading OP-TEE just before the kernel is deprecated
+	  in favor of early loading OP-TEE in the PBL (CONFIG_PBL_OPTEE).
+	  Early-loading greatly reduces the attack surface and is the only mode
+	  supported outside of ARMv7.
+
 config PBL_OPTEE
 	bool "Enable OP-TEE early start"
 	depends on ARM
@@ -1307,9 +1349,10 @@ config FASTBOOT_SPARSE
 config FASTBOOT_CMD_OEM
 	bool
 	prompt "Enable OEM commands"
+	select HAS_INSECURE_DEFAULTS
 	help
 	  This option enables the fastboot "oem" group of commands. They allow to
-	  executing arbitrary barebox commands and may be disabled in secure
+	  executing arbitrary barebox commands and should be disabled in secure
 	  environments.
 
 endmenu
diff --git a/lib/Kconfig.hardening b/lib/Kconfig.hardening
index 6457d24c7382..ed280dd216d8 100644
--- a/lib/Kconfig.hardening
+++ b/lib/Kconfig.hardening
@@ -1,5 +1,11 @@
 menu "Hardening options"
 
+if HAS_INSECURE_DEFAULTS
+comment "This barebox configuration has CONFIG_HAS_INSECURE_DEFAULTS=y indicating"
+comment "that some of the configured options have potentially insecure defaults."
+comment "Extra care needs to be in secure booted systems."
+endif
+
 config BUG_ON_DATA_CORRUPTION
 	bool "Trigger a BUG when data corruption is detected"
 	select DEBUG_LIST
diff --git a/net/Kconfig b/net/Kconfig
index 2491c497bdfc..0f33a58ff2d5 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -31,9 +31,13 @@ config NET_NETCONSOLE
 	bool
 	depends on !CONSOLE_NONE
 	prompt "network console support"
+	select HAS_INSECURE_DEFAULTS
 	help
 	  This option adds support for a simple udp based network console.
 
+	  This console's communication is not encrypted and is thus not
+	  suitable for use in untrusted networks.
+
 config NET_RESOLV
 	bool
 	prompt "dns support"
-- 
2.39.5



From m.felsch at pengutronix.de  Mon Feb 17 11:25:23 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Mon, 17 Feb 2025 20:25:23 +0100
Subject: [PATCH 0/6] of: partition: add Linux
 CONFIG_OF_PARTITION-compatible adaptive fixup mode
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <20250217192523.crgvcg2phxhce46d@pengutronix.de>

Hi Ahmad,

thanks for working on this!

On 25-02-17, Ahmad Fatoum wrote:
> barebox has for many years supported a superset of the upstream OF
> partitions binding by parsing partitions out of SD/eMMC and EEPROM
> in addition to MTD.
> 
> Unfortunately, we didn't upstream our binding and a different binding
> went upstream into Linux v6.13-rc1 along with Linux commit
> 2e3a191e89f9 ("block: add support for partition table defined in OF").
> 
> Since then, if CONFIG_OF_PARTITION, which is disabled by default, is
> enabled, Linux will ignore any GPT/MBR if an SD/eMMC node has a
> fixed-partitions compatible subnode.
> 
> This is different from the barebox behavior, which allows both OF
> partitions and GPT/MBR to co-exist as long as they don't conflict.
> 
> As many barebox boards:
> 
>   - Place the environment in non-partitioned space prior to the first
>     partition
> 
>   - Fixup all fixed-partitions into the kernel device tree by default

Could we add a warning/notice that the board should be converted to make
use of the barebox GPT parttype-uuid? It's 2025 and IMHO there is no
reason for not using the GPT with the barebox state part-type UUID in
place. This is of course not related to this patchset.

Regards,
  Marco

> this can result in breakage if a newer kernel is booted with
> CONFIG_OF_PARTITION enabled.
> 
> To resolve this, this series introduces the barebox,fixed-partitions
> compatible and uses that in Linux device tree fixups for SD/eMMC
> by default.
> 
> Ahmad Fatoum (6):
>   of: factor out of_node_is_fixed_partitions check
>   of: of_path: support barebox,fixed-partitions
>   ARM: IMX8MP: var-dart-dt8mcustomboard.dts: use new-style partition
>     binding
>   ARM: dts: prefix all non-MTD fixed-partitions with barebox,
>   of: partition: refactor of_partition_binding checks into switch
>   of: partition: add Linux CONFIG_OF_PARTITION-compatible adaptive fixup
>     mode
> 
>  .../devicetree/bindings/mtd/partition.rst     | 27 +++++++-
>  Documentation/user/state.rst                  |  4 +-
>  arch/arm/dts/am335x-phytec-state.dtsi         |  2 +-
>  .../dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts  |  2 +-
>  arch/arm/dts/imx50-kindle-common.dtsi         |  2 +-
>  arch/arm/dts/imx51-zii-rdu1.dts               |  2 +-
>  arch/arm/dts/imx6dl-colibri-iris.dts          |  2 +-
>  arch/arm/dts/imx6qdl-phytec-mira.dtsi         |  2 +-
>  arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi  |  2 +-
>  arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi  |  2 +-
>  arch/arm/dts/imx6qdl-phytec-state.dtsi        |  2 +-
>  arch/arm/dts/imx6qdl-zii-rdu2.dtsi            |  2 +-
>  arch/arm/dts/imx6ul-liteboard.dts             |  4 +-
>  arch/arm/dts/imx6ul-phytec-state.dtsi         |  2 +-
>  arch/arm/dts/imx6ul-tqma6ul-common.dtsi       |  4 +-
>  arch/arm/dts/imx6ul-webasto-ccbv2.dts         |  2 +-
>  arch/arm/dts/imx6ul-webasto-marvel.dts        |  2 +-
>  arch/arm/dts/imx7d-ac-sxb.dtsi                |  4 +-
>  arch/arm/dts/imx7d-flex-concentrator-mfg.dts  |  2 +-
>  arch/arm/dts/imx7d-gome-e143_01.dts           |  2 +-
>  arch/arm/dts/imx7d-phyboard-zeta.dts          |  2 +-
>  arch/arm/dts/imx7s-warp.dts                   |  2 +-
>  arch/arm/dts/imx8mm-innocomm-wb15-evk.dts     |  4 +-
>  arch/arm/dts/imx8mm-phyboard-polis-rdk.dts    |  4 +-
>  arch/arm/dts/imx8mp-debix-model-a.dts         |  4 +-
>  arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts    |  4 +-
>  arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi       |  2 +-
>  .../dts/imx8mp-var-dart-dt8mcustomboard.dts   | 25 ++++----
>  arch/arm/dts/rk3566-cm3-io.dts                |  4 +-
>  arch/arm/dts/rk3566-pinetab2.dtsi             |  4 +-
>  arch/arm/dts/rk3568-bpi-r2-pro.dts            |  4 +-
>  arch/arm/dts/rk3568-evb1-v10.dts              |  4 +-
>  arch/arm/dts/rk3568-mecsbc.dts                |  4 +-
>  arch/arm/dts/rk3568-rock-3a.dts               |  4 +-
>  arch/arm/dts/rk3568-wolfvision-pf5.dts        |  2 +-
>  arch/arm/dts/rk3588-orangepi-5-plus.dts       |  4 +-
>  arch/arm/dts/rk3588-rock-5b.dts               |  4 +-
>  arch/arm/dts/socfpga_arria10_achilles.dts     |  2 +-
>  arch/arm/dts/socfpga_arria10_mercury_aa1.dts  |  2 +-
>  arch/arm/dts/state-example.dtsi               |  4 +-
>  drivers/of/base.c                             |  6 +-
>  drivers/of/of_path.c                          |  9 ++-
>  drivers/of/partition.c                        | 62 ++++++++++++-------
>  include/of.h                                  |  6 ++
>  44 files changed, 149 insertions(+), 96 deletions(-)
> 
> -- 
> 2.39.5
> 
> 
> 


From a.fatoum at pengutronix.de  Mon Feb 17 11:57:23 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Mon, 17 Feb 2025 20:57:23 +0100
Subject: [PATCH 0/6] of: partition: add Linux
 CONFIG_OF_PARTITION-compatible adaptive fixup mode
In-Reply-To: <20250217192523.crgvcg2phxhce46d@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
 <20250217192523.crgvcg2phxhce46d@pengutronix.de>
Message-ID: <87a7379e-8b95-4639-a100-8efe2e070fba@pengutronix.de>

Hi,

On 17.02.25 20:25, Marco Felsch wrote:
> Hi Ahmad,
> 
> thanks for working on this!
> 
> On 25-02-17, Ahmad Fatoum wrote:
>> barebox has for many years supported a superset of the upstream OF
>> partitions binding by parsing partitions out of SD/eMMC and EEPROM
>> in addition to MTD.
>>
>> Unfortunately, we didn't upstream our binding and a different binding
>> went upstream into Linux v6.13-rc1 along with Linux commit
>> 2e3a191e89f9 ("block: add support for partition table defined in OF").
>>
>> Since then, if CONFIG_OF_PARTITION, which is disabled by default, is
>> enabled, Linux will ignore any GPT/MBR if an SD/eMMC node has a
>> fixed-partitions compatible subnode.
>>
>> This is different from the barebox behavior, which allows both OF
>> partitions and GPT/MBR to co-exist as long as they don't conflict.
>>
>> As many barebox boards:
>>
>>   - Place the environment in non-partitioned space prior to the first
>>     partition
>>
>>   - Fixup all fixed-partitions into the kernel device tree by default
> 
> Could we add a warning/notice that the board should be converted to make
> use of the barebox GPT parttype-uuid? It's 2025 and IMHO there is no
> reason for not using the GPT with the barebox state part-type UUID in
> place. This is of course not related to this patchset.

There's no partition type UUID solution for barebox on EFI systems yet
and for many systems in the field, switching to partition type UUID
would mean a migration step, where a rollback to a system with an old
barebox-state version is not possible...

Cheers,
Ahmad

> 
> Regards,
>   Marco
> 
>> this can result in breakage if a newer kernel is booted with
>> CONFIG_OF_PARTITION enabled.
>>
>> To resolve this, this series introduces the barebox,fixed-partitions
>> compatible and uses that in Linux device tree fixups for SD/eMMC
>> by default.
>>
>> Ahmad Fatoum (6):
>>   of: factor out of_node_is_fixed_partitions check
>>   of: of_path: support barebox,fixed-partitions
>>   ARM: IMX8MP: var-dart-dt8mcustomboard.dts: use new-style partition
>>     binding
>>   ARM: dts: prefix all non-MTD fixed-partitions with barebox,
>>   of: partition: refactor of_partition_binding checks into switch
>>   of: partition: add Linux CONFIG_OF_PARTITION-compatible adaptive fixup
>>     mode
>>
>>  .../devicetree/bindings/mtd/partition.rst     | 27 +++++++-
>>  Documentation/user/state.rst                  |  4 +-
>>  arch/arm/dts/am335x-phytec-state.dtsi         |  2 +-
>>  .../dts/fsl-ls1046a-tqmls1046a-mbls10xxa.dts  |  2 +-
>>  arch/arm/dts/imx50-kindle-common.dtsi         |  2 +-
>>  arch/arm/dts/imx51-zii-rdu1.dts               |  2 +-
>>  arch/arm/dts/imx6dl-colibri-iris.dts          |  2 +-
>>  arch/arm/dts/imx6qdl-phytec-mira.dtsi         |  2 +-
>>  arch/arm/dts/imx6qdl-phytec-phycard-som.dtsi  |  2 +-
>>  arch/arm/dts/imx6qdl-phytec-phycore-som.dtsi  |  2 +-
>>  arch/arm/dts/imx6qdl-phytec-state.dtsi        |  2 +-
>>  arch/arm/dts/imx6qdl-zii-rdu2.dtsi            |  2 +-
>>  arch/arm/dts/imx6ul-liteboard.dts             |  4 +-
>>  arch/arm/dts/imx6ul-phytec-state.dtsi         |  2 +-
>>  arch/arm/dts/imx6ul-tqma6ul-common.dtsi       |  4 +-
>>  arch/arm/dts/imx6ul-webasto-ccbv2.dts         |  2 +-
>>  arch/arm/dts/imx6ul-webasto-marvel.dts        |  2 +-
>>  arch/arm/dts/imx7d-ac-sxb.dtsi                |  4 +-
>>  arch/arm/dts/imx7d-flex-concentrator-mfg.dts  |  2 +-
>>  arch/arm/dts/imx7d-gome-e143_01.dts           |  2 +-
>>  arch/arm/dts/imx7d-phyboard-zeta.dts          |  2 +-
>>  arch/arm/dts/imx7s-warp.dts                   |  2 +-
>>  arch/arm/dts/imx8mm-innocomm-wb15-evk.dts     |  4 +-
>>  arch/arm/dts/imx8mm-phyboard-polis-rdk.dts    |  4 +-
>>  arch/arm/dts/imx8mp-debix-model-a.dts         |  4 +-
>>  arch/arm/dts/imx8mp-debix-som-a-bmb-08.dts    |  4 +-
>>  arch/arm/dts/imx8mp-karo-qsxp-ml81.dtsi       |  2 +-
>>  .../dts/imx8mp-var-dart-dt8mcustomboard.dts   | 25 ++++----
>>  arch/arm/dts/rk3566-cm3-io.dts                |  4 +-
>>  arch/arm/dts/rk3566-pinetab2.dtsi             |  4 +-
>>  arch/arm/dts/rk3568-bpi-r2-pro.dts            |  4 +-
>>  arch/arm/dts/rk3568-evb1-v10.dts              |  4 +-
>>  arch/arm/dts/rk3568-mecsbc.dts                |  4 +-
>>  arch/arm/dts/rk3568-rock-3a.dts               |  4 +-
>>  arch/arm/dts/rk3568-wolfvision-pf5.dts        |  2 +-
>>  arch/arm/dts/rk3588-orangepi-5-plus.dts       |  4 +-
>>  arch/arm/dts/rk3588-rock-5b.dts               |  4 +-
>>  arch/arm/dts/socfpga_arria10_achilles.dts     |  2 +-
>>  arch/arm/dts/socfpga_arria10_mercury_aa1.dts  |  2 +-
>>  arch/arm/dts/state-example.dtsi               |  4 +-
>>  drivers/of/base.c                             |  6 +-
>>  drivers/of/of_path.c                          |  9 ++-
>>  drivers/of/partition.c                        | 62 ++++++++++++-------
>>  include/of.h                                  |  6 ++
>>  44 files changed, 149 insertions(+), 96 deletions(-)
>>
>> -- 
>> 2.39.5
>>
>>
>>
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From eagle.alexander923 at gmail.com  Mon Feb 17 21:18:29 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Tue, 18 Feb 2025 08:18:29 +0300
Subject: [PATCH] net: Fix DRIVER_NET_TI_DAVINCI_MDIO dependency
In-Reply-To: <20250217110548.1695938-1-s.hauer@pengutronix.de>
References: <20250217110548.1695938-1-s.hauer@pengutronix.de>
Message-ID: <CAP1tNvTY53UDtd4gzkeQkiZxnh-hsvcpAd=RaiLKm_FWBXJ+_Q@mail.gmail.com>

Thanks, Sascha!

Tested-by: Alexander Shiyan <eagle.alexander923 at gmail.com>

??, 17 ????. 2025??. ? 14:05, Sascha Hauer <s.hauer at pengutronix.de>:
>
> The davinci-mdio driver was factored out from DRIVER_NET_CPSW which
> depends on ARCH_OMAP, so DRIVER_NET_TI_DAVINCI_MDIO should depend
> on the same symbol, not ARCH_OMAP3.
>
> Fixes: f703666dd1 ("net: davinci_mdio: separate driver")
> Reported-by: Alexander Shiyan <eagle.alexander923 at gmail.com>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
>  drivers/net/Kconfig | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 0e78579250..5c436a05cc 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -58,7 +58,7 @@ config DRIVER_NET_CPSW
>
>  config DRIVER_NET_TI_DAVINCI_MDIO
>         bool "TI Davinci MDIO driver"
> -       depends on ARCH_OMAP3 || ARCH_K3 || COMPILE_TEST
> +       depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST
>
>  config DRIVER_NET_DAVINCI_EMAC
>         bool "TI Davinci/OMAP EMAC ethernet driver"
> --
> 2.39.5
>


From s.hauer at pengutronix.de  Tue Feb 18 01:05:27 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Feb 2025 10:05:27 +0100
Subject: [PATCH v2 1/3] common: introduce CONFIG_HAS_INSECURE_DEFAULTS
In-Reply-To: <20250217180949.3961860-1-a.fatoum@pengutronix.de>
References: <20250217180949.3961860-1-a.fatoum@pengutronix.de>
Message-ID: <173986952764.2719121.10220055863778577335.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 19:09:47 +0100, Ahmad Fatoum wrote:
> Unlike the functionality controlled by CONFIG_INSECURE, most
> functionality in barebox is not as clear-cut: In secure systems, it's
> better to turn off the option, but with enough care, board code may
> disable the option later on.
> 
> To help with securing barebox, let's identify these options that need a
> more thorough look by having them select HAS_INSECURE_DEFAULTS.
> 
> [...]

Applied, thanks!

[1/3] common: introduce CONFIG_HAS_INSECURE_DEFAULTS
      https://git.pengutronix.de/cgit/barebox/commit/?id=1ceb8fadf957 (link may not be stable)
[2/3] Documentation: user: optee: bring up-to-date
      https://git.pengutronix.de/cgit/barebox/commit/?id=1db2bef631dd (link may not be stable)
[3/3] Documentation: user: add security consideration for using barebox
      https://git.pengutronix.de/cgit/barebox/commit/?id=9fb315ae4bc5 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:26 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:26 +0100
Subject: [PATCH v2 01/10] ARM: socfpga: kconfig: sort entries
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-1-30b6f507810b@pengutronix.de>

Sort the SoCFPGA entries in the menu by soc type. Add a comment while at it.
Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 arch/arm/mach-socfpga/Kconfig | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index a4d71777978869c29443e4499c262875a835437d..80a15377b2e4be4d1386904a298a9aadcffbab00 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -23,6 +23,10 @@ config ARCH_SOCFPGA_ARRIA10
 	select OFDEVICE
 	select OFTREE
 
+if 32BIT
+
+comment "Cyclone5 boards"
+
 config MACH_SOCFPGA_ALTERA_SOCDK
 	select ARCH_SOCFPGA_CYCLONE5
 	bool "Altera SoCFPGA Development Kit"
@@ -31,14 +35,6 @@ config MACH_SOCFPGA_EBV_SOCRATES
 	select ARCH_SOCFPGA_CYCLONE5
 	bool "EBV Socrates"
 
-config MACH_SOCFPGA_ENCLUSTRA_AA1
-	select ARCH_SOCFPGA_ARRIA10
-	bool "Enclustra AA1"
-
-config MACH_SOCFPGA_REFLEX_ACHILLES
-	select ARCH_SOCFPGA_ARRIA10
-	bool "Reflex Achilles"
-
 config MACH_SOCFPGA_TERASIC_DE0_NANO_SOC
 	select ARCH_SOCFPGA_CYCLONE5
 	bool "Terasic DE0-NANO-SoC aka Atlas"
@@ -51,4 +47,15 @@ config MACH_SOCFPGA_TERASIC_SOCKIT
 	select ARCH_SOCFPGA_CYCLONE5
 	bool "Terasic SoCKit"
 
+comment "Arria10 boards"
+
+config MACH_SOCFPGA_ENCLUSTRA_AA1
+	select ARCH_SOCFPGA_ARRIA10
+	bool "Enclustra AA1"
+
+config MACH_SOCFPGA_REFLEX_ACHILLES
+	select ARCH_SOCFPGA_ARRIA10
+	bool "Reflex Achilles"
+
+endif
 endif

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:25 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:25 +0100
Subject: [PATCH v2 00/10] ARM: SoCFPGA: Add initial support for Agilex5
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>

This series adds basic support for the Altera Agilex5 SoCFPGA series.
Currently only booting from QSPI is supported. Flashing the image to the
QSPI has to be done with quartus_pgm, therefore there are still some
essential things left to have proper support for this platform.

Nevertheless it boots from QSPI and starts linux on the included
Arrow AXE5 board.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
Changes in v2:
- reorder patches
- rebase to v2025.01.0
- rework xgmac to use correct DMA buffers
- fix variable/functions scopes by adding name prefixes
- add pr_fmt where necessary
- axe5: board: convert from postcore_initcall to device_platform_driver
- Link to v1: https://lore.barebox.org/20241029-v2024-10-0-topic-socfpga-agilex5-v1-0-96df2d7dadf4 at pengutronix.de

---
Steffen Trumtrar (10):
      ARM: socfpga: kconfig: sort entries
      mach: socfpga: debug_ll: rework putc_ll
      reset: reset-socfpga: build only for 32-bit socfpga
      arm: socfgpa: add support for SoCFPGA Agilex5
      linux: clk: add clk_parent_data
      clk: support init->parent_data
      clk: socfpga: add agilex5 clock support
      net: phy: add Analog Devices ADIN1300
      net: add support for Designware XGMAC (10gb) ethernet
      ARM: socfpga: add Arrow AXE5 Agilex5 board

 arch/arm/Kconfig                              |   3 -
 arch/arm/boards/Makefile                      |   1 +
 arch/arm/boards/arrow-axe5-eagle/Makefile     |   3 +
 arch/arm/boards/arrow-axe5-eagle/board.c      |  24 +
 arch/arm/boards/arrow-axe5-eagle/lowlevel.c   |  74 +++
 arch/arm/configs/socfpga-agilex5_defconfig    |  88 +++
 arch/arm/dts/Makefile                         |   1 +
 arch/arm/dts/socfpga_agilex5.dtsi             |  71 +++
 arch/arm/dts/socfpga_agilex5_axe5_eagle.dts   |  91 +++
 arch/arm/mach-socfpga/Kconfig                 |  56 +-
 arch/arm/mach-socfpga/Makefile                |  13 +
 arch/arm/mach-socfpga/agilex5-clock-manager.c | 383 ++++++++++++
 arch/arm/mach-socfpga/agilex5-sdram.c         | 347 +++++++++++
 arch/arm/mach-socfpga/agilex5-secreg.c        | 289 +++++++++
 arch/arm/mach-socfpga/arria10-init.c          |   2 +-
 arch/arm/mach-socfpga/atf.c                   |  34 +
 arch/arm/mach-socfpga/cpu_init.c              |  43 ++
 arch/arm/mach-socfpga/cyclone5-init.c         |   2 +-
 arch/arm/mach-socfpga/iossm_mailbox.c         | 511 +++++++++++++++
 arch/arm/mach-socfpga/iossm_mailbox.h         | 157 +++++
 arch/arm/mach-socfpga/mailbox_s10.c           | 347 +++++++++++
 arch/arm/mach-socfpga/secure_reg_helper.c     |  75 +++
 arch/arm/mach-socfpga/smc_api.c               |  43 ++
 arch/arm/mach-socfpga/soc64-system-manager.c  | 102 +++
 arch/arm/mach-socfpga/soc64-wrap-handoff.c    | 124 ++++
 common/Kconfig.debug_ll                       |  17 +
 drivers/clk/clk.c                             |  48 +-
 drivers/clk/socfpga/Makefile                  |   4 +-
 drivers/clk/socfpga/clk-agilex5.c             | 833 +++++++++++++++++++++++++
 drivers/clk/socfpga/clk-gate-s10.c            | 184 ++++++
 drivers/clk/socfpga/clk-periph-s10.c          | 163 +++++
 drivers/clk/socfpga/clk-pll-s10.c             | 140 +++++
 drivers/clk/socfpga/clk.h                     |   9 +
 drivers/clk/socfpga/stratix10-clk.h           |  73 +++
 drivers/net/Kconfig                           |  18 +
 drivers/net/Makefile                          |   2 +
 drivers/net/designware_xgmac.c                | 856 ++++++++++++++++++++++++++
 drivers/net/designware_xgmac.h                | 298 +++++++++
 drivers/net/designware_xgmac_socfpga.c        | 156 +++++
 drivers/net/phy/Kconfig                       |   7 +
 drivers/net/phy/Makefile                      |   1 +
 drivers/net/phy/adin.c                        | 360 +++++++++++
 drivers/reset/Kconfig                         |   6 +
 drivers/reset/Makefile                        |   2 +-
 firmware/Kconfig                              |   3 +
 firmware/Makefile                             |   1 +
 images/Makefile.socfpga                       |  17 +
 include/linux/clk.h                           |  15 +
 include/mach/socfpga/agilex5-clk.h            | 266 ++++++++
 include/mach/socfpga/atf.h                    |  14 +
 include/mach/socfpga/debug_ll.h               |  44 +-
 include/mach/socfpga/generic.h                |   3 +
 include/mach/socfpga/init.h                   |   2 +
 include/mach/socfpga/intel-smc.h              | 545 ++++++++++++++++
 include/mach/socfpga/mailbox_s10.h            | 191 ++++++
 include/mach/socfpga/secure_reg_helper.h      |  19 +
 include/mach/socfpga/smc_api.h                |  12 +
 include/mach/socfpga/soc64-firewall.h         | 177 ++++++
 include/mach/socfpga/soc64-handoff.h          |  50 ++
 include/mach/socfpga/soc64-regs.h             | 195 ++++++
 include/mach/socfpga/soc64-reset-manager.h    |  40 ++
 include/mach/socfpga/soc64-sdram.h            | 203 ++++++
 include/mach/socfpga/soc64-system-manager.h   | 176 ++++++
 63 files changed, 7994 insertions(+), 40 deletions(-)
---
base-commit: fb590cfa8fea6906d3f78dd409856d350e24b582
change-id: 20241029-v2024-10-0-topic-socfpga-agilex5-c087bbc7d774

Best regards,
-- 
Steffen Trumtrar <s.trumtrar at pengutronix.de>



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:27 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:27 +0100
Subject: [PATCH v2 02/10] mach: socfpga: debug_ll: rework putc_ll
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-2-30b6f507810b@pengutronix.de>

Cleanup the debug_ll code for SoCFPGA. The old Gen5 Socfpga have a
narrower ioport width for the NS16550. All newer generations support
32-bit access. Invert the logic and add new *_uart_putc functions for
use with pbl_set_putc.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 arch/arm/mach-socfpga/arria10-init.c  |  2 +-
 arch/arm/mach-socfpga/cyclone5-init.c |  2 +-
 include/mach/socfpga/debug_ll.h       | 44 +++++++++++++++++++++++------------
 3 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-socfpga/arria10-init.c b/arch/arm/mach-socfpga/arria10-init.c
index f8a15ec8b46a761904e470d66bd0900fdb0686ec..14cee3196ade7d36adbb1b70c5b0041bce3cc193 100644
--- a/arch/arm/mach-socfpga/arria10-init.c
+++ b/arch/arm/mach-socfpga/arria10-init.c
@@ -147,7 +147,7 @@ void arria10_finish_io(uint32_t *pinmux)
 
 	arria10_reset_deassert_fpga_peripherals();
 
-	INIT_LL();
+	socfpga_uart_setup_ll();
 
 	puts_ll("lowlevel init done\n");
 }
diff --git a/arch/arm/mach-socfpga/cyclone5-init.c b/arch/arm/mach-socfpga/cyclone5-init.c
index 79a9b15d8761baa8b576a83871a06fbf0559ce91..63ec48b8e48d7e8daa9ce9c158ad5716739b9b3d 100644
--- a/arch/arm/mach-socfpga/cyclone5-init.c
+++ b/arch/arm/mach-socfpga/cyclone5-init.c
@@ -56,5 +56,5 @@ void socfpga_lowlevel_init(struct socfpga_cm_config *cm_config,
 	writel(0x18, CYCLONE5_L3REGS_ADDRESS);
 	writel(0x1, 0xfffefc00);
 
-	INIT_LL();
+	socfpga_uart_setup_ll();
 }
diff --git a/include/mach/socfpga/debug_ll.h b/include/mach/socfpga/debug_ll.h
index 25b3581634704ac523b031a915b73408b674e0c5..698cca60373f7e382db12344e83925dbcb3b35aa 100644
--- a/include/mach/socfpga/debug_ll.h
+++ b/include/mach/socfpga/debug_ll.h
@@ -30,6 +30,26 @@
 #define SCR		0x1c
 #define THR		0x30
 
+static inline void socfpga_gen5_uart_putc(void *base, int c)
+{
+	/* Wait until there is space in the FIFO */
+	while ((readb(base + LSR) & LSR_THRE) == 0);
+	/* Send the character */
+	writeb(c, base + THR);
+	/* Wait to make sure it hits the line, in case we die too soon. */
+	while ((readb(base + LSR) & LSR_THRE) == 0);
+}
+
+static inline void socfpga_uart_putc(void *base, int c)
+{
+	/* Wait until there is space in the FIFO */
+	while ((readl(base + LSR) & LSR_THRE) == 0);
+	/* Send the character */
+	writel(c, base + THR);
+	/* Wait to make sure it hits the line, in case we die too soon. */
+	while ((readl(base + LSR) & LSR_THRE) == 0);
+}
+
 #ifdef CONFIG_DEBUG_LL
 static inline unsigned int ns16550_calc_divisor(unsigned int clk,
 					 unsigned int baudrate)
@@ -37,7 +57,7 @@ static inline unsigned int ns16550_calc_divisor(unsigned int clk,
 	return (clk / 16 / baudrate);
 }
 
-static inline void INIT_LL(void)
+static inline void socfpga_uart_setup_ll(void)
 {
 	unsigned int div = ns16550_calc_divisor(CONFIG_DEBUG_SOCFPGA_UART_CLOCK,
 						115200);
@@ -53,25 +73,19 @@ static inline void INIT_LL(void)
 	writel(FCRVAL, UART_BASE + FCR);
 }
 
-#ifdef CONFIG_ARCH_SOCFPGA_ARRIA10
+#if defined(CONFIG_ARCH_SOCFPGA_CYCLONE5)
 static inline void PUTC_LL(char c)
 {
-	/* Wait until there is space in the FIFO */
-	while ((readl(UART_BASE + LSR) & LSR_THRE) == 0);
-	/* Send the character */
-	writel(c, UART_BASE + THR);
-	/* Wait to make sure it hits the line, in case we die too soon. */
-	while ((readl(UART_BASE + LSR) & LSR_THRE) == 0);
+	void __iomem *base = IOMEM(UART_BASE);
+
+	socfpga_gen5_uart_putc(base, c);
 }
 #else
 static inline void PUTC_LL(char c)
 {
-	/* Wait until there is space in the FIFO */
-	while ((readb(UART_BASE + LSR) & LSR_THRE) == 0);
-	/* Send the character */
-	writeb(c, UART_BASE + THR);
-	/* Wait to make sure it hits the line, in case we die too soon. */
-	while ((readb(UART_BASE + LSR) & LSR_THRE) == 0);
+	void __iomem *base = IOMEM(UART_BASE);
+
+	socfpga_uart_putc(base, c);
 }
 #endif
 
@@ -80,7 +94,7 @@ static inline unsigned int ns16550_calc_divisor(unsigned int clk,
 					 unsigned int baudrate) {
 	return -ENOSYS;
 }
-static inline void INIT_LL(void) {}
+static inline void socfpga_uart_setup_ll(void) {}
 static inline void PUTC_LL(char c) {}
 #endif
 #endif /* __MACH_SOCFPGA_DEBUG_LL_H__ */

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:33 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:33 +0100
Subject: [PATCH v2 08/10] net: phy: add Analog Devices ADIN1300
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-8-30b6f507810b@pengutronix.de>

The Analog Devices ADIN1300 is a low power 10Mbps,100Mbps, and 1Gbps
ethernet phy.
(https://www.analog.com/media/en/technical-documentation/data-sheets/adin1300.pdf)

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/net/phy/Kconfig  |   7 +
 drivers/net/phy/Makefile |   1 +
 drivers/net/phy/adin.c   | 360 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 368 insertions(+)

diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 8e12671801f39a4507937e16d2382e60c258990e..ac6fcf79027aa587b658d5f43cfbf7bb4f86f1f3 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -9,6 +9,13 @@ if PHYLIB
 
 comment "MII PHY device drivers"
 
+config ADIN_PHY
+	bool "Driver for Analog Devices Industrial Ethernet PHYs"
+	help
+	  Currently supports the:  
+	  - ADIN1300
+	  Ethernet PHY
+
 config AR8327N_PHY
 	bool "Driver for QCA AR8327N PHYs"
 	help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index ce15e1bab79fb227f48dca5e9cdba2d0f7e92f7b..862a7e9ba1d19a12b272431c88d452e1434e757a 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y += phy.o mdio_bus.o phy-core.o
+obj-$(CONFIG_ADIN_PHY)		+= adin.o
 obj-$(CONFIG_AR8327N_PHY)	+= ar8327.o
 obj-$(CONFIG_AT803X_PHY)	+= at803x.o
 obj-$(CONFIG_DAVICOM_PHY)	+= davicom.o
diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c
new file mode 100644
index 0000000000000000000000000000000000000000..413722d9297d28c50633c1f6c1892a055fb728f9
--- /dev/null
+++ b/drivers/net/phy/adin.c
@@ -0,0 +1,360 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Driver for Analog Devices Industrial Ethernet PHYs
+ *
+ * Copyright 2019 Analog Devices Inc.
+ */
+#include <common.h>
+#include <init.h>
+#include <linux/bitfield.h>
+#include <linux/mdio.h>
+#include <linux/phy.h>
+#include <linux/string.h>
+
+#define PHY_ID_ADIN1200				0x0283bc20
+#define PHY_ID_ADIN1300				0x0283bc30
+
+#define ADIN1300_MII_EXT_REG_PTR		0x0010
+#define ADIN1300_MII_EXT_REG_DATA		0x0011
+
+#define ADIN1300_PHY_CTRL1			0x0012
+#define   ADIN1300_AUTO_MDI_EN			BIT(10)
+#define   ADIN1300_MAN_MDIX_EN			BIT(9)
+#define   ADIN1300_DIAG_CLK_EN			BIT(2)
+
+#define ADIN1300_RX_ERR_CNT			0x0014
+
+#define ADIN1300_PHY_CTRL_STATUS2		0x0015
+#define   ADIN1300_NRG_PD_EN			BIT(3)
+#define   ADIN1300_NRG_PD_TX_EN			BIT(2)
+#define   ADIN1300_NRG_PD_STATUS		BIT(1)
+
+#define ADIN1300_PHY_CTRL2			0x0016
+#define   ADIN1300_DOWNSPEED_AN_100_EN		BIT(11)
+#define   ADIN1300_DOWNSPEED_AN_10_EN		BIT(10)
+#define   ADIN1300_GROUP_MDIO_EN		BIT(6)
+#define   ADIN1300_DOWNSPEEDS_EN	\
+	(ADIN1300_DOWNSPEED_AN_100_EN | ADIN1300_DOWNSPEED_AN_10_EN)
+
+#define ADIN1300_PHY_CTRL3			0x0017
+#define   ADIN1300_LINKING_EN			BIT(13)
+#define   ADIN1300_DOWNSPEED_RETRIES_MSK	GENMASK(12, 10)
+
+#define ADIN1300_INT_MASK_REG			0x0018
+#define   ADIN1300_INT_MDIO_SYNC_EN		BIT(9)
+#define   ADIN1300_INT_ANEG_STAT_CHNG_EN	BIT(8)
+#define   ADIN1300_INT_ANEG_PAGE_RX_EN		BIT(6)
+#define   ADIN1300_INT_IDLE_ERR_CNT_EN		BIT(5)
+#define   ADIN1300_INT_MAC_FIFO_OU_EN		BIT(4)
+#define   ADIN1300_INT_RX_STAT_CHNG_EN		BIT(3)
+#define   ADIN1300_INT_LINK_STAT_CHNG_EN	BIT(2)
+#define   ADIN1300_INT_SPEED_CHNG_EN		BIT(1)
+#define   ADIN1300_INT_HW_IRQ_EN		BIT(0)
+#define ADIN1300_INT_MASK_EN	\
+	(ADIN1300_INT_LINK_STAT_CHNG_EN | ADIN1300_INT_HW_IRQ_EN)
+#define ADIN1300_INT_STATUS_REG			0x0019
+
+#define ADIN1300_PHY_STATUS1			0x001a
+#define   ADIN1300_PAIR_01_SWAP			BIT(11)
+
+/* EEE register addresses, accessible via Clause 22 access using
+ * ADIN1300_MII_EXT_REG_PTR & ADIN1300_MII_EXT_REG_DATA.
+ * The bit-fields are the same as specified by IEEE for EEE.
+ */
+#define ADIN1300_EEE_CAP_REG			0x8000
+#define ADIN1300_EEE_ADV_REG			0x8001
+#define ADIN1300_EEE_LPABLE_REG			0x8002
+#define ADIN1300_CLOCK_STOP_REG			0x9400
+#define ADIN1300_LPI_WAKE_ERR_CNT_REG		0xa000
+
+#define ADIN1300_CDIAG_RUN			0xba1b
+#define   ADIN1300_CDIAG_RUN_EN			BIT(0)
+
+/*
+ * The XSIM3/2/1 and XSHRT3/2/1 are actually relative.
+ * For CDIAG_DTLD_RSLTS(0) it's ADIN1300_CDIAG_RSLT_XSIM3/2/1
+ * For CDIAG_DTLD_RSLTS(1) it's ADIN1300_CDIAG_RSLT_XSIM3/2/0
+ * For CDIAG_DTLD_RSLTS(2) it's ADIN1300_CDIAG_RSLT_XSIM3/1/0
+ * For CDIAG_DTLD_RSLTS(3) it's ADIN1300_CDIAG_RSLT_XSIM2/1/0
+ */
+#define ADIN1300_CDIAG_DTLD_RSLTS(x)		(0xba1d + (x))
+#define   ADIN1300_CDIAG_RSLT_BUSY		BIT(10)
+#define   ADIN1300_CDIAG_RSLT_XSIM3		BIT(9)
+#define   ADIN1300_CDIAG_RSLT_XSIM2		BIT(8)
+#define   ADIN1300_CDIAG_RSLT_XSIM1		BIT(7)
+#define   ADIN1300_CDIAG_RSLT_SIM		BIT(6)
+#define   ADIN1300_CDIAG_RSLT_XSHRT3		BIT(5)
+#define   ADIN1300_CDIAG_RSLT_XSHRT2		BIT(4)
+#define   ADIN1300_CDIAG_RSLT_XSHRT1		BIT(3)
+#define   ADIN1300_CDIAG_RSLT_SHRT		BIT(2)
+#define   ADIN1300_CDIAG_RSLT_OPEN		BIT(1)
+#define   ADIN1300_CDIAG_RSLT_GOOD		BIT(0)
+
+#define ADIN1300_CDIAG_FLT_DIST(x)		(0xba21 + (x))
+
+#define ADIN1300_GE_SOFT_RESET_REG		0xff0c
+#define   ADIN1300_GE_SOFT_RESET		BIT(0)
+
+#define ADIN1300_GE_CLK_CFG_REG			0xff1f
+#define   ADIN1300_GE_CLK_CFG_MASK		GENMASK(5, 0)
+#define   ADIN1300_GE_CLK_CFG_RCVR_125		BIT(5)
+#define   ADIN1300_GE_CLK_CFG_FREE_125		BIT(4)
+#define   ADIN1300_GE_CLK_CFG_REF_EN		BIT(3)
+#define   ADIN1300_GE_CLK_CFG_HRT_RCVR		BIT(2)
+#define   ADIN1300_GE_CLK_CFG_HRT_FREE		BIT(1)
+#define   ADIN1300_GE_CLK_CFG_25		BIT(0)
+
+#define ADIN1300_GE_RGMII_CFG_REG		0xff23
+#define   ADIN1300_GE_RGMII_RX_MSK		GENMASK(8, 6)
+#define   ADIN1300_GE_RGMII_RX_SEL(x)		\
+		FIELD_PREP(ADIN1300_GE_RGMII_RX_MSK, x)
+#define   ADIN1300_GE_RGMII_GTX_MSK		GENMASK(5, 3)
+#define   ADIN1300_GE_RGMII_GTX_SEL(x)		\
+		FIELD_PREP(ADIN1300_GE_RGMII_GTX_MSK, x)
+#define   ADIN1300_GE_RGMII_RXID_EN		BIT(2)
+#define   ADIN1300_GE_RGMII_TXID_EN		BIT(1)
+#define   ADIN1300_GE_RGMII_EN			BIT(0)
+
+/* RGMII internal delay settings for rx and tx for ADIN1300 */
+#define ADIN1300_RGMII_1_60_NS			0x0001
+#define ADIN1300_RGMII_1_80_NS			0x0002
+#define	ADIN1300_RGMII_2_00_NS			0x0000
+#define	ADIN1300_RGMII_2_20_NS			0x0006
+#define	ADIN1300_RGMII_2_40_NS			0x0007
+
+#define ADIN1300_GE_RMII_CFG_REG		0xff24
+#define   ADIN1300_GE_RMII_FIFO_DEPTH_MSK	GENMASK(6, 4)
+#define   ADIN1300_GE_RMII_FIFO_DEPTH_SEL(x)	\
+		FIELD_PREP(ADIN1300_GE_RMII_FIFO_DEPTH_MSK, x)
+#define   ADIN1300_GE_RMII_EN			BIT(0)
+
+/* RMII fifo depth values */
+#define ADIN1300_RMII_4_BITS			0x0000
+#define ADIN1300_RMII_8_BITS			0x0001
+#define ADIN1300_RMII_12_BITS			0x0002
+#define ADIN1300_RMII_16_BITS			0x0003
+#define ADIN1300_RMII_20_BITS			0x0004
+#define ADIN1300_RMII_24_BITS			0x0005
+
+/**
+ * struct adin_cfg_reg_map - map a config value to aregister value
+ * @cfg:	value in device configuration
+ * @reg:	value in the register
+ */
+struct adin_cfg_reg_map {
+	int cfg;
+	int reg;
+};
+
+static const struct adin_cfg_reg_map adin_rgmii_delays[] = {
+	{ 1600, ADIN1300_RGMII_1_60_NS },
+	{ 1800, ADIN1300_RGMII_1_80_NS },
+	{ 2000, ADIN1300_RGMII_2_00_NS },
+	{ 2200, ADIN1300_RGMII_2_20_NS },
+	{ 2400, ADIN1300_RGMII_2_40_NS },
+	{ },
+};
+
+static const struct adin_cfg_reg_map adin_rmii_fifo_depths[] = {
+	{ 4,  ADIN1300_RMII_4_BITS },
+	{ 8,  ADIN1300_RMII_8_BITS },
+	{ 12, ADIN1300_RMII_12_BITS },
+	{ 16, ADIN1300_RMII_16_BITS },
+	{ 20, ADIN1300_RMII_20_BITS },
+	{ 24, ADIN1300_RMII_24_BITS },
+	{ },
+};
+
+static int adin_lookup_reg_value(const struct adin_cfg_reg_map *tbl, int cfg)
+{
+	size_t i;
+
+	for (i = 0; tbl[i].cfg; i++) {
+		if (tbl[i].cfg == cfg)
+			return tbl[i].reg;
+	}
+
+	return -EINVAL;
+}
+
+static u32 adin_get_reg_value(struct phy_device *phydev,
+			      const char *prop_name,
+			      const struct adin_cfg_reg_map *tbl,
+			      u32 dflt)
+{
+	struct device *dev = &phydev->bus->dev;
+	u32 val;
+	int rc;
+
+	if (of_property_read_u32(dev->of_node, prop_name, &val))
+		return dflt;
+
+	rc = adin_lookup_reg_value(tbl, val);
+	if (rc < 0) {
+		phydev_warn(phydev,
+			    "Unsupported value %u for %s using default (%u)\n",
+			    val, prop_name, dflt);
+		return dflt;
+	}
+
+	return rc;
+}
+
+static u16 adin_ext_read(struct phy_device *phydev, const u32 regnum)
+{
+	u16 val;
+
+	phy_write(phydev, ADIN1300_MII_EXT_REG_PTR, regnum);
+	val = phy_read(phydev, ADIN1300_MII_EXT_REG_DATA);
+
+	debug("%s: adin at 0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
+
+	return val;
+}
+
+static int adin_ext_write(struct phy_device *phydev, const u32 regnum, const u16 val)
+{
+	debug("%s: adin at 0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);
+
+	phy_write(phydev, ADIN1300_MII_EXT_REG_PTR, regnum);
+
+	return phy_write(phydev, ADIN1300_MII_EXT_REG_DATA, val);
+}
+
+static int adin_config_rgmii_mode(struct phy_device *phydev)
+{
+	u32 val;
+	int reg;
+
+	if (!phy_interface_is_rgmii(phydev))
+		return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+					  ADIN1300_GE_RGMII_CFG_REG,
+					  ADIN1300_GE_RGMII_EN);
+
+	reg = adin_ext_read(phydev, ADIN1300_GE_RGMII_CFG_REG);
+	if (reg < 0)
+		return reg;
+
+	reg |= ADIN1300_GE_RGMII_EN;
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+		reg |= ADIN1300_GE_RGMII_RXID_EN;
+
+		val = adin_get_reg_value(phydev, "adi,rx-internal-delay-ps",
+					 adin_rgmii_delays,
+					 ADIN1300_RGMII_2_00_NS);
+		reg &= ~ADIN1300_GE_RGMII_RX_MSK;
+		reg |= ADIN1300_GE_RGMII_RX_SEL(val);
+	} else {
+		reg &= ~ADIN1300_GE_RGMII_RXID_EN;
+	}
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+		reg |= ADIN1300_GE_RGMII_TXID_EN;
+
+		val = adin_get_reg_value(phydev, "adi,tx-internal-delay-ps",
+					 adin_rgmii_delays,
+					 ADIN1300_RGMII_2_00_NS);
+		reg &= ~ADIN1300_GE_RGMII_GTX_MSK;
+		reg |= ADIN1300_GE_RGMII_GTX_SEL(val);
+	} else {
+		reg &= ~ADIN1300_GE_RGMII_TXID_EN;
+	}
+
+	return adin_ext_write(phydev, ADIN1300_GE_RGMII_CFG_REG, reg);
+}
+
+static int adin_config_rmii_mode(struct phy_device *phydev)
+{
+	u32 val;
+	int reg;
+
+	if (phydev->interface != PHY_INTERFACE_MODE_RMII)
+		return phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1,
+					  ADIN1300_GE_RMII_CFG_REG,
+					  ADIN1300_GE_RMII_EN);
+
+	reg = phy_read_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_RMII_CFG_REG);
+	if (reg < 0)
+		return reg;
+
+	reg |= ADIN1300_GE_RMII_EN;
+
+	val = adin_get_reg_value(phydev, "adi,fifo-depth-bits",
+				 adin_rmii_fifo_depths,
+				 ADIN1300_RMII_8_BITS);
+
+	reg &= ~ADIN1300_GE_RMII_FIFO_DEPTH_MSK;
+	reg |= ADIN1300_GE_RMII_FIFO_DEPTH_SEL(val);
+
+	return phy_write_mmd(phydev, MDIO_MMD_VEND1,
+			     ADIN1300_GE_RMII_CFG_REG, reg);
+}
+
+static int adin_config_init(struct phy_device *phydev)
+{
+	int rc;
+
+	rc = adin_config_rgmii_mode(phydev);
+	if (rc < 0)
+		return rc;
+
+	rc = adin_config_rmii_mode(phydev);
+	if (rc < 0)
+		return rc;
+
+	return genphy_config_init(phydev);
+}
+
+static int adin_soft_reset(struct phy_device *phydev)
+{
+	int rc;
+
+	/* Read link and autonegotiation status */
+	/* The reset bit is self-clearing, set it and wait */
+	rc = phy_set_bits_mmd(phydev, MDIO_MMD_VEND1,
+			      ADIN1300_GE_SOFT_RESET_REG,
+			      ADIN1300_GE_SOFT_RESET);
+	if (rc < 0)
+		return rc;
+
+	mdelay(20);
+
+	/* If we get a read error something may be wrong */
+	rc = phy_read_mmd(phydev, MDIO_MMD_VEND1,
+			  ADIN1300_GE_SOFT_RESET_REG);
+
+	return rc < 0 ? rc : 0;
+}
+
+static int adin_config_aneg(struct phy_device *phydev)
+{
+	int ret;
+
+	ret = genphy_config_aneg(phydev);
+	if (ret < 0)
+		return ret;
+
+	/* Enable Autonegotiation */
+	phy_write(phydev, MII_BMCR, BMCR_ANENABLE);
+	phydev->autoneg = AUTONEG_ENABLE;
+
+	return 0;
+}
+
+static struct phy_driver adin_driver[] = {
+	{
+		.phy_id		= 0x0283bc30,
+		.phy_id_mask	= 0xffffffff,
+		.drv.name	= "ADIN1300",
+		.features	= PHY_GBIT_FEATURES,
+		.config_init	= adin_config_init,
+		.soft_reset	= adin_soft_reset,
+		.config_aneg	= adin_config_aneg,
+		.read_status	= genphy_read_status,
+	},
+};
+
+device_phy_drivers(adin_driver);

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:30 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:30 +0100
Subject: [PATCH v2 05/10] linux: clk: add clk_parent_data
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-5-30b6f507810b@pengutronix.de>

Some linux clock drivers use the clk_parent_data struct.

Import it from linux to make driver porting easier.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 include/linux/clk.h | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/include/linux/clk.h b/include/linux/clk.h
index 733ba356dd4bf02132cd0599fbb68b1e37ed1781..948fe98e21a78ad794f2503732ab16b857c0b6fe 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -334,6 +334,20 @@ struct clk_ops {
 	int		(*get_phase)(struct clk_hw *hw);
 };
 
+/**
+ * struct clk_parent_data - clk parent information
+ * @hw: parent clk_hw pointer (used for clk providers with internal clks)
+ * @fw_name: parent name local to provider registering clk
+ * @name: globally unique parent name (used as a fallback)
+ * @index: parent index local to provider registering clk (if @fw_name absent)
+ */
+struct clk_parent_data {
+	const struct clk_hw	*hw;
+	const char		*fw_name;
+	const char		*name;
+	int			index;
+};
+
 /**
  * struct clk_init_data - holds init data that's common to all clocks and is
  * shared between the clock provider and the common clock framework.
@@ -350,6 +364,7 @@ struct clk_init_data {
 	const char		*name;
 	const struct clk_ops	*ops;
 	const char		* const *parent_names;
+	const struct clk_parent_data *parent_data;
 	const struct clk_hw	**parent_hws;
 	unsigned int		num_parents;
 	unsigned long		flags;

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:28 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:28 +0100
Subject: [PATCH v2 03/10] reset: reset-socfpga: build only for 32-bit
 socfpga
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-3-30b6f507810b@pengutronix.de>

The 64-bit SoCFPGA platforms will use reset-simple.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/reset/Kconfig  | 6 ++++++
 drivers/reset/Makefile | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 16c05d50f0e30cb93609c6fbaa4287975894509a..c3779f087490f57deeabf2178723983a87d0446c 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -57,4 +57,10 @@ config RESET_SCMI
 	  This driver uses SCMI Message Protocol to interact with the
 	  firmware controlling all the reset signals.
 
+config RESET_SOCFPGA32
+	bool "SoCFPGA 32-bit Reset Driver"
+	default ARCH_SOCFPGA && 32BIT
+	help
+	  This enables the reset controller driver for 32-bit SoCFPGA platforms.
+
 endif
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index b1668433d76af89a49ef577ad9d0cdc4af48de8d..a446cb20d0b7ddb6404fdf385498bdf6a076e34e 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_RESET_CONTROLLER) += core.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
-obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_RESET_SOCFPGA32) += reset-socfpga.o
 obj-$(CONFIG_RESET_IMX7) += reset-imx7.o
 obj-$(CONFIG_RESET_STARFIVE) += reset-starfive-vic.o
 obj-$(CONFIG_RESET_SCMI) += reset-scmi.o

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:35 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:35 +0100
Subject: [PATCH v2 10/10] ARM: socfpga: add Arrow AXE5 Agilex5 board
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-10-30b6f507810b@pengutronix.de>

Add the Agilex5-based Arrow AXE5-Eagle board.
It consists among other things of:
  - Agilex5 SoCFPGA
  - 1 GB LPDDR4 SDRAM for HPS
  - 1 GB LPDDR4 SDRAM for FPGA
  - 1 Gb QSPI for configuration via SDM
  - microSD
  - 4-port USB hub
  - 2x 1Gb Ethernet
  - HDMI output

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 arch/arm/boards/Makefile                    |  1 +
 arch/arm/boards/arrow-axe5-eagle/Makefile   |  3 +
 arch/arm/boards/arrow-axe5-eagle/board.c    | 24 ++++++++
 arch/arm/boards/arrow-axe5-eagle/lowlevel.c | 74 +++++++++++++++++++++++
 arch/arm/configs/socfpga-agilex5_defconfig  | 88 ++++++++++++++++++++++++++++
 arch/arm/dts/Makefile                       |  1 +
 arch/arm/dts/socfpga_agilex5_axe5_eagle.dts | 91 +++++++++++++++++++++++++++++
 images/Makefile.socfpga                     |  9 +++
 8 files changed, 291 insertions(+)

diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index 67d91616f623be9eddd370485707eeb25d3ebe40..4a0293a2c64f9bdc5d04fd1ecd7e5bcb7f40ae3c 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -111,6 +111,7 @@ obj-$(CONFIG_MACH_SAMA5D4_WIFX)			+= sama5d4_wifx/
 obj-$(CONFIG_MACH_SCB9328)			+= scb9328/
 obj-$(CONFIG_MACH_SEEED_ODYSSEY)		+= seeed-odyssey/
 obj-$(CONFIG_MACH_SOCFPGA_ALTERA_SOCDK)		+= altera-socdk/
+obj-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE)	+= arrow-axe5-eagle/
 obj-$(CONFIG_MACH_SOCFPGA_EBV_SOCRATES)		+= ebv-socrates/
 obj-$(CONFIG_MACH_SOCFPGA_ENCLUSTRA_AA1)	+= enclustra-aa1/
 obj-$(CONFIG_MACH_SOCFPGA_REFLEX_ACHILLES)	+= reflex-achilles/
diff --git a/arch/arm/boards/arrow-axe5-eagle/Makefile b/arch/arm/boards/arrow-axe5-eagle/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1d052d28c9fc6a82dbf806eedac60fac8a56d4f9
--- /dev/null
+++ b/arch/arm/boards/arrow-axe5-eagle/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+lwl-y += lowlevel.o
+obj-y += board.o
diff --git a/arch/arm/boards/arrow-axe5-eagle/board.c b/arch/arm/boards/arrow-axe5-eagle/board.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0c4b2034a774d2b3aabba9c9afa61661c2ad317
--- /dev/null
+++ b/arch/arm/boards/arrow-axe5-eagle/board.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <bbu.h>
+#include <mach/socfpga/soc64-regs.h>
+
+static int axe5_probe(struct device *dev)
+{
+	return 0;
+}
+
+static const struct of_device_id axe5_of_match[] = {
+	{ .compatible = "arrow,axe5-eagle" },
+	{ /* sentinel */ },
+};
+BAREBOX_DEEP_PROBE_ENABLE(axe5_of_match);
+
+static struct driver axe5_board_driver = {
+	.name = "board-arrow-axe5-eagle",
+	.probe = axe5_probe,
+	.of_compatible = axe5_of_match,
+};
+device_platform_driver(axe5_board_driver);
diff --git a/arch/arm/boards/arrow-axe5-eagle/lowlevel.c b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
new file mode 100644
index 0000000000000000000000000000000000000000..b736ca643f86b031dc070baf62f15a4a09e5aaba
--- /dev/null
+++ b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <common.h>
+#include <io.h>
+#include <linux/sizes.h>
+#include <asm/barebox-arm.h>
+#include <asm/system.h>
+#include <pbl.h>
+#include <mach/socfpga/debug_ll.h>
+#include <mach/socfpga/init.h>
+#include <mach/socfpga/generic.h>
+#include <mach/socfpga/mailbox_s10.h>
+#include <mach/socfpga/soc64-firewall.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-sdram.h>
+#include <mach/socfpga/soc64-system-manager.h>
+
+extern char __dtb_z_socfpga_agilex5_axe5_eagle_start[];
+
+#define AXE5_STACKTOP	(SZ_512K)
+
+static noinline void axe5_eagle_continue(void)
+{
+	void *fdt;
+
+	agilex5_clk_init();
+
+	socfpga_uart_setup_ll();
+	pbl_set_putc(socfpga_uart_putc, (void *) SOCFPGA_UART0_ADDRESS);
+
+	pr_debug("Lowlevel init done\n");
+
+	printk("Change the pullup values on EMAC2 HPS mii signals\n");
+	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x224);
+	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x228);
+	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x23c);
+	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x234);
+	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x248);
+	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x24c);
+
+	writel(0x410, 0x10c03304);
+	writel(0x410, 0x10c03300);
+	/* reset the phy via GPIO10. We currently haven't got enough space
+	 * to enable the gpio driver in barebox. */
+	writel(0x000, 0x10c03300);
+	mdelay(1000);
+	writel(0x410, 0x10c03300);
+
+	if (current_el() == 3) {
+		agilex5_initialize_security_policies();
+		pr_debug("Security policies initialized\n");
+
+		agilex5_ddr_init_full();
+
+		socfpga_mailbox_s10_init();
+		socfpga_mailbox_s10_qspi_open();
+
+		agilex5_load_and_start_image_via_tfa(SZ_1G);
+	}
+
+	fdt = __dtb_z_socfpga_agilex5_axe5_eagle_start;
+
+	barebox_arm_entry(SOCFPGA_AGILEX5_DDR_BASE + SZ_1M, SZ_1G - SZ_1M, fdt);
+}
+
+ENTRY_FUNCTION_WITHSTACK(start_socfpga_agilex5_axe5_eagle, AXE5_STACKTOP, r0, r1, r2)
+{
+	if (current_el() == 3)
+		socfpga_agilex5_cpu_lowlevel_init();
+
+	relocate_to_current_adr();
+	setup_c();
+
+	axe5_eagle_continue();
+}
diff --git a/arch/arm/configs/socfpga-agilex5_defconfig b/arch/arm/configs/socfpga-agilex5_defconfig
new file mode 100644
index 0000000000000000000000000000000000000000..b443a1281e6ad621d7270cade3ea0d60ccdc9af5
--- /dev/null
+++ b/arch/arm/configs/socfpga-agilex5_defconfig
@@ -0,0 +1,88 @@
+CONFIG_ARCH_SOCFPGA=y
+CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_MMU=y
+CONFIG_MALLOC_SIZE=0x0
+CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
+CONFIG_PROMPT="barebox> "
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+# CONFIG_TIMESTAMP is not set
+CONFIG_BOOTM_SHOW_TYPE=y
+CONFIG_BOOTM_VERBOSE=y
+CONFIG_BOOTM_INITRD=y
+CONFIG_BOOTM_OFTREE=y
+CONFIG_BOOTM_OFTREE_UIMAGE=y
+CONFIG_BOOTM_AIMAGE=y
+CONFIG_BLSPEC=y
+CONFIG_SYSTEM_PARTITIONS=y
+CONFIG_CONSOLE_ACTIVATE_FIRST=y
+CONFIG_CONSOLE_ALLOW_COLOR=y
+CONFIG_PBL_CONSOLE=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_RESET_SOURCE=y
+CONFIG_PRINTF_FULL=y
+CONFIG_CMD_DMESG=y
+CONFIG_CMD_IOMEM=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_DEFAULTENV=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_FILETYPE=y
+CONFIG_CMD_LN=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_SHA256SUM=y
+CONFIG_CMD_UNCOMPRESS=y
+CONFIG_CMD_LET=y
+CONFIG_CMD_READF=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_ETHLOG=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_LOGIN=y
+CONFIG_CMD_PASSWD=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_CRC=y
+CONFIG_CMD_CRC_CMP=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MM=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_DETECT=y
+CONFIG_CMD_BAREBOX_UPDATE=y
+CONFIG_CMD_OF_DIFF=y
+CONFIG_CMD_OF_NODE=y
+CONFIG_CMD_OF_PROPERTY=y
+CONFIG_CMD_OF_DISPLAY_TIMINGS=y
+CONFIG_CMD_OF_FIXUP_STATUS=y
+CONFIG_CMD_OF_OVERLAY=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIME=y
+CONFIG_NET=y
+CONFIG_OF_BAREBOX_DRIVERS=y
+CONFIG_OF_BAREBOX_ENV_IN_FS=y
+CONFIG_OF_OVERLAY_LIVE=y
+CONFIG_SERIAL_DEV_BUS=y
+CONFIG_DRIVER_SERIAL_NS16550=y
+# CONFIG_SPI is not set
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_SPI_CADENCE_QUADSPI=y
+CONFIG_MFD_SYSCON=y
+# CONFIG_PINCTRL is not set
+CONFIG_ARM_SCMI_PROTOCOL=y
+# CONFIG_VIRTIO_MENU is not set
+CONFIG_MAILBOX=y
+CONFIG_FS_TFTP=y
+CONFIG_ZLIB=y
+CONFIG_CRC_CCITT=y
+CONFIG_NLS=y
+# CONFIG_MISSING_FIRMWARE_ERROR is not set
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index fe32b812f6037f382954a84f9ab40cfc8715e367..beac55d06e5ae0d411f4f25cbe3426a9a0d9845b 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -137,6 +137,7 @@ lwl-$(CONFIG_MACH_SOCFPGA_REFLEX_ACHILLES) += socfpga_arria10_achilles.dtb.o
 lwl-$(CONFIG_MACH_SOCFPGA_TERASIC_DE0_NANO_SOC) += socfpga_cyclone5_de0_nano_soc.dtb.o
 lwl-$(CONFIG_MACH_SOCFPGA_TERASIC_DE10_NANO) += socfpga_cyclone5_de10_nano.dtb.o
 lwl-$(CONFIG_MACH_SOCFPGA_TERASIC_SOCKIT) += socfpga_cyclone5_sockit.dtb.o
+lwl-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += socfpga_agilex5_axe5_eagle.dtb.o
 lwl-$(CONFIG_MACH_SOLIDRUN_CUBOX) += dove-cubox-bb.dtb.o
 lwl-$(CONFIG_MACH_SOLIDRUN_MICROSOM) += imx6dl-hummingboard.dtb.o imx6q-hummingboard.dtb.o \
 				imx6dl-hummingboard2.dtb.o imx6q-hummingboard2.dtb.o \
diff --git a/arch/arm/dts/socfpga_agilex5_axe5_eagle.dts b/arch/arm/dts/socfpga_agilex5_axe5_eagle.dts
new file mode 100644
index 0000000000000000000000000000000000000000..af12f55383a55856bd6d90ab9126a2cce53c5b9d
--- /dev/null
+++ b/arch/arm/dts/socfpga_agilex5_axe5_eagle.dts
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier:     GPL-2.0
+/*
+ * Copyright (C) 2024 Pengutronix, Steffen Trumtrar <kernel at pengutronix.de>
+ */
+
+#include <arm64/intel/socfpga_agilex5.dtsi>
+#include "socfpga_agilex5.dtsi"
+
+/ {
+	model = "SoCFPGA Agilex5 AXE5-Eagle";
+	compatible = "arrow,axe5-eagle", "intel,socfpga-agilex","altr,socfpga";
+
+	aliases {
+		serial0 = &uart0;
+		ethernet0 = &gmac2;
+	};
+
+	chosen {
+		stdout-path = &uart0;
+	};
+
+	memory at 80100000 {
+		device_type = "memory";
+		reg = <0 0x80100000 0 0x3ff00000>;
+	};
+};
+
+&osc1 {
+	clock-frequency = <25000000>;
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&qspi {
+	status = "okay";
+
+	flash0: flash at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "mt25qu02g";
+		reg = <0>;
+		spi-max-frequency = <100000000>;
+
+		m25p,fast-read;
+		cdns,page-size = <256>;
+		cdns,block-size = <16>;
+		cdns,read-delay = <1>;
+		cdns,tshsl-ns = <50>;
+		cdns,tsd2d-ns = <50>;
+		cdns,tchsh-ns = <4>;
+		cdns,tslch-ns = <4>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			qspi_boot: partition at 0 {
+				label = "u-boot";
+				reg = <0x0 0x04200000>;
+			};
+
+			root: partition at 4200000 {
+				label = "root";
+				reg = <0x04200000 0x0BE00000>;
+			};
+		};
+	};
+};
+
+&gmac2 {
+	status = "okay";
+	phy-mode = "rgmii-id";
+	phy-handle = <&emac2_phy0>;
+
+	max-frame-size = <9000>;
+
+	mdio0 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "snps,dwmac-mdio";
+		emac2_phy0: ethernet-phy at 1 {
+			phy-reset-gpios = <&portb 10 GPIO_ACTIVE_LOW>;
+			reg = <0x1>;
+			adi,rx-internal-delay-ps = <2000>;
+			adi,tx-internal-delay-ps = <2000>;
+		};
+	};
+};
diff --git a/images/Makefile.socfpga b/images/Makefile.socfpga
index 807ca78e4ac8636382107f844eeb83ba9007a583..db1a47b6a1ad7f6a7d08036bdeed6a50b707ac47 100644
--- a/images/Makefile.socfpga
+++ b/images/Makefile.socfpga
@@ -87,6 +87,15 @@ pblb-$(CONFIG_MACH_SOCFPGA_EBV_SOCRATES) += start_socfpga_socrates
 FILE_barebox-socfpga-socrates.img = start_socfpga_socrates.pblb
 socfpga-barebox-$(CONFIG_MACH_SOCFPGA_EBV_SOCRATES) += barebox-socfpga-socrates.img
 
+# ----------------------- Agilex5 based boards ---------------------------
+pblb-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += start_socfpga_agilex5_axe5_eagle
+FILE_barebox-socfpga-agilex5-axe5-eagle.img = start_socfpga_agilex5_axe5_eagle.pblb.hex
+socfpga-barebox-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += barebox-socfpga-agilex5-axe5-eagle.img
+
+pblb-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += start_socfpga_agilex5_axe5_eagle
+FILE_barebox-socfpga-agilex5-axe5-eagle-2nd.img = start_socfpga_agilex5_axe5_eagle.pblb
+socfpga-barebox-$(CONFIG_MACH_SOCFPGA_ARROW_AXE5_EAGLE) += barebox-socfpga-agilex5-axe5-eagle-2nd.img
+
 ifdef CONFIG_ARCH_SOCFPGA_XLOAD
 image-y += $(socfpga-xload-y)
 else

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:32 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:32 +0100
Subject: [PATCH v2 07/10] clk: socfpga: add agilex5 clock support
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-7-30b6f507810b@pengutronix.de>

Add support for the Stratix10 and Agilex5 pll,gate and periph clocks.

Only tested on Agilex5.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/clk/socfpga/Makefile         |   4 +-
 drivers/clk/socfpga/clk-agilex5.c    | 833 +++++++++++++++++++++++++++++++++++
 drivers/clk/socfpga/clk-gate-s10.c   | 184 ++++++++
 drivers/clk/socfpga/clk-periph-s10.c | 163 +++++++
 drivers/clk/socfpga/clk-pll-s10.c    | 140 ++++++
 drivers/clk/socfpga/clk.h            |   9 +
 drivers/clk/socfpga/stratix10-clk.h  |  73 +++
 7 files changed, 1405 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/socfpga/Makefile b/drivers/clk/socfpga/Makefile
index 0a195cbf3f8efe2828cc2eade549d550001f0ca1..bd6f2266fc6847d3201d3fcb536e8061816ac8e3 100644
--- a/drivers/clk/socfpga/Makefile
+++ b/drivers/clk/socfpga/Makefile
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
-obj-y	+= clk.o
+obj-$(CONFIG_ARCH_SOCFPGA_CYCLONE5)	+= clk.o
+obj-$(CONFIG_ARCH_SOCFPGA_ARRIA10)	+= clk.o
 
 obj-$(CONFIG_ARCH_SOCFPGA_ARRIA10) += clk-gate-a10.o clk-periph-a10.o clk-pll-a10.o
+obj-$(CONFIG_ARCH_SOCFPGA_AGILEX5) += clk-agilex5.o clk-pll-s10.o clk-periph-s10.o clk-gate-s10.o
diff --git a/drivers/clk/socfpga/clk-agilex5.c b/drivers/clk/socfpga/clk-agilex5.c
new file mode 100644
index 0000000000000000000000000000000000000000..1b6dc5abde931e192b917b3584513406075c06e8
--- /dev/null
+++ b/drivers/clk/socfpga/clk-agilex5.c
@@ -0,0 +1,833 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022, Intel Corporation
+ */
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <dt-bindings/clock/intel,agilex5-clkmgr.h>
+
+#include "stratix10-clk.h"
+
+static const struct clk_parent_data pll_mux[] = {
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data boot_mux[] = {
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+};
+
+static const struct clk_parent_data core0_free_mux[] = {
+	{
+		.fw_name = "main_pll_c1",
+		.name = "main_pll_c1",
+	},
+	{
+		.fw_name = "peri_pll_c0",
+		.name = "peri_pll_c0",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data core1_free_mux[] = {
+	{
+		.fw_name = "main_pll_c1",
+		.name = "main_pll_c1",
+	},
+	{
+		.fw_name = "peri_pll_c0",
+		.name = "peri_pll_c0",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data core2_free_mux[] = {
+	{
+		.fw_name = "main_pll_c0",
+		.name = "main_pll_c0",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data core3_free_mux[] = {
+	{
+		.fw_name = "main_pll_c0",
+		.name = "main_pll_c0",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data dsu_free_mux[] = {
+	{
+		.fw_name = "main_pll_c2",
+		.name = "main_pll_c2",
+	},
+	{
+		.fw_name = "peri_pll_c0",
+		.name = "peri_pll_c0",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data noc_free_mux[] = {
+	{
+		.fw_name = "main_pll_c3",
+		.name = "main_pll_c3",
+	},
+	{
+		.fw_name = "peri_pll_c1",
+		.name = "peri_pll_c1",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data emaca_free_mux[] = {
+	{
+		.fw_name = "main_pll_c1",
+		.name = "main_pll_c1",
+	},
+	{
+		.fw_name = "peri_pll_c3",
+		.name = "peri_pll_c3",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data emacb_free_mux[] = {
+	{
+		.fw_name = "main_pll_c1",
+		.name = "main_pll_c1",
+	},
+	{
+		.fw_name = "peri_pll_c3",
+		.name = "peri_pll_c3",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data emac_ptp_free_mux[] = {
+	{
+		.fw_name = "main_pll_c3",
+		.name = "main_pll_c3",
+	},
+	{
+		.fw_name = "peri_pll_c3",
+		.name = "peri_pll_c3",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data gpio_db_free_mux[] = {
+	{
+		.fw_name = "main_pll_c3",
+		.name = "main_pll_c3",
+	},
+	{
+		.fw_name = "peri_pll_c1",
+		.name = "peri_pll_c1",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data psi_ref_free_mux[] = {
+	{
+		.fw_name = "main_pll_c1",
+		.name = "main_pll_c1",
+	},
+	{
+		.fw_name = "peri_pll_c3",
+		.name = "peri_pll_c3",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data usb31_free_mux[] = {
+	{
+		.fw_name = "main_pll_c3",
+		.name = "main_pll_c3",
+	},
+	{
+		.fw_name = "peri_pll_c2",
+		.name = "peri_pll_c2",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data s2f_usr0_free_mux[] = {
+	{
+		.fw_name = "main_pll_c1",
+		.name = "main_pll_c1",
+	},
+	{
+		.fw_name = "peri_pll_c3",
+		.name = "peri_pll_c3",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data s2f_usr1_free_mux[] = {
+	{
+		.fw_name = "main_pll_c1",
+		.name = "main_pll_c1",
+	},
+	{
+		.fw_name = "peri_pll_c3",
+		.name = "peri_pll_c3",
+	},
+	{
+		.fw_name = "osc1",
+		.name = "osc1",
+	},
+	{
+		.fw_name = "cb-intosc-hs-div2-clk",
+		.name = "cb-intosc-hs-div2-clk",
+	},
+	{
+		.fw_name = "f2s-free-clk",
+		.name = "f2s-free-clk",
+	},
+};
+
+static const struct clk_parent_data core0_mux[] = {
+	{
+		.fw_name = "core0_free_clk",
+		.name = "core0_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data core1_mux[] = {
+	{
+		.fw_name = "core1_free_clk",
+		.name = "core1_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data core2_mux[] = {
+	{
+		.fw_name = "core2_free_clk",
+		.name = "core2_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data core3_mux[] = {
+	{
+		.fw_name = "core3_free_clk",
+		.name = "core3_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data dsu_mux[] = {
+	{
+		.fw_name = "dsu_free_clk",
+		.name = "dsu_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data emac_mux[] = {
+	{
+		.fw_name = "emaca_free_clk",
+		.name = "emaca_free_clk",
+	},
+	{
+		.fw_name = "emacb_free_clk",
+		.name = "emacb_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data noc_mux[] = {
+	{
+		.fw_name = "noc_free_clk",
+		.name = "noc_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data s2f_user0_mux[] = {
+	{
+		.fw_name = "s2f_user0_free_clk",
+		.name = "s2f_user0_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data s2f_user1_mux[] = {
+	{
+		.fw_name = "s2f_user1_free_clk",
+		.name = "s2f_user1_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data psi_mux[] = {
+	{
+		.fw_name = "psi_ref_free_clk",
+		.name = "psi_ref_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data gpio_db_mux[] = {
+	{
+		.fw_name = "gpio_db_free_clk",
+		.name = "gpio_db_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data emac_ptp_mux[] = {
+	{
+		.fw_name = "emac_ptp_free_clk",
+		.name = "emac_ptp_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+static const struct clk_parent_data usb31_mux[] = {
+	{
+		.fw_name = "usb31_free_clk",
+		.name = "usb31_free_clk",
+	},
+	{
+		.fw_name = "boot_clk",
+		.name = "boot_clk",
+	},
+};
+
+/*
+ * TODO - Clocks in AO (always on) controller
+ * 2 main PLLs only
+ */
+static const struct stratix10_pll_clock agilex5_pll_clks[] = {
+	{ AGILEX5_BOOT_CLK, "boot_clk", boot_mux, ARRAY_SIZE(boot_mux), 0,
+	  0x0 },
+	{ AGILEX5_MAIN_PLL_CLK, "main_pll", pll_mux, ARRAY_SIZE(pll_mux), 0,
+	  0x48 },
+	{ AGILEX5_PERIPH_PLL_CLK, "periph_pll", pll_mux, ARRAY_SIZE(pll_mux), 0,
+	  0x9C },
+};
+
+static const struct stratix10_perip_c_clock agilex5_main_perip_c_clks[] = {
+	{ AGILEX5_MAIN_PLL_C0_CLK, "main_pll_c0", "main_pll", NULL, 1, 0,
+	  0x5C },
+	{ AGILEX5_MAIN_PLL_C1_CLK, "main_pll_c1", "main_pll", NULL, 1, 0,
+	  0x60 },
+	{ AGILEX5_MAIN_PLL_C2_CLK, "main_pll_c2", "main_pll", NULL, 1, 0,
+	  0x64 },
+	{ AGILEX5_MAIN_PLL_C3_CLK, "main_pll_c3", "main_pll", NULL, 1, 0,
+	  0x68 },
+	{ AGILEX5_PERIPH_PLL_C0_CLK, "peri_pll_c0", "periph_pll", NULL, 1, 0,
+	  0xB0 },
+	{ AGILEX5_PERIPH_PLL_C1_CLK, "peri_pll_c1", "periph_pll", NULL, 1, 0,
+	  0xB4 },
+	{ AGILEX5_PERIPH_PLL_C2_CLK, "peri_pll_c2", "periph_pll", NULL, 1, 0,
+	  0xB8 },
+	{ AGILEX5_PERIPH_PLL_C3_CLK, "peri_pll_c3", "periph_pll", NULL, 1, 0,
+	  0xBC },
+};
+
+/* Non-SW clock-gated enabled clocks */
+static const struct stratix10_perip_cnt_clock agilex5_main_perip_cnt_clks[] = {
+	{ AGILEX5_CORE0_FREE_CLK, "core0_free_clk", NULL, core0_free_mux,
+	ARRAY_SIZE(core0_free_mux), 0, 0x0104, 0, 0, 0},
+	{ AGILEX5_CORE1_FREE_CLK, "core1_free_clk", NULL, core1_free_mux,
+	ARRAY_SIZE(core1_free_mux), 0, 0x0104, 0, 0, 0},
+	{ AGILEX5_CORE2_FREE_CLK, "core2_free_clk", NULL, core2_free_mux,
+	ARRAY_SIZE(core2_free_mux), 0, 0x010C, 0, 0, 0},
+	{ AGILEX5_CORE3_FREE_CLK, "core3_free_clk", NULL, core3_free_mux,
+	ARRAY_SIZE(core3_free_mux), 0, 0x0110, 0, 0, 0},
+	{ AGILEX5_DSU_FREE_CLK, "dsu_free_clk", NULL, dsu_free_mux,
+	ARRAY_SIZE(dsu_free_mux), 0, 0x0100, 0, 0, 0},
+	{ AGILEX5_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux,
+	  ARRAY_SIZE(noc_free_mux), 0, 0x40, 0, 0, 0 },
+	{ AGILEX5_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux,
+	  ARRAY_SIZE(emaca_free_mux), 0, 0xD4, 0, 0x88, 0 },
+	{ AGILEX5_EMAC_B_FREE_CLK, "emacb_free_clk", NULL, emacb_free_mux,
+	  ARRAY_SIZE(emacb_free_mux), 0, 0xD8, 0, 0x88, 1 },
+	{ AGILEX5_EMAC_PTP_FREE_CLK, "emac_ptp_free_clk", NULL,
+	  emac_ptp_free_mux, ARRAY_SIZE(emac_ptp_free_mux), 0, 0xDC, 0, 0x88,
+	  2 },
+	{ AGILEX5_GPIO_DB_FREE_CLK, "gpio_db_free_clk", NULL, gpio_db_free_mux,
+	  ARRAY_SIZE(gpio_db_free_mux), 0, 0xE0, 0, 0x88, 3 },
+	{ AGILEX5_S2F_USER0_FREE_CLK, "s2f_user0_free_clk", NULL,
+	  s2f_usr0_free_mux, ARRAY_SIZE(s2f_usr0_free_mux), 0, 0xE8, 0, 0x30,
+	  2 },
+	{ AGILEX5_S2F_USER1_FREE_CLK, "s2f_user1_free_clk", NULL,
+	  s2f_usr1_free_mux, ARRAY_SIZE(s2f_usr1_free_mux), 0, 0xEC, 0, 0x88,
+	  5 },
+	{ AGILEX5_PSI_REF_FREE_CLK, "psi_ref_free_clk", NULL, psi_ref_free_mux,
+	  ARRAY_SIZE(psi_ref_free_mux), 0, 0xF0, 0, 0x88, 6 },
+	{ AGILEX5_USB31_FREE_CLK, "usb31_free_clk", NULL, usb31_free_mux,
+	  ARRAY_SIZE(usb31_free_mux), 0, 0xF8, 0, 0x88, 7},
+};
+
+/* SW Clock gate enabled clocks */
+static const struct stratix10_gate_clock agilex5_gate_clks[] = {
+
+	/* TODO HW Managed Clocks list */
+
+	/* TODO SW Managed Clocks list */
+
+	/* Main PLL0 Begin */
+	/* MPU clocks */
+	{ AGILEX5_CORE0_CLK, "core0_clk", NULL, core0_mux,
+	  ARRAY_SIZE(core0_mux), 0, 0x24, 8, 0, 0, 0, 0x30, 5, 0 },
+	{ AGILEX5_CORE1_CLK, "core1_clk", NULL, core1_mux,
+	  ARRAY_SIZE(core1_mux), 0, 0x24, 9, 0, 0, 0, 0x30, 5, 0 },
+	{ AGILEX5_CORE2_CLK, "core2_clk", NULL, core2_mux,
+	  ARRAY_SIZE(core2_mux), 0, 0x24, 10, 0, 0, 0, 0x30, 6, 0 },
+	{ AGILEX5_CORE3_CLK, "core3_clk", NULL, core3_mux,
+	  ARRAY_SIZE(core3_mux), 0, 0x24, 11, 0, 0, 0, 0x30, 7, 0 },
+	{ AGILEX5_MPU_CLK, "dsu_clk", NULL, dsu_mux, ARRAY_SIZE(dsu_mux), 0, 0,
+	  0, 0, 0, 0, 0x34, 4, 0 },
+	{ AGILEX5_MPU_PERIPH_CLK, "mpu_periph_clk", NULL, dsu_mux,
+	  ARRAY_SIZE(dsu_mux), 0, 0, 0, 0x44, 20, 2, 0x34, 4, 0 },
+	{ AGILEX5_MPU_CCU_CLK, "mpu_ccu_clk", NULL, dsu_mux,
+	  ARRAY_SIZE(dsu_mux), 0, 0, 0, 0x44, 18, 2, 0x34, 4, 0 },
+
+	/* ANGTS TODO l4 main clk has no divider now. To check. */
+	{ AGILEX5_L4_MAIN_CLK, "l4_main_clk", NULL, noc_mux,
+	  ARRAY_SIZE(noc_mux), 0, 0x24, 1, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_L4_MP_CLK, "l4_mp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0,
+	  0x24, 2, 0x44, 4, 2, 0x30, 1, 0 },
+	{ AGILEX5_L4_SYS_FREE_CLK, "l4_sys_free_clk", NULL, noc_mux,
+	  ARRAY_SIZE(noc_mux), 0, 0, 0, 0x44, 2, 2, 0x30, 1, 0 },
+	{ AGILEX5_L4_SP_CLK, "l4_sp_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux),
+	  CLK_IS_CRITICAL, 0x24, 3, 0x44, 6, 2, 0x30, 1, 0 },
+
+	/* Core sight clocks*/
+	{ AGILEX5_CS_AT_CLK, "cs_at_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0,
+	  0x24, 4, 0x44, 24, 2, 0x30, 1, 0 },
+	{ AGILEX5_CS_TRACE_CLK, "cs_trace_clk", NULL, noc_mux,
+	  ARRAY_SIZE(noc_mux), 0, 0x24, 4, 0x44, 26, 2, 0x30, 1, 0 },
+	{ AGILEX5_CS_PDBG_CLK, "cs_pdbg_clk", "cs_at_clk", NULL, 1, 0, 0x24, 4,
+	  0x44, 28, 1, 0, 0, 0 },
+	/* Main PLL0 End */
+
+	/* Main Peripheral PLL1 Begin */
+	{ AGILEX5_EMAC0_CLK, "emac0_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux),
+	  0, 0x7C, 0, 0, 0, 0, 0x94, 26, 0 },
+	{ AGILEX5_EMAC1_CLK, "emac1_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux),
+	  0, 0x7C, 1, 0, 0, 0, 0x94, 27, 0 },
+	{ AGILEX5_EMAC2_CLK, "emac2_clk", NULL, emac_mux, ARRAY_SIZE(emac_mux),
+	  0, 0x7C, 2, 0, 0, 0, 0x94, 28, 0 },
+	{ AGILEX5_EMAC_PTP_CLK, "emac_ptp_clk", NULL, emac_ptp_mux,
+	  ARRAY_SIZE(emac_ptp_mux), 0, 0x7C, 3, 0, 0, 0, 0x88, 2, 0 },
+	{ AGILEX5_GPIO_DB_CLK, "gpio_db_clk", NULL, gpio_db_mux,
+	  ARRAY_SIZE(gpio_db_mux), 0, 0x7C, 4, 0x98, 0, 16, 0x88, 3, 1 },
+	  /* Main Peripheral PLL1 End */
+
+	  /* Peripheral clocks  */
+	{ AGILEX5_S2F_USER0_CLK, "s2f_user0_clk", NULL, s2f_user0_mux,
+	  ARRAY_SIZE(s2f_user0_mux), 0, 0x24, 6, 0, 0, 0, 0x30, 2, 0 },
+	{ AGILEX5_S2F_USER1_CLK, "s2f_user1_clk", NULL, s2f_user1_mux,
+	  ARRAY_SIZE(s2f_user1_mux), 0, 0x7C, 6, 0, 0, 0, 0x88, 5, 0 },
+	{ AGILEX5_PSI_REF_CLK, "psi_ref_clk", NULL, psi_mux,
+	  ARRAY_SIZE(psi_mux), 0, 0x7C, 7, 0, 0, 0, 0x88, 6, 0 },
+	{ AGILEX5_USB31_SUSPEND_CLK, "usb31_suspend_clk", NULL, usb31_mux,
+	  ARRAY_SIZE(usb31_mux), 0, 0x7C, 25, 0, 0, 0, 0x88, 7, 0 },
+	{ AGILEX5_USB31_BUS_CLK_EARLY, "usb31_bus_clk_early", "l4_main_clk",
+	  NULL, 1, 0, 0x7C, 25, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_USB2OTG_HCLK, "usb2otg_hclk", "l4_mp_clk", NULL, 1, 0, 0x7C,
+	  8, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SPIM_0_CLK, "spim_0_clk", "l4_mp_clk", NULL, 1, 0, 0x7C, 9,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SPIM_1_CLK, "spim_1_clk", "l4_mp_clk", NULL, 1, 0, 0x7C, 11,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SPIS_0_CLK, "spis_0_clk", "l4_sp_clk", NULL, 1, 0, 0x7C, 12,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SPIS_1_CLK, "spis_1_clk", "l4_sp_clk", NULL, 1, 0, 0x7C, 13,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_DMA_CORE_CLK, "dma_core_clk", "l4_mp_clk", NULL, 1, 0, 0x7C,
+	  14, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_DMA_HS_CLK, "dma_hs_clk", "l4_mp_clk", NULL, 1, 0, 0x7C, 14,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_I3C_0_CORE_CLK, "i3c_0_core_clk", "l4_mp_clk", NULL, 1, 0,
+	  0x7C, 18, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_I3C_1_CORE_CLK, "i3c_1_core_clk", "l4_mp_clk", NULL, 1, 0,
+	  0x7C, 19, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_I2C_0_PCLK, "i2c_0_pclk", "l4_sp_clk", NULL, 1, 0, 0x7C, 15,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_I2C_1_PCLK, "i2c_1_pclk", "l4_sp_clk", NULL, 1, 0, 0x7C, 16,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_I2C_EMAC0_PCLK, "i2c_emac0_pclk", "l4_sp_clk", NULL, 1, 0,
+	  0x7C, 17, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_I2C_EMAC1_PCLK, "i2c_emac1_pclk", "l4_sp_clk", NULL, 1, 0,
+	  0x7C, 22, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_I2C_EMAC2_PCLK, "i2c_emac2_pclk", "l4_sp_clk", NULL, 1, 0,
+	  0x7C, 27, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_UART_0_PCLK, "uart_0_pclk", "l4_sp_clk", NULL, 1, 0, 0x7C, 20,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_UART_1_PCLK, "uart_1_pclk", "l4_sp_clk", NULL, 1, 0, 0x7C, 21,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SPTIMER_0_PCLK, "sptimer_0_pclk", "l4_sp_clk", NULL, 1, 0,
+	  0x7C, 23, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SPTIMER_1_PCLK, "sptimer_1_pclk", "l4_sp_clk", NULL, 1, 0,
+	  0x7C, 24, 0, 0, 0, 0, 0, 0 },
+
+	/*NAND, SD/MMC and SoftPHY overall clocking*/
+	{ AGILEX5_DFI_CLK, "dfi_clk", "l4_mp_clk", NULL, 1, 0, 0, 0, 0x44, 16,
+	  2, 0, 0, 0 },
+	{ AGILEX5_NAND_NF_CLK, "nand_nf_clk", "dfi_clk", NULL, 1, 0, 0x7C, 10,
+	  0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_NAND_BCH_CLK, "nand_bch_clk", "l4_mp_clk", NULL, 1, 0, 0x7C,
+	  10, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SDMMC_SDPHY_REG_CLK, "sdmmc_sdphy_reg_clk", "l4_mp_clk", NULL,
+	  1, 0, 0x7C, 5, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SDMCLK, "sdmclk", "dfi_clk", NULL, 1, 0, 0x7C, 5, 0, 0, 0, 0,
+	  0, 0 },
+	{ AGILEX5_SOFTPHY_REG_PCLK, "softphy_reg_pclk", "l4_mp_clk", NULL, 1, 0,
+	  0x7C, 26, 0, 0, 0, 0, 0, 0 },
+	{ AGILEX5_SOFTPHY_PHY_CLK, "softphy_phy_clk", "l4_mp_clk", NULL, 1, 0,
+	  0x7C, 26, 0x44, 16, 2, 0, 0, 0 },
+	{ AGILEX5_SOFTPHY_CTRL_CLK, "softphy_ctrl_clk", "dfi_clk", NULL, 1, 0,
+	  0x7C, 26, 0, 0, 0, 0, 0, 0 },
+};
+
+static int
+agilex5_clk_register_c_perip(const struct stratix10_perip_c_clock *clks,
+			     int nums, struct stratix10_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	void __iomem *base = data->base;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		hw_clk = s10_register_periph(&clks[i], base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+	return 0;
+}
+
+static int
+agilex5_clk_register_cnt_perip(const struct stratix10_perip_cnt_clock *clks,
+			       int nums, struct stratix10_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	void __iomem *base = data->base;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		hw_clk = s10_register_cnt_periph(&clks[i], base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+
+	return 0;
+}
+
+static int agilex5_clk_register_gate(const struct stratix10_gate_clock *clks,
+				     int nums,
+				     struct stratix10_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	void __iomem *base = data->base;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		hw_clk = agilex_register_gate(&clks[i], base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+
+	return 0;
+}
+
+static int agilex5_clk_register_pll(const struct stratix10_pll_clock *clks,
+				    int nums, struct stratix10_clock_data *data)
+{
+	struct clk_hw *hw_clk;
+	void __iomem *base = data->base;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		hw_clk = agilex5_register_pll(&clks[i], base);
+		if (IS_ERR(hw_clk)) {
+			pr_err("%s: failed to register clock %s\n", __func__,
+			       clks[i].name);
+			continue;
+		}
+		data->clk_data.hws[clks[i].id] = hw_clk;
+	}
+
+	return 0;
+}
+
+static int agilex5_clkmgr_probe(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct stratix10_clock_data *clk_data;
+	struct resource *res;
+	int i, num_clks;
+
+	res = dev_get_resource(dev, IORESOURCE_MEM, 0);
+	if (IS_ERR(res))
+		return PTR_ERR(res);
+
+	num_clks = AGILEX5_NUM_CLKS;
+
+	clk_data = xzalloc(struct_size(clk_data, clk_data.hws, num_clks));
+	if (!clk_data)
+		return -ENOMEM;
+
+	for (i = 0; i < num_clks; i++)
+		clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT);
+
+	clk_data->base = IOMEM(res->start);
+	clk_data->clk_data.num = num_clks;
+
+	agilex5_clk_register_pll(agilex5_pll_clks, ARRAY_SIZE(agilex5_pll_clks),
+				 clk_data);
+
+	agilex5_clk_register_c_perip(agilex5_main_perip_c_clks,
+				     ARRAY_SIZE(agilex5_main_perip_c_clks),
+				     clk_data);
+
+	agilex5_clk_register_cnt_perip(agilex5_main_perip_cnt_clks,
+				       ARRAY_SIZE(agilex5_main_perip_cnt_clks),
+				       clk_data);
+
+	agilex5_clk_register_gate(agilex5_gate_clks,
+				  ARRAY_SIZE(agilex5_gate_clks), clk_data);
+
+	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data->clk_data);
+	return 0;
+}
+
+static const struct of_device_id agilex5_clkmgr_match_table[] = {
+	{
+		.compatible = "intel,agilex5-clkmgr",
+	} , {
+		/* sentinel */
+	}
+};
+
+static struct driver agilex5_clkmgr_driver = {
+	.name	= "agilex5-clkmgr",
+	.of_match_table = agilex5_clkmgr_match_table,
+	.probe	= agilex5_clkmgr_probe,
+};
+
+static int __init agilex5_clk_init(void)
+{
+	return platform_driver_register(&agilex5_clkmgr_driver);
+}
+core_initcall(agilex5_clk_init);
diff --git a/drivers/clk/socfpga/clk-gate-s10.c b/drivers/clk/socfpga/clk-gate-s10.c
new file mode 100644
index 0000000000000000000000000000000000000000..2aac28c7c2d4bc24d640bcab5c6fa047123fafa0
--- /dev/null
+++ b/drivers/clk/socfpga/clk-gate-s10.c
@@ -0,0 +1,184 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017, Intel Corporation
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#include "stratix10-clk.h"
+#include "clk.h"
+
+#define SOCFPGA_CS_PDBG_CLK	"cs_pdbg_clk"
+#define to_socfpga_gate_clk(p) container_of(p, struct socfpga_gate_clk, hw)
+
+#define SOCFPGA_EMAC0_CLK		"emac0_clk"
+#define SOCFPGA_EMAC1_CLK		"emac1_clk"
+#define SOCFPGA_EMAC2_CLK		"emac2_clk"
+#define AGILEX_BYPASS_OFFSET		0xC
+#define STRATIX10_BYPASS_OFFSET		0x2C
+#define BOOTCLK_BYPASS			2
+
+static unsigned long socfpga_gate_clk_recalc_rate(struct clk_hw *hwclk,
+						  unsigned long parent_rate)
+{
+	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+	u32 div = 1, val;
+
+	if (socfpgaclk->fixed_div) {
+		div = socfpgaclk->fixed_div;
+	} else if (socfpgaclk->div_reg) {
+		val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+		val &= GENMASK(socfpgaclk->width - 1, 0);
+		div = (1 << val);
+	}
+	return parent_rate / div;
+}
+
+static unsigned long socfpga_dbg_clk_recalc_rate(struct clk_hw *hwclk,
+						  unsigned long parent_rate)
+{
+	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+	u32 div, val;
+
+	val = readl(socfpgaclk->div_reg) >> socfpgaclk->shift;
+	val &= GENMASK(socfpgaclk->width - 1, 0);
+	div = (1 << val);
+	div = div ? 4 : 1;
+
+	return parent_rate / div;
+}
+
+static int socfpga_gate_get_parent(struct clk_hw *hwclk)
+{
+	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+	u32 mask, second_bypass;
+	u8 parent = 0;
+	const char *name = clk_hw_get_name(hwclk);
+
+printk("%s: %s\n", __func__, name);
+
+	if (socfpgaclk->bypass_reg) {
+		mask = (0x1 << socfpgaclk->bypass_shift);
+		parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
+			  socfpgaclk->bypass_shift);
+printk("%s: parent %d\n", __func__, parent);
+	}
+
+	if (streq(name, SOCFPGA_EMAC0_CLK) ||
+	    streq(name, SOCFPGA_EMAC1_CLK) ||
+	    streq(name, SOCFPGA_EMAC2_CLK)) {
+		second_bypass = readl(socfpgaclk->bypass_reg -
+				      STRATIX10_BYPASS_OFFSET);
+		/* EMACA bypass to bootclk @0xB0 offset */
+		if (second_bypass & 0x1)
+			if (parent == 0) /* only applicable if parent is maca */
+				parent = BOOTCLK_BYPASS;
+
+		if (second_bypass & 0x2)
+			if (parent == 1) /* only applicable if parent is macb */
+				parent = BOOTCLK_BYPASS;
+	}
+	return parent;
+}
+
+static int socfpga_agilex_gate_get_parent(struct clk_hw *hwclk)
+{
+	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
+	u32 mask, second_bypass;
+	u8 parent = 0;
+	const char *name = clk_hw_get_name(hwclk);
+
+	if (socfpgaclk->bypass_reg) {
+		mask = (0x1 << socfpgaclk->bypass_shift);
+		parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
+			  socfpgaclk->bypass_shift);
+	}
+
+	if (streq(name, SOCFPGA_EMAC0_CLK) ||
+	    streq(name, SOCFPGA_EMAC1_CLK) ||
+	    streq(name, SOCFPGA_EMAC2_CLK)) {
+		second_bypass = readl(socfpgaclk->bypass_reg -
+				      AGILEX_BYPASS_OFFSET);
+		/* EMACA bypass to bootclk @0x88 offset */
+		if (second_bypass & 0x1)
+			if (parent == 0) /* only applicable if parent is maca */
+				parent = BOOTCLK_BYPASS;
+
+		if (second_bypass & 0x2)
+			if (parent == 1) /* only applicable if parent is macb */
+				parent = BOOTCLK_BYPASS;
+	}
+
+	return parent;
+}
+
+static struct clk_ops agilex_gateclk_ops = {
+	.recalc_rate = socfpga_gate_clk_recalc_rate,
+	.get_parent = socfpga_agilex_gate_get_parent,
+};
+
+static const struct clk_ops dbgclk_ops = {
+	.recalc_rate = socfpga_dbg_clk_recalc_rate,
+	.get_parent = socfpga_gate_get_parent,
+};
+
+struct clk_hw *agilex_register_gate(const struct stratix10_gate_clock *clks, void __iomem *regbase)
+{
+	struct clk_hw *hw_clk;
+	struct socfpga_gate_clk *socfpga_clk;
+	struct clk_init_data init;
+	const char *parent_name = clks->parent_name;
+	int ret;
+
+	socfpga_clk = kzalloc(sizeof(*socfpga_clk), GFP_KERNEL);
+	if (!socfpga_clk)
+		return NULL;
+
+	socfpga_clk->reg = regbase + clks->gate_reg;
+	socfpga_clk->bit_idx = clks->gate_idx;
+
+	agilex_gateclk_ops.enable = clk_gate_ops.enable;
+	agilex_gateclk_ops.disable = clk_gate_ops.disable;
+
+	socfpga_clk->fixed_div = clks->fixed_div;
+
+	if (clks->div_reg)
+		socfpga_clk->div_reg = regbase + clks->div_reg;
+	else
+		socfpga_clk->div_reg = NULL;
+
+	socfpga_clk->width = clks->div_width;
+	socfpga_clk->shift = clks->div_offset;
+
+	if (clks->bypass_reg)
+		socfpga_clk->bypass_reg = regbase + clks->bypass_reg;
+	else
+		socfpga_clk->bypass_reg = NULL;
+	socfpga_clk->bypass_shift = clks->bypass_shift;
+
+	if (streq(clks->name, "cs_pdbg_clk"))
+		init.ops = &dbgclk_ops;
+	else
+		init.ops = &agilex_gateclk_ops;
+	init.name = clks->name;
+	init.flags = clks->flags;
+
+	init.num_parents = clks->num_parents;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	if (init.parent_names == NULL)
+		init.parent_data = clks->parent_data;
+	socfpga_clk->hw.init = &init;
+
+	hw_clk = &socfpga_clk->hw;
+
+	ret = clk_hw_register(NULL, &socfpga_clk->hw);
+	if (ret) {
+		kfree(socfpga_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
diff --git a/drivers/clk/socfpga/clk-periph-s10.c b/drivers/clk/socfpga/clk-periph-s10.c
new file mode 100644
index 0000000000000000000000000000000000000000..68f9d4bc80af5587666e1a4900362eba290ef4f4
--- /dev/null
+++ b/drivers/clk/socfpga/clk-periph-s10.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017, Intel Corporation
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <linux/clk-provider.h>
+
+#include "stratix10-clk.h"
+#include "clk.h"
+
+#define CLK_MGR_FREE_SHIFT		16
+#define CLK_MGR_FREE_MASK		0x7
+#define SWCTRLBTCLKSEN_SHIFT		8
+
+#define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw)
+
+static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
+					     unsigned long parent_rate)
+{
+	struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
+	unsigned long div = 1;
+	u32 val;
+
+	val = readl(socfpgaclk->reg);
+	val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0);
+	parent_rate /= val;
+
+	return parent_rate / div;
+}
+
+static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
+					     unsigned long parent_rate)
+{
+	struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
+	unsigned long div = 1;
+
+	if (socfpgaclk->fixed_div) {
+		div = socfpgaclk->fixed_div;
+	} else {
+		if (socfpgaclk->reg)
+			div = ((readl(socfpgaclk->reg) & 0x7ff) + 1);
+	}
+
+	return parent_rate / div;
+}
+
+static int clk_periclk_get_parent(struct clk_hw *hwclk)
+{
+	struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
+	u32 clk_src, mask;
+	u8 parent = 0;
+
+	/* handle the bypass first */
+	if (socfpgaclk->bypass_reg) {
+		mask = (0x1 << socfpgaclk->bypass_shift);
+		parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
+			   socfpgaclk->bypass_shift);
+		if (parent)
+			return parent;
+	}
+
+	if (socfpgaclk->reg) {
+		clk_src = readl(socfpgaclk->reg);
+		parent = (clk_src >> CLK_MGR_FREE_SHIFT) &
+			  CLK_MGR_FREE_MASK;
+	}
+	return parent;
+}
+
+static const struct clk_ops peri_c_clk_ops = {
+	.recalc_rate = clk_peri_c_clk_recalc_rate,
+	.get_parent = clk_periclk_get_parent,
+};
+
+static const struct clk_ops peri_cnt_clk_ops = {
+	.recalc_rate = clk_peri_cnt_clk_recalc_rate,
+	.get_parent = clk_periclk_get_parent,
+};
+
+struct clk_hw *s10_register_periph(const struct stratix10_perip_c_clock *clks,
+				void __iomem *reg)
+{
+	struct clk_hw *hw_clk;
+	struct socfpga_periph_clk *periph_clk;
+	struct clk_init_data init;
+	const char *name = clks->name;
+	const char *parent_name = clks->parent_name;
+	int ret;
+
+	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
+	if (WARN_ON(!periph_clk))
+		return NULL;
+
+	periph_clk->reg = reg + clks->offset;
+
+	init.name = name;
+	init.ops = &peri_c_clk_ops;
+	init.flags = clks->flags;
+
+	init.num_parents = clks->num_parents;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	if (init.parent_names == NULL)
+		init.parent_data = clks->parent_data;
+
+	periph_clk->hw.init = &init;
+	hw_clk = &periph_clk->hw;
+
+	ret = clk_hw_register(NULL, hw_clk);
+	if (ret) {
+		kfree(periph_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
+
+struct clk_hw *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,
+				    void __iomem *regbase)
+{
+	struct clk_hw *hw_clk;
+	struct socfpga_periph_clk *periph_clk;
+	struct clk_init_data init;
+	const char *name = clks->name;
+	const char *parent_name = clks->parent_name;
+	int ret;
+
+	periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
+	if (WARN_ON(!periph_clk))
+		return NULL;
+
+	if (clks->offset)
+		periph_clk->reg = regbase + clks->offset;
+	else
+		periph_clk->reg = NULL;
+
+	if (clks->bypass_reg)
+		periph_clk->bypass_reg = regbase + clks->bypass_reg;
+	else
+		periph_clk->bypass_reg = NULL;
+	periph_clk->bypass_shift = clks->bypass_shift;
+	periph_clk->fixed_div = clks->fixed_divider;
+
+	init.name = name;
+	init.ops = &peri_cnt_clk_ops;
+	init.flags = clks->flags;
+
+	init.num_parents = clks->num_parents;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	if (init.parent_names == NULL)
+		init.parent_data = clks->parent_data;
+
+	periph_clk->hw.init = &init;
+	hw_clk = &periph_clk->hw;
+
+	ret = clk_hw_register(NULL, hw_clk);
+	if (ret) {
+		kfree(periph_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
diff --git a/drivers/clk/socfpga/clk-pll-s10.c b/drivers/clk/socfpga/clk-pll-s10.c
new file mode 100644
index 0000000000000000000000000000000000000000..59e5ec33b06b6cf634b353bf6d6fe4d345171550
--- /dev/null
+++ b/drivers/clk/socfpga/clk-pll-s10.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017, Intel Corporation
+ */
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#include "stratix10-clk.h"
+#include "clk.h"
+
+/* Clock Manager offsets */
+#define CLK_MGR_PLL_CLK_SRC_SHIFT	16
+#define CLK_MGR_PLL_CLK_SRC_MASK	0x3
+
+/* PLL Clock enable bits */
+#define SOCFPGA_PLL_POWER		0
+#define SOCFPGA_PLL_RESET_MASK		0x2
+#define SOCFPGA_PLL_REFDIV_MASK		0x00003F00
+#define SOCFPGA_PLL_REFDIV_SHIFT	8
+#define SOCFPGA_PLL_AREFDIV_MASK	0x00000F00
+#define SOCFPGA_PLL_DREFDIV_MASK	0x00003000
+#define SOCFPGA_PLL_DREFDIV_SHIFT	12
+#define SOCFPGA_PLL_MDIV_MASK		0xFF000000
+#define SOCFPGA_PLL_MDIV_SHIFT		24
+#define SOCFPGA_AGILEX_PLL_MDIV_MASK	0x000003FF
+#define SWCTRLBTCLKSEL_MASK		0x200
+#define SWCTRLBTCLKSEL_SHIFT		9
+
+#define SOCFPGA_BOOT_CLK		"boot_clk"
+
+#define to_socfpga_clk(p) container_of(p, struct socfpga_pll, hw)
+
+static unsigned long agilex_clk_pll_recalc_rate(struct clk_hw *hwclk,
+						unsigned long parent_rate)
+{
+	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+	unsigned long arefdiv, reg, mdiv;
+	unsigned long long vco_freq;
+
+	/* read VCO1 reg for numerator and denominator */
+	reg = readl(socfpgaclk->reg);
+	arefdiv = (reg & SOCFPGA_PLL_AREFDIV_MASK) >> SOCFPGA_PLL_REFDIV_SHIFT;
+
+	vco_freq = (unsigned long long)parent_rate / arefdiv;
+
+	/* Read mdiv and fdiv from the fdbck register */
+	reg = readl(socfpgaclk->reg + 0x24);
+	mdiv = reg & SOCFPGA_AGILEX_PLL_MDIV_MASK;
+
+	vco_freq = (unsigned long long)vco_freq * mdiv;
+	return (unsigned long)vco_freq;
+}
+
+static unsigned long clk_boot_clk_recalc_rate(struct clk_hw *hwclk,
+					 unsigned long parent_rate)
+{
+	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+	u32 div;
+
+	div = ((readl(socfpgaclk->reg) &
+		SWCTRLBTCLKSEL_MASK) >>
+		SWCTRLBTCLKSEL_SHIFT);
+	div += 1;
+	return parent_rate / div;
+}
+
+static int clk_pll_get_parent(struct clk_hw *hwclk)
+{
+	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+	u32 pll_src;
+
+	pll_src = readl(socfpgaclk->reg);
+	return (pll_src >> CLK_MGR_PLL_CLK_SRC_SHIFT) &
+		CLK_MGR_PLL_CLK_SRC_MASK;
+}
+
+static int clk_boot_get_parent(struct clk_hw *hwclk)
+{
+	struct socfpga_pll *socfpgaclk = to_socfpga_clk(hwclk);
+	u32 pll_src;
+
+	pll_src = readl(socfpgaclk->reg);
+	return (pll_src >> SWCTRLBTCLKSEL_SHIFT) &
+		SWCTRLBTCLKSEL_MASK;
+}
+
+/* TODO need to fix, Agilex5 SM requires change */
+static const struct clk_ops agilex5_clk_pll_ops = {
+	/* TODO This may require a custom Agilex5 implementation */
+	.recalc_rate = agilex_clk_pll_recalc_rate,
+	.get_parent = clk_pll_get_parent,
+};
+
+static const struct clk_ops clk_boot_ops = {
+	.recalc_rate = clk_boot_clk_recalc_rate,
+	.get_parent = clk_boot_get_parent,
+};
+
+struct clk_hw *agilex5_register_pll(const struct stratix10_pll_clock *clks,
+				void __iomem *reg)
+{
+	struct clk_hw *hw_clk;
+	struct socfpga_pll *pll_clk;
+	struct clk_init_data init;
+	const char *name = clks->name;
+	int ret;
+
+	pll_clk = xzalloc(sizeof(*pll_clk));
+	if (!pll_clk)
+		return ERR_PTR(-ENOMEM);
+
+	pll_clk->reg = reg + clks->offset;
+
+	if (streq(name, SOCFPGA_BOOT_CLK))
+		init.ops = &clk_boot_ops;
+	else
+		init.ops = &agilex5_clk_pll_ops;
+
+	init.name = name;
+	init.flags = clks->flags;
+
+	init.num_parents = clks->num_parents;
+	init.parent_names = NULL;
+	init.parent_data = clks->parent_data;
+	pll_clk->hw.init = &init;
+
+	pll_clk->bit_idx = SOCFPGA_PLL_POWER;
+	hw_clk = &pll_clk->hw;
+
+	ret = clk_hw_register(NULL, hw_clk);
+	if (ret) {
+		kfree(pll_clk);
+		return ERR_PTR(ret);
+	}
+	return hw_clk;
+}
+
diff --git a/drivers/clk/socfpga/clk.h b/drivers/clk/socfpga/clk.h
index 402f714436ab2f94dc5ecbad244915f0fa1c6194..19fc45e7f639583342b37422f30762d673421760 100644
--- a/drivers/clk/socfpga/clk.h
+++ b/drivers/clk/socfpga/clk.h
@@ -20,6 +20,11 @@
 #define SOCFPGA_MAX_PARENTS		5
 
 #define streq(a, b) (strcmp((a), (b)) == 0)
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel) \
+	((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
+
+#define SYSMGR_SDMMC_CTRL_SET_AS10(smplsel, drvsel) \
+	((((smplsel) & 0x7) << 4) | (((drvsel) & 0x7) << 0))
 
 extern void __iomem *clk_mgr_base_addr;
 
@@ -58,11 +63,13 @@ struct socfpga_gate_clk {
 	char *parent_name;
 	u32 fixed_div;
 	void __iomem *div_reg;
+	void __iomem *bypass_reg;
 	struct regmap *sys_mgr_base_addr;
 	u32 width;	/* only valid if div_reg != 0 */
 	u32 shift;	/* only valid if div_reg != 0 */
 	u32 bit_idx;
 	void __iomem *reg;
+	u32 bypass_shift;      /* only valid if bypass_reg != 0 */
 	u32 clk_phase[2];
 	const char *parent_names[SOCFPGA_MAX_PARENTS];
 };
@@ -73,8 +80,10 @@ struct socfpga_periph_clk {
 	char *parent_name;
 	u32 fixed_div;
 	void __iomem *div_reg;
+	void __iomem *bypass_reg;
 	u32 width;      /* only valid if div_reg != 0 */
 	u32 shift;      /* only valid if div_reg != 0 */
+	u32 bypass_shift;      /* only valid if bypass_reg != 0 */
 	const char *parent_names[SOCFPGA_MAX_PARENTS];
 };
 
diff --git a/drivers/clk/socfpga/stratix10-clk.h b/drivers/clk/socfpga/stratix10-clk.h
new file mode 100644
index 0000000000000000000000000000000000000000..1fe025f65f7a05faf00efc3991d2afc9c564d5ca
--- /dev/null
+++ b/drivers/clk/socfpga/stratix10-clk.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier:    GPL-2.0 */
+/*
+ * Copyright (C) 2017, Intel Corporation
+ */
+
+#ifndef	__STRATIX10_CLK_H
+#define	__STRATIX10_CLK_H
+
+struct stratix10_clock_data {
+	void __iomem		*base;
+
+	/* Must be last */
+	struct clk_hw_onecell_data	clk_data;
+};
+
+struct stratix10_pll_clock {
+	unsigned int		id;
+	const char		*name;
+	const struct clk_parent_data	*parent_data;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+};
+
+struct stratix10_perip_c_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	const struct clk_parent_data	*parent_data;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+};
+
+struct stratix10_perip_cnt_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	const struct clk_parent_data	*parent_data;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			fixed_divider;
+	unsigned long		bypass_reg;
+	unsigned long		bypass_shift;
+};
+
+struct stratix10_gate_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	const struct clk_parent_data	*parent_data;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		gate_reg;
+	u8			gate_idx;
+	unsigned long		div_reg;
+	u8			div_offset;
+	u8			div_width;
+	unsigned long		bypass_reg;
+	u8			bypass_shift;
+	u8			fixed_div;
+};
+
+struct clk_hw *agilex5_register_pll(const struct stratix10_pll_clock *clks,
+				void __iomem *reg);
+struct clk_hw *s10_register_periph(const struct stratix10_perip_c_clock *clks,
+				void __iomem *reg);
+struct clk_hw *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,
+				    void __iomem *reg);
+struct clk_hw *agilex_register_gate(const struct stratix10_gate_clock *clks,
+			      void __iomem *reg);
+#endif	/* __STRATIX10_CLK_H */

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:31 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:31 +0100
Subject: [PATCH v2 06/10] clk: support init->parent_data
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-6-30b6f507810b@pengutronix.de>

Linux clk driver supports matching parents via init->parent_data instead
of init->parent_names.

Add support for this feature to barebox, too.
Linux however supports setting a "name" and "fw_name" for a parent
clock. "fw_name" is a local name for the provider registering the clock
and "name" is a globally unique parent name. For the time being, only
support the globally unique "name" field.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/clk/clk.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 40 insertions(+), 8 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index bd368782804c9a2cce1ced7826501363c0c2ab2d..be4060e6d5a0d7ecbed729b4d96570d7980f5857 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -476,11 +476,28 @@ int bclk_register(struct clk *clk)
 	return ret;
 }
 
+static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist)
+{
+	const char *dst;
+
+	if (!src) {
+		if (must_exist)
+			return -EINVAL;
+		return 0;
+	}
+
+	*dst_p = dst = xstrdup(src);
+	if (!dst)
+		return -ENOMEM;
+
+	return 0;
+}
+
 struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 {
 	struct clk *clk;
 	const struct clk_init_data *init = hw->init;
-	char **parent_names = NULL;
+	const char **parent_names = NULL;
 	int i, ret;
 
 	if (!hw->init)
@@ -496,14 +513,29 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 
 	clk->parents = xzalloc(sizeof(struct clk *) * clk->num_parents);
 
-	if (init->parent_names) {
+	if (init->parent_names || init->parent_data) {
 		parent_names = xzalloc(init->num_parents * sizeof(char *));
 
-		for (i = 0; i < init->num_parents; i++)
-			parent_names[i] = xstrdup(init->parent_names[i]);
-
-		clk->parent_names = (const char *const*)parent_names;
-
+		for (i = 0; i < init->num_parents; i++) {
+			if (init->parent_names) {
+				ret = clk_cpy_name(&parent_names[i],
+						   init->parent_names[i], true);
+			} else if (init->parent_data) {
+				/* Linux copies fw_name and if successful also name.
+				 * As fw_name is not handled in barebox, just copy the
+				 * name field and fallback to hw->clk.name if it doesn't
+				 * exist.
+				 */
+				ret = clk_cpy_name(&parent_names[i],
+						   init->parent_data[i].name,
+						   true);
+				if (ret)
+					ret = clk_cpy_name(&parent_names[i],
+							   init->parent_data[i].hw->clk.name,
+							   false);
+			}
+		}
+		clk->parent_names = (const char *const *)parent_names;
 	} else {
 		for (i = 0; i < init->num_parents; i++)
 			clk->parents[i] = clk_hw_to_clk(init->parent_hws[i]);
@@ -515,7 +547,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 	if (ret) {
 		if (parent_names) {
 			for (i = 0; i < init->num_parents; i++)
-				free(parent_names[i]);
+				free(&parent_names[i]);
 			free(parent_names);
 		}
 		free(clk->parents);

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:34 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:34 +0100
Subject: [PATCH v2 09/10] net: add support for Designware XGMAC (10gb)
 ethernet
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-9-30b6f507810b@pengutronix.de>

The Designware XGMAC is designed for 1/2.5/5/10G ethernet applications.
It is mostly identical to the eqos driver but has a different register
layout.

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 drivers/net/Kconfig                    |  18 +
 drivers/net/Makefile                   |   2 +
 drivers/net/designware_xgmac.c         | 856 +++++++++++++++++++++++++++++++++
 drivers/net/designware_xgmac.h         | 298 ++++++++++++
 drivers/net/designware_xgmac_socfpga.c | 156 ++++++
 5 files changed, 1330 insertions(+)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 25f4f337394cbbcff5d88e428080843f0346d3a8..b03b6a5757de10332c737bb11549af590aea4efd 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -157,6 +157,24 @@ config DRIVER_NET_DESIGNWARE_ROCKCHIP
 	help
 	  This option enables support for the Ethernet MAC on different Rockchip SoCs
 
+config DRIVER_NET_DESIGNWARE_XGMAC
+	bool "Designware XGMAC Ethernet driver support" if COMPILE_TEST
+	depends on HAS_DMA && OFTREE
+	select PHYLIB
+	select MFD_SYSCON
+	help
+	  This option enables support for the Synopsys Designware Ethernet XGMAC (10G Ethernet MAC).
+
+config DRIVER_NET_DESIGNWARE_XGMAC_SOCFPGA
+	bool "Designware XGMAC Ethernet driver support for SOCFPGA"
+	select DRIVER_NET_DESIGNWARE_XGMAC
+	depends on (ARCH_SOCFPGA_AGILEX5 || COMPILE_TEST)
+	select RESET_CONTROLLER if ARCH_SOCFPGA
+	select RESET_SIMPLE if ARCH_SOCFPGA_AGILEX5
+	help
+	  This option enables support for the Synopsys Designware Ethernet XGMAC with specific configuration
+	  for the Intel SoC FPGA chip.
+
 config DRIVER_NET_DM9K
 	bool "Davicom dm9k[E|A|B] ethernet driver"
 	depends on HAS_DM9000 || COMPILE_TEST
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b66131632d5773f59fb35f3efac6f8c919f296f8..37b720635a38dc6d447982f935962b9065899258 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -21,6 +21,8 @@ obj-$(CONFIG_DRIVER_NET_DESIGNWARE_IMX8) += designware_imx.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE_STM32) += designware_stm32.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE_TEGRA186) += designware_tegra186.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE_ROCKCHIP) += designware_rockchip.o
+obj-$(CONFIG_DRIVER_NET_DESIGNWARE_XGMAC) += designware_xgmac.o
+obj-$(CONFIG_DRIVER_NET_DESIGNWARE_XGMAC_SOCFPGA) += designware_xgmac_socfpga.o
 obj-$(CONFIG_DRIVER_NET_DM9K)		+= dm9k.o
 obj-$(CONFIG_DRIVER_NET_E1000)		+= e1000/
 obj-$(CONFIG_DRIVER_NET_ENC28J60)	+= enc28j60.o
diff --git a/drivers/net/designware_xgmac.c b/drivers/net/designware_xgmac.c
new file mode 100644
index 0000000000000000000000000000000000000000..ca79ab4cb4a39c053fff0df13f587cbde9c2e6e7
--- /dev/null
+++ b/drivers/net/designware_xgmac.c
@@ -0,0 +1,856 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Intel Corporation.
+ *
+ * Portions based on U-Boot's dwc_eth_qos.c.
+ */
+
+/*
+ * This driver supports the Synopsys Designware Ethernet XGMAC (10G Ethernet
+ * MAC) IP block. The IP supports multiple options for bus type, clocking/
+ * reset structure, and feature list.
+ *
+ * The driver is written such that generic core logic is kept separate from
+ * configuration-specific logic. Code that interacts with configuration-
+ * specific resources is split out into separate functions to avoid polluting
+ * common code. If/when this driver is enhanced to support multiple
+ * configurations, the core code should be adapted to call all configuration-
+ * specific functions through function pointers, with the definition of those
+ * function pointers being supplied by struct udevice_id xgmac_ids[]'s .data
+ * field.
+ *
+ * This configuration uses an AXI master/DMA bus, an AHB slave/register bus,
+ * contains the DMA, MTL, and MAC sub-blocks, and supports a single RGMII PHY.
+ * This configuration also has SW control over all clock and reset signals to
+ * the HW block.
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <dma.h>
+#include <errno.h>
+#include <gpio.h>
+#include <malloc.h>
+#include <net.h>
+#include <of_gpio.h>
+#include <of_net.h>
+#include <linux/iopoll.h>
+#include <linux/phy.h>
+#include <asm/cache.h>
+#include "designware_xgmac.h"
+
+static int xgmac_mdio_wait_idle(struct xgmac_priv *xgmac)
+{
+	u32 idle;
+
+	return readl_poll_timeout(&xgmac->mac_regs->mdio_data, idle,
+				  !(idle & XGMAC_MAC_MDIO_ADDRESS_SBUSY),
+				  XGMAC_TIMEOUT_100MS);
+}
+
+static int xgmac_mdio_read(struct mii_bus *bus, int mdio_addr, int mdio_reg)
+{
+	struct xgmac_priv *xgmac = bus->priv;
+	u32 val;
+	u32 hw_addr;
+	u32 idle;
+	int ret;
+
+	ret = readl_poll_timeout(&xgmac->mac_regs->mdio_data, idle,
+				 !(idle & XGMAC_MAC_MDIO_ADDRESS_SBUSY),
+				 XGMAC_TIMEOUT_100MS);
+	if (ret) {
+		dev_err(xgmac->dev, "MDIO not idle at entry: %d\n", ret);
+		return ret;
+	}
+
+	/* Set clause 22 format */
+	val = BIT(mdio_addr);
+	writel(val, &xgmac->mac_regs->mdio_clause_22_port);
+
+	hw_addr = (mdio_addr << XGMAC_MAC_MDIO_ADDRESS_PA_SHIFT) |
+		   (mdio_reg & XGMAC_MAC_MDIO_REG_ADDR_C22P_MASK);
+
+	val = xgmac->config->config_mac_mdio <<
+	      XGMAC_MAC_MDIO_ADDRESS_CR_SHIFT;
+
+	val |= XGMAC_MAC_MDIO_ADDRESS_SADDR |
+	       XGMAC_MDIO_SINGLE_CMD_ADDR_CMD_READ |
+	       XGMAC_MAC_MDIO_ADDRESS_SBUSY;
+
+	ret = readl_poll_timeout(&xgmac->mac_regs->mdio_data, idle,
+				 !(idle & XGMAC_MAC_MDIO_ADDRESS_SBUSY),
+				 XGMAC_TIMEOUT_100MS);
+	if (ret) {
+		dev_err(xgmac->dev, "MDIO not idle at entry: %d\n", ret);
+		return ret;
+	}
+
+	writel(hw_addr, &xgmac->mac_regs->mdio_address);
+	writel(val, &xgmac->mac_regs->mdio_data);
+
+	ret = readl_poll_timeout(&xgmac->mac_regs->mdio_data, idle,
+				 !(idle & XGMAC_MAC_MDIO_ADDRESS_SBUSY),
+				 XGMAC_TIMEOUT_100MS);
+	if (ret) {
+		dev_err(xgmac->dev, "MDIO read didn't complete: %d\n", ret);
+		return ret;
+	}
+
+	val = readl(&xgmac->mac_regs->mdio_data);
+	val &= XGMAC_MAC_MDIO_DATA_GD_MASK;
+
+	return val;
+}
+
+static int xgmac_mdio_write(struct mii_bus *bus, int mdio_addr, int mdio_reg,
+			    u16 mdio_val)
+{
+	struct xgmac_priv *xgmac = bus->priv;
+	u32 val;
+	u32 hw_addr;
+	int ret;
+
+	ret = xgmac_mdio_wait_idle(xgmac);
+	if (ret) {
+		dev_err(xgmac->dev, "MDIO not idle at entry: %d\n", ret);
+		return ret;
+	}
+
+	/* Set clause 22 format */
+	val = BIT(mdio_addr);
+	writel(val, &xgmac->mac_regs->mdio_clause_22_port);
+
+	hw_addr = (mdio_addr << XGMAC_MAC_MDIO_ADDRESS_PA_SHIFT) |
+		   (mdio_reg & XGMAC_MAC_MDIO_REG_ADDR_C22P_MASK);
+
+	hw_addr |= (mdio_reg >> XGMAC_MAC_MDIO_ADDRESS_PA_SHIFT) <<
+		    XGMAC_MAC_MDIO_ADDRESS_DA_SHIFT;
+
+	val = (xgmac->config->config_mac_mdio <<
+	       XGMAC_MAC_MDIO_ADDRESS_CR_SHIFT);
+
+	val |= XGMAC_MAC_MDIO_ADDRESS_SADDR |
+		mdio_val | XGMAC_MDIO_SINGLE_CMD_ADDR_CMD_WRITE |
+		XGMAC_MAC_MDIO_ADDRESS_SBUSY;
+
+	ret = xgmac_mdio_wait_idle(xgmac);
+	if (ret) {
+		dev_err(xgmac->dev, "MDIO not idle at entry: %d\n", ret);
+		return ret;
+	}
+
+	writel(hw_addr, &xgmac->mac_regs->mdio_address);
+	writel(val, &xgmac->mac_regs->mdio_data);
+
+	ret = xgmac_mdio_wait_idle(xgmac);
+	if (ret) {
+		dev_err(xgmac->dev, "MDIO write didn't complete: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int xgmac_set_full_duplex(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	clrbits_le32(&xgmac->mac_regs->mac_extended_conf, XGMAC_MAC_EXT_CONF_HD);
+
+	return 0;
+}
+
+static int xgmac_set_half_duplex(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	setbits_le32(&xgmac->mac_regs->mac_extended_conf, XGMAC_MAC_EXT_CONF_HD);
+
+	/* WAR: Flush TX queue when switching to half-duplex */
+	setbits_le32(&xgmac->mtl_regs->txq0_operation_mode,
+		     XGMAC_MTL_TXQ0_OPERATION_MODE_FTQ);
+
+	return 0;
+}
+
+static int xgmac_set_gmii_speed(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	clrsetbits_le32(&xgmac->mac_regs->tx_configuration,
+			XGMAC_MAC_CONF_SS_SHIFT_MASK,
+			XGMAC_MAC_CONF_SS_1G_GMII << XGMAC_MAC_CONF_SS_SHIFT);
+
+	return 0;
+}
+
+static int xgmac_set_mii_speed_100(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	clrsetbits_le32(&xgmac->mac_regs->tx_configuration,
+			XGMAC_MAC_CONF_SS_SHIFT_MASK,
+			XGMAC_MAC_CONF_SS_100M_MII << XGMAC_MAC_CONF_SS_SHIFT);
+
+	return 0;
+}
+
+static int xgmac_set_mii_speed_10(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	clrsetbits_le32(&xgmac->mac_regs->tx_configuration,
+			XGMAC_MAC_CONF_SS_SHIFT_MASK,
+			XGMAC_MAC_CONF_SS_2_10M_MII << XGMAC_MAC_CONF_SS_SHIFT);
+
+	return 0;
+}
+
+static void xgmac_adjust_link(struct eth_device *edev)
+{
+	struct device *dev = edev->parent;
+	bool en_calibration;
+	int ret;
+
+	if (edev->phydev->duplex)
+		ret = xgmac_set_full_duplex(dev);
+	else
+		ret = xgmac_set_half_duplex(dev);
+	if (ret < 0) {
+		dev_err(dev, "xgmac_set_*_duplex() failed: %d\n", ret);
+	}
+
+	switch (edev->phydev->speed) {
+	case SPEED_1000:
+		en_calibration = true;
+		ret = xgmac_set_gmii_speed(dev);
+		break;
+	case SPEED_100:
+		en_calibration = true;
+		ret = xgmac_set_mii_speed_100(dev);
+		break;
+	case SPEED_10:
+		en_calibration = false;
+		ret = xgmac_set_mii_speed_10(dev);
+		break;
+	default:
+		dev_err(dev, "invalid speed %d\n", edev->phydev->speed);
+	}
+	if (ret < 0)
+		dev_err(dev, "xgmac_set_*mii_speed*() failed: %d\n", ret);
+}
+
+static int xgmac_write_hwaddr(struct eth_device *edev, const unsigned char *mac)
+{
+	struct xgmac_priv *xgmac = edev->priv;
+	u32 val;
+
+	memcpy(xgmac->macaddr, mac, ETH_ALEN);
+
+	/*
+	 * This function may be called before start() or after stop(). At that
+	 * time, on at least some configurations of the XGMAC HW, all clocks to
+	 * the XGMAC HW block will be stopped, and a reset signal applied. If
+	 * any register access is attempted in this state, bus timeouts or CPU
+	 * hangs may occur. This check prevents that.
+	 *
+	 * A simple solution to this problem would be to not implement
+	 * write_hwaddr(), since start() always writes the MAC address into HW
+	 * anyway. However, it is desirable to implement write_hwaddr() to
+	 * support the case of SW that runs subsequent to U-Boot which expects
+	 * the MAC address to already be programmed into the XGMAC registers,
+	 * which must happen irrespective of whether the U-Boot user (or
+	 * scripts) actually made use of the XGMAC device, and hence
+	 * irrespective of whether start() was ever called.
+	 *
+	 */
+	if (!xgmac->config->reg_access_always_ok && !xgmac->reg_access_ok)
+		return 0;
+
+	/* Update the MAC address */
+	val = (xgmac->macaddr[5] << 8) |
+		(xgmac->macaddr[4]);
+	writel(val, &xgmac->mac_regs->address0_high);
+	val = (xgmac->macaddr[3] << 24) |
+		(xgmac->macaddr[2] << 16) |
+		(xgmac->macaddr[1] << 8) |
+		(xgmac->macaddr[0]);
+	writel(val, &xgmac->mac_regs->address0_low);
+	return 0;
+}
+
+static int xgmac_read_rom_hwaddr(struct eth_device *edev, unsigned char *mac)
+{
+	struct xgmac_priv *xgmac = edev->priv;
+	int ret;
+
+	ret = xgmac->config->ops->xgmac_get_enetaddr(edev->parent);
+	if (ret < 0)
+		return ret;
+
+	return !is_valid_ether_addr(xgmac->macaddr);
+}
+
+static int xgmac_start(struct eth_device *edev)
+{
+	struct xgmac_priv *xgmac = edev->priv;
+	int ret, i;
+	u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl;
+	ulong last_rx_desc;
+	ulong desc_pad;
+	u32 idle;
+
+	ret = phy_device_connect(edev, &xgmac->miibus, xgmac->phy_addr,
+				 xgmac_adjust_link, 0, xgmac->interface);
+	if (ret)
+		return ret;
+
+	ret = xgmac->config->ops->xgmac_start_resets(edev->parent);
+	if (ret < 0) {
+		dev_err(&edev->dev, "xgmac_start_resets() failed: %d\n", ret);
+		goto err;
+	}
+
+	xgmac->reg_access_ok = true;
+
+	setbits_le32(&xgmac->dma_regs->mode, XGMAC_DMA_MODE_SWR);
+
+	ret = readl_poll_timeout(&xgmac->dma_regs->mode, idle,
+				  !(idle & XGMAC_DMA_MODE_SWR),
+				  XGMAC_TIMEOUT_100MS);
+	if (ret) {
+		dev_err(&edev->dev, "XGMAC_DMA_MODE_SWR stuck: %d\n", ret);
+		goto err;
+	}
+
+	/* Configure MTL */
+
+	/* Enable Store and Forward mode for TX */
+	/* Program Tx operating mode */
+	setbits_le32(&xgmac->mtl_regs->txq0_operation_mode,
+		     XGMAC_MTL_TXQ0_OPERATION_MODE_TSF |
+		     (XGMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED <<
+		      XGMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT));
+
+	/* Transmit Queue weight */
+	writel(0x10, &xgmac->mtl_regs->txq0_quantum_weight);
+
+	/* Enable Store and Forward mode for RX, since no jumbo frame */
+	setbits_le32(&xgmac->mtl_regs->rxq0_operation_mode,
+		     XGMAC_MTL_RXQ0_OPERATION_MODE_RSF);
+
+	/* Transmit/Receive queue fifo size; use all RAM for 1 queue */
+	val = readl(&xgmac->mac_regs->hw_feature1);
+	tx_fifo_sz = (val >> XGMAC_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT) &
+		XGMAC_MAC_HW_FEATURE1_TXFIFOSIZE_MASK;
+	rx_fifo_sz = (val >> XGMAC_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT) &
+		XGMAC_MAC_HW_FEATURE1_RXFIFOSIZE_MASK;
+
+	/*
+	 * r/tx_fifo_sz is encoded as log2(n / 128). Undo that by shifting.
+	 * r/tqs is encoded as (n / 256) - 1.
+	 */
+	tqs = (128 << tx_fifo_sz) / 256 - 1;
+	rqs = (128 << rx_fifo_sz) / 256 - 1;
+
+	clrsetbits_le32(&xgmac->mtl_regs->txq0_operation_mode,
+			XGMAC_MTL_TXQ0_OPERATION_MODE_TQS_MASK <<
+			XGMAC_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT,
+			tqs << XGMAC_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT);
+	clrsetbits_le32(&xgmac->mtl_regs->rxq0_operation_mode,
+			XGMAC_MTL_RXQ0_OPERATION_MODE_RQS_MASK <<
+			XGMAC_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT,
+			rqs << XGMAC_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT);
+
+	setbits_le32(&xgmac->mtl_regs->rxq0_operation_mode,
+		     XGMAC_MTL_RXQ0_OPERATION_MODE_EHFC);
+
+	/* Configure MAC */
+	clrsetbits_le32(&xgmac->mac_regs->rxq_ctrl0,
+			XGMAC_MAC_RXQ_CTRL0_RXQ0EN_MASK <<
+			XGMAC_MAC_RXQ_CTRL0_RXQ0EN_SHIFT,
+			xgmac->config->config_mac <<
+			XGMAC_MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
+
+	/* Multicast and Broadcast Queue Enable */
+	setbits_le32(&xgmac->mac_regs->rxq_ctrl1,
+		     XGMAC_MAC_RXQ_CTRL1_MCBCQEN);
+
+	/* enable promisc mode and receive all mode */
+	setbits_le32(&xgmac->mac_regs->mac_packet_filter,
+		     XGMAC_MAC_PACKET_FILTER_RA |
+			 XGMAC_MAC_PACKET_FILTER_PR);
+
+	/* Set TX flow control parameters */
+	/* Set Pause Time */
+	setbits_le32(&xgmac->mac_regs->q0_tx_flow_ctrl,
+		     XGMAC_MAC_Q0_TX_FLOW_CTRL_PT_MASK <<
+		     XGMAC_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT);
+
+	/* Assign priority for RX flow control */
+	clrbits_le32(&xgmac->mac_regs->rxq_ctrl2,
+		     XGMAC_MAC_RXQ_CTRL2_PSRQ0_MASK <<
+		     XGMAC_MAC_RXQ_CTRL2_PSRQ0_SHIFT);
+
+	/* Enable flow control */
+	setbits_le32(&xgmac->mac_regs->q0_tx_flow_ctrl,
+		     XGMAC_MAC_Q0_TX_FLOW_CTRL_TFE);
+	setbits_le32(&xgmac->mac_regs->rx_flow_ctrl,
+		     XGMAC_MAC_RX_FLOW_CTRL_RFE);
+
+	clrbits_le32(&xgmac->mac_regs->tx_configuration,
+		     XGMAC_MAC_CONF_JD);
+
+	clrbits_le32(&xgmac->mac_regs->rx_configuration,
+		     XGMAC_MAC_CONF_JE |
+		     XGMAC_MAC_CONF_GPSLCE |
+		     XGMAC_MAC_CONF_WD);
+
+	setbits_le32(&xgmac->mac_regs->rx_configuration,
+		     XGMAC_MAC_CONF_ACS |
+		     XGMAC_MAC_CONF_CST);
+
+	/* Configure DMA */
+	clrsetbits_le32(&xgmac->dma_regs->sysbus_mode,
+			XGMAC_DMA_SYSBUS_MODE_AAL,
+			XGMAC_DMA_SYSBUS_MODE_EAME |
+			XGMAC_DMA_SYSBUS_MODE_UNDEF);
+
+	/* Enable OSP mode */
+	setbits_le32(&xgmac->dma_regs->ch0_tx_control,
+		     XGMAC_DMA_CH0_TX_CONTROL_OSP);
+
+	/* RX buffer size. Must be a multiple of bus width */
+	clrsetbits_le32(&xgmac->dma_regs->ch0_rx_control,
+			XGMAC_DMA_CH0_RX_CONTROL_RBSZ_MASK <<
+			XGMAC_DMA_CH0_RX_CONTROL_RBSZ_SHIFT,
+			XGMAC_MAX_PACKET_SIZE <<
+			XGMAC_DMA_CH0_RX_CONTROL_RBSZ_SHIFT);
+
+	desc_pad = 0;
+
+	setbits_le32(&xgmac->dma_regs->ch0_control,
+		     XGMAC_DMA_CH0_CONTROL_PBLX8 |
+		     (desc_pad << XGMAC_DMA_CH0_CONTROL_DSL_SHIFT));
+
+	/*
+	 * Burst length must be < 1/2 FIFO size.
+	 * FIFO size in tqs is encoded as (n / 256) - 1.
+	 * Each burst is n * 8 (PBLX8) * 16 (AXI width) == 128 bytes.
+	 * Half of n * 256 is n * 128, so pbl == tqs, modulo the -1.
+	 */
+	pbl = tqs + 1;
+	if (pbl > 32)
+		pbl = 32;
+
+	clrsetbits_le32(&xgmac->dma_regs->ch0_tx_control,
+			XGMAC_DMA_CH0_TX_CONTROL_TXPBL_MASK <<
+			XGMAC_DMA_CH0_TX_CONTROL_TXPBL_SHIFT,
+			pbl << XGMAC_DMA_CH0_TX_CONTROL_TXPBL_SHIFT);
+
+	clrsetbits_le32(&xgmac->dma_regs->ch0_rx_control,
+			XGMAC_DMA_CH0_RX_CONTROL_RXPBL_MASK <<
+			XGMAC_DMA_CH0_RX_CONTROL_RXPBL_SHIFT,
+			8 << XGMAC_DMA_CH0_RX_CONTROL_RXPBL_SHIFT);
+
+	/* DMA performance configuration */
+	val = (XGMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK <<
+	       XGMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT) |
+	       (XGMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_MASK <<
+	       XGMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_SHIFT) |
+	       XGMAC_DMA_SYSBUS_MODE_EAME |
+	       XGMAC_DMA_SYSBUS_MODE_BLEN16 |
+	       XGMAC_DMA_SYSBUS_MODE_BLEN8 |
+	       XGMAC_DMA_SYSBUS_MODE_BLEN4 |
+	       XGMAC_DMA_SYSBUS_MODE_BLEN32;
+
+	writel(val, &xgmac->dma_regs->sysbus_mode);
+
+	/* Set up descriptors */
+
+	xgmac->tx_desc_idx = 0;
+	xgmac->rx_desc_idx = 0;
+
+	for (i = 0; i < XGMAC_DESCRIPTORS_NUM; i++) {
+		struct xgmac_desc *rx_desc = &xgmac->rx_descs[i];
+
+		writel(XGMAC_DESC3_OWN, &rx_desc->des3);
+	}
+
+	writel(0, &xgmac->dma_regs->ch0_txdesc_list_haddress);
+	writel(xgmac->tx_descs_phys, &xgmac->dma_regs->ch0_txdesc_list_address);
+	writel(XGMAC_DESCRIPTORS_NUM - 1,
+	       &xgmac->dma_regs->ch0_txdesc_ring_length);
+
+	writel(0, &xgmac->dma_regs->ch0_rxdesc_list_haddress);
+	writel(xgmac->rx_descs_phys, &xgmac->dma_regs->ch0_rxdesc_list_address);
+	writel(XGMAC_DESCRIPTORS_NUM - 1,
+	       &xgmac->dma_regs->ch0_rxdesc_ring_length);
+
+	/* Enable everything */
+	setbits_le32(&xgmac->dma_regs->ch0_tx_control,
+		     XGMAC_DMA_CH0_TX_CONTROL_ST);
+	setbits_le32(&xgmac->dma_regs->ch0_rx_control,
+		     XGMAC_DMA_CH0_RX_CONTROL_SR);
+	setbits_le32(&xgmac->mac_regs->tx_configuration,
+		     XGMAC_MAC_CONF_TE);
+	setbits_le32(&xgmac->mac_regs->rx_configuration,
+		     XGMAC_MAC_CONF_RE);
+
+	/* TX tail pointer not written until we need to TX a packet */
+	/*
+	 * Point RX tail pointer at last descriptor. Ideally, we'd point at the
+	 * first descriptor, implying all descriptors were available. However,
+	 * that's not distinguishable from none of the descriptors being
+	 * available.
+	 */
+	last_rx_desc = (ulong)&xgmac->rx_descs[(XGMAC_DESCRIPTORS_NUM - 1)];
+	writel(last_rx_desc, &xgmac->dma_regs->ch0_rxdesc_tail_pointer);
+
+	xgmac->started = true;
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static void xgmac_stop(struct eth_device *edev)
+{
+	struct xgmac_priv *xgmac = edev->priv;
+	u64 start_time;
+	u32 val;
+	u32 trcsts;
+	u32 txqsts;
+	u32 prxq;
+	u32 rxqsts;
+
+	debug("%s(dev=%p):\n", __func__, edev);
+
+	if (!xgmac->started)
+		return;
+	xgmac->started = false;
+	xgmac->reg_access_ok = false;
+
+	/* Disable TX DMA */
+	clrbits_le32(&xgmac->dma_regs->ch0_tx_control,
+		     XGMAC_DMA_CH0_TX_CONTROL_ST);
+
+	/* Wait for TX all packets to drain out of MTL */
+	start_time = get_time_ns();
+
+	while (!is_timeout(start_time, XGMAC_TIMEOUT_100MS)) {
+		val = readl(&xgmac->mtl_regs->txq0_debug);
+
+		trcsts = (val >> XGMAC_MTL_TXQ0_DEBUG_TRCSTS_SHIFT) &
+			  XGMAC_MTL_TXQ0_DEBUG_TRCSTS_MASK;
+
+		txqsts = val & XGMAC_MTL_TXQ0_DEBUG_TXQSTS;
+
+		if (trcsts != XGMAC_MTL_TXQ0_DEBUG_TRCSTS_READ_STATE && !txqsts)
+			break;
+	}
+
+	/* Turn off MAC TX and RX */
+	clrbits_le32(&xgmac->mac_regs->tx_configuration,
+		     XGMAC_MAC_CONF_RE);
+	clrbits_le32(&xgmac->mac_regs->rx_configuration,
+		     XGMAC_MAC_CONF_RE);
+
+	/* Wait for all RX packets to drain out of MTL */
+	start_time = get_time_ns();
+
+	while (!is_timeout(start_time, XGMAC_TIMEOUT_100MS)) {
+		val = readl(&xgmac->mtl_regs->rxq0_debug);
+
+		prxq = (val >> XGMAC_MTL_RXQ0_DEBUG_PRXQ_SHIFT) &
+			XGMAC_MTL_RXQ0_DEBUG_PRXQ_MASK;
+
+		rxqsts = (val >> XGMAC_MTL_RXQ0_DEBUG_RXQSTS_SHIFT) &
+			  XGMAC_MTL_RXQ0_DEBUG_RXQSTS_MASK;
+
+		if (!prxq && !rxqsts)
+			break;
+	}
+
+	/* Turn off RX DMA */
+	clrbits_le32(&xgmac->dma_regs->ch0_rx_control,
+		     XGMAC_DMA_CH0_RX_CONTROL_SR);
+}
+
+static int xgmac_send(struct eth_device *edev, void *packet, int length)
+{
+	struct xgmac_priv *xgmac = edev->priv;
+	struct xgmac_desc *tx_desc;
+	dma_addr_t dma;
+	u32 des3_prev, des3;
+	int ret;
+
+	tx_desc = &xgmac->tx_descs[xgmac->tx_desc_idx];
+	xgmac->tx_desc_idx++;
+	xgmac->tx_desc_idx %= XGMAC_DESCRIPTORS_NUM;
+
+	dma = dma_map_single(edev->parent, packet, length, DMA_TO_DEVICE);
+	if (dma_mapping_error(edev->parent, dma))
+		return -EFAULT;
+
+	tx_desc->des0 = lower_32_bits(dma);
+	tx_desc->des1 = upper_32_bits(dma);
+	tx_desc->des2 = length;
+	/*
+	 * Make sure that if HW sees the _OWN write below, it will see all the
+	 * writes to the rest of the descriptor too.
+	 */
+	barrier();
+
+	des3_prev = XGMAC_DESC3_OWN | XGMAC_DESC3_FD | XGMAC_DESC3_LD | length;
+	writel(des3_prev, &tx_desc->des3);
+	writel((ulong)(tx_desc + 1), &xgmac->dma_regs->ch0_txdesc_tail_pointer); // <-- TODO
+
+	ret = readl_poll_timeout(&tx_desc->des3, des3,
+				 !(des3 & XGMAC_DESC3_OWN),
+				 100 * USEC_PER_MSEC);
+
+	dma_unmap_single(edev->parent, dma, length, DMA_TO_DEVICE);
+
+	if (ret == -ETIMEDOUT)
+		debug("%s: TX timeout 0x%08x\n", __func__, des3);
+
+	return ret;
+}
+
+static void xgmac_recv(struct eth_device *edev)
+{
+	struct xgmac_priv *xgmac = edev->priv;
+	struct xgmac_desc *rx_desc;
+	dma_addr_t dma;
+	void *pkt;
+	int length;
+
+	rx_desc = &xgmac->rx_descs[xgmac->rx_desc_idx];
+
+	if (rx_desc->des3 & XGMAC_DESC3_OWN)
+		return;
+
+	dma = xgmac->dma_rx_buf_phys[xgmac->rx_desc_idx];
+	pkt = xgmac->dma_rx_buf_virt[xgmac->rx_desc_idx];
+	length = rx_desc->des3 & XGMAC_RDES3_PKT_LENGTH_MASK;
+
+	dma_sync_single_for_cpu(edev->parent, dma, length, DMA_FROM_DEVICE);
+	net_receive(edev, pkt, length);
+	dma_sync_single_for_device(edev->parent, dma, length, DMA_FROM_DEVICE);
+
+	/* Read Format RX descriptor */
+	rx_desc = &xgmac->rx_descs[xgmac->rx_desc_idx];
+	rx_desc->des0 = dma;
+	rx_desc->des1 = 0;
+	rx_desc->des2 = 0;
+	/*
+	 * Make sure that if HW sees the _OWN write below, it will see all the
+	 * writes to the rest of the descriptor too.
+	 */
+	rx_desc->des3 = XGMAC_DESC3_OWN;
+	barrier();
+
+	writel(xgmac->rx_descs_phys + (xgmac->rx_desc_idx * XGMAC_DESCRIPTOR_SIZE),
+	       &xgmac->dma_regs->ch0_rxdesc_tail_pointer);
+
+	xgmac->rx_desc_idx++;
+	xgmac->rx_desc_idx %= XGMAC_DESCRIPTORS_NUM;
+}
+
+static int xgmac_probe_resources_core(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+	unsigned int desc_step;
+	int ret = 0;
+	void *p;
+	int i;
+
+	/* Maximum distance between neighboring descriptors, in Bytes. */
+	desc_step = sizeof(struct xgmac_desc);
+
+	xgmac->tx_descs = dma_alloc_coherent(DMA_DEVICE_BROKEN,
+					     XGMAC_DESCRIPTORS_SIZE,
+					     &xgmac->tx_descs_phys);
+	if (!xgmac->tx_descs) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	xgmac->rx_descs = dma_alloc_coherent(DMA_DEVICE_BROKEN,
+					     XGMAC_DESCRIPTORS_SIZE,
+					     &xgmac->rx_descs_phys);
+	if (!xgmac->rx_descs) {
+		ret = -ENOMEM;
+		goto err_free_tx_descs;
+	}
+
+	p = dma_alloc(XGMAC_RX_BUFFER_SIZE);
+	if (!p)
+		goto err_free_descs;
+
+	for (i = 0; i < XGMAC_DESCRIPTORS_NUM; i++) {
+		struct xgmac_desc *rx_desc = &xgmac->rx_descs[i];
+		dma_addr_t dma;
+
+		dma = dma_map_single(dev, p, XGMAC_MAX_PACKET_SIZE, DMA_FROM_DEVICE);
+		if (dma_mapping_error(dev, dma)) {
+			ret = -EFAULT;
+			goto err_free_dma_bufs;
+		}
+
+		rx_desc->des0 = dma;
+		xgmac->dma_rx_buf_phys[i] = dma;
+		xgmac->dma_rx_buf_virt[i] = p;
+
+		p += XGMAC_MAX_PACKET_SIZE;
+	}
+
+	return 0;
+
+err_free_dma_bufs:
+	dma_free(phys_to_virt(xgmac->rx_descs[0].des0));
+err_free_descs:
+	dma_free_coherent(DMA_DEVICE_BROKEN, xgmac->rx_descs, xgmac->rx_descs_phys,
+			  XGMAC_DESCRIPTORS_SIZE);
+err_free_tx_descs:
+	dma_free_coherent(DMA_DEVICE_BROKEN, xgmac->tx_descs, xgmac->tx_descs_phys,
+			  XGMAC_DESCRIPTORS_SIZE);
+err:
+
+	return ret;
+}
+
+static int xgmac_remove_resources_core(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	dma_free(xgmac->rx_dma_buf);
+	dma_free_coherent(DMA_DEVICE_BROKEN, xgmac->rx_descs, xgmac->rx_descs_phys,
+			  XGMAC_DESCRIPTORS_SIZE);
+	dma_free_coherent(DMA_DEVICE_BROKEN, xgmac->tx_descs, xgmac->tx_descs_phys,
+			  XGMAC_DESCRIPTORS_SIZE);
+
+	return 0;
+}
+
+static void xgmac_probe_dt(struct device *dev, struct xgmac_priv *xgmac)
+{
+	struct device_node *child;
+	int phy_reset;
+	int ret;
+
+	xgmac->interface = of_get_phy_mode(dev->of_node);
+	xgmac->phy_addr = 0;
+
+	/* Set MDIO bus device node, if present. */
+	for_each_child_of_node(dev->of_node, child) {
+		if (of_device_is_compatible(child, "snps,dwmac-mdio") ||
+		    (child->name && !of_node_cmp(child->name, "mdio"))) {
+			xgmac->miibus.dev.of_node = child;
+			break;
+		}
+	}
+
+	phy_reset = of_get_named_gpio(dev->of_node, "phy-reset-gpios", 0);
+	if (gpio_is_valid(phy_reset)) {
+		ret = gpio_request(phy_reset, "phy-reset");
+		if (ret)
+			return;
+
+		xgmac->phy_reset_gpio = phy_reset;
+	}
+
+}
+
+int xgmac_probe(struct device *dev)
+{
+	struct device_node *np = dev->of_node;
+	struct mii_bus *miibus;
+	struct xgmac_priv *xgmac;
+	struct resource *iores;
+	struct eth_device *edev;
+	int ret = 0;
+
+	xgmac = xzalloc(sizeof(*xgmac));
+
+	xgmac->dev = dev;
+	xgmac->config = device_get_match_data(dev);
+	if (ret < 0) {
+		dev_err(dev, "xgmac_probe() failed to get driver data: %d\n", ret);
+		return ret;
+	}
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+	xgmac->regs = IOMEM(iores->start);
+
+	xgmac->mac_regs = xgmac->regs + XGMAC_MAC_REGS_BASE;
+	xgmac->mtl_regs = xgmac->regs + XGMAC_MTL_REGS_BASE;
+	xgmac->dma_regs = xgmac->regs + XGMAC_DMA_REGS_BASE;
+
+	xgmac_probe_dt(dev, xgmac);
+
+	edev = &xgmac->netdev;
+	dev->priv = edev->priv = xgmac;
+
+	edev->parent = dev;
+	edev->open = xgmac_start;
+	edev->send = xgmac_send;
+	edev->halt = xgmac_stop;
+	edev->recv = xgmac_recv;
+	edev->get_ethaddr = xgmac_read_rom_hwaddr;
+	edev->set_ethaddr = xgmac_write_hwaddr;
+
+	of_property_read_u32(np, "max-speed", &xgmac->max_speed);
+
+	miibus = &xgmac->miibus;
+	miibus->parent = edev->parent;
+	miibus->read = xgmac_mdio_read;
+	miibus->write = xgmac_mdio_write;
+	miibus->priv = xgmac;
+
+	gpio_direction_output(xgmac->phy_reset_gpio, 0);
+
+	udelay(2);
+
+	gpio_set_value(xgmac->phy_reset_gpio, 1);
+
+	ret = xgmac_probe_resources_core(dev);
+	if (ret < 0) {
+		dev_err(dev, "xgmac_probe_resources_core() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = xgmac->config->ops->xgmac_probe_resources(dev);
+	if (ret < 0) {
+		dev_err(dev, "xgmac_probe_resources() failed: %d\n", ret);
+		goto err_remove_resources_core;
+	}
+
+	ret = mdiobus_register(miibus);
+	if (ret)
+		return ret;
+
+	return eth_register(edev);
+
+err_remove_resources_core:
+	xgmac_remove_resources_core(dev);
+
+	return ret;
+}
+
+void xgmac_remove(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	gpio_free(xgmac->phy_reset_gpio);
+	eth_unregister(&xgmac->netdev);
+	mdiobus_unregister(&xgmac->miibus);
+
+	xgmac_remove_resources_core(dev);
+}
diff --git a/drivers/net/designware_xgmac.h b/drivers/net/designware_xgmac.h
new file mode 100644
index 0000000000000000000000000000000000000000..4f6d90f87bb3b8fb261836b3b7700abd152841a1
--- /dev/null
+++ b/drivers/net/designware_xgmac.h
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2023 Intel Coporation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/phy.h>
+
+/* Core registers */
+
+#define XGMAC_MAC_REGS_BASE 0x000
+
+struct xgmac_mac_regs {
+	u32 tx_configuration;			/* 0x000 */
+	u32 rx_configuration;			/* 0x004 */
+	u32 mac_packet_filter;			/* 0x008 */
+	u32 unused_00c[(0x070 - 0x00c) / 4];	/* 0x00c */
+	u32 q0_tx_flow_ctrl;			/* 0x070 */
+	u32 unused_070[(0x090 - 0x074) / 4];	/* 0x074 */
+	u32 rx_flow_ctrl;			/* 0x090 */
+	u32 unused_094[(0x0a0 - 0x094) / 4];	/* 0x094 */
+	u32 rxq_ctrl0;				/* 0x0a0 */
+	u32 rxq_ctrl1;				/* 0x0a4 */
+	u32 rxq_ctrl2;				/* 0x0a8 */
+	u32 unused_0ac[(0x0dc - 0x0ac) / 4];	/* 0x0ac */
+	u32 us_tic_counter;			/* 0x0dc */
+	u32 unused_0e0[(0x11c - 0x0e0) / 4];	/* 0x0e0 */
+	u32 hw_feature0;			/* 0x11c */
+	u32 hw_feature1;			/* 0x120 */
+	u32 hw_feature2;			/* 0x124 */
+	u32 hw_feature3;			/* 0x128 */
+	u32 hw_feature4;			/* 0x12c */
+	u32 unused_130[(0x140 - 0x130) / 4];	/* 0x130 */
+	u32 mac_extended_conf;			/* 0x140 */
+	u32 unused_144[(0x200 - 0x144) / 4];	/* 0x144 */
+	u32 mdio_address;			/* 0x200 */
+	u32 mdio_data;				/* 0x204 */
+	u32 mdio_cont_write_addr;		/* 0x208 */
+	u32 mdio_cont_write_data;		/* 0x20c */
+	u32 mdio_cont_scan_port_enable;		/* 0x210 */
+	u32 mdio_intr_status;			/* 0x214 */
+	u32 mdio_intr_enable;			/* 0x218 */
+	u32 mdio_port_cnct_dsnct_status;	/* 0x21c */
+	u32 mdio_clause_22_port;		/* 0x220 */
+	u32 unused_224[(0x300 - 0x224)	/ 4];	/* 0x224 */
+	u32 address0_high;			/* 0x300 */
+	u32 address0_low;			/* 0x304 */
+};
+
+#define XGMAC_TIMEOUT_100MS			100000
+#define XGMAC_MAC_CONF_SS_SHIFT			29
+#define XGMAC_MAC_CONF_SS_SHIFT_MASK		GENMASK(31, 29)
+#define XGMAC_MAC_CONF_SS_10G_XGMII		0
+#define XGMAC_MAC_CONF_SS_2_5G_GMII		2
+#define XGMAC_MAC_CONF_SS_1G_GMII		3
+#define XGMAC_MAC_CONF_SS_100M_MII		4
+#define XGMAC_MAC_CONF_SS_5G_XGMII		5
+#define XGMAC_MAC_CONF_SS_2_5G_XGMII		6
+#define XGMAC_MAC_CONF_SS_2_10M_MII		7
+
+#define XGMAC_MAC_CONF_JD			BIT(16)
+#define XGMAC_MAC_CONF_JE			BIT(8)
+#define XGMAC_MAC_CONF_WD			BIT(7)
+#define XGMAC_MAC_CONF_GPSLCE			BIT(6)
+#define XGMAC_MAC_CONF_CST			BIT(2)
+#define XGMAC_MAC_CONF_ACS			BIT(1)
+#define XGMAC_MAC_CONF_TE			BIT(0)
+#define XGMAC_MAC_CONF_RE			BIT(0)
+
+#define XGMAC_MAC_EXT_CONF_HD			BIT(24)
+
+#define XGMAC_MAC_PACKET_FILTER_RA		BIT(31)
+#define XGMAC_MAC_PACKET_FILTER_PR		BIT(0)
+
+#define XGMAC_MAC_Q0_TX_FLOW_CTRL_PT_SHIFT	16
+#define XGMAC_MAC_Q0_TX_FLOW_CTRL_PT_MASK	GENMASK(15, 0)
+#define XGMAC_MAC_Q0_TX_FLOW_CTRL_TFE		BIT(1)
+
+#define XGMAC_MAC_RX_FLOW_CTRL_RFE		BIT(0)
+#define XGMAC_MAC_RXQ_CTRL0_RXQ0EN_SHIFT	0
+#define XGMAC_MAC_RXQ_CTRL0_RXQ0EN_MASK		GENMASK(1, 0)
+#define XGMAC_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED	0
+#define XGMAC_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB	2
+#define XGMAC_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV	1
+
+#define XGMAC_MAC_RXQ_CTRL1_MCBCQEN		BIT(15)
+
+#define XGMAC_MAC_RXQ_CTRL2_PSRQ0_SHIFT		0
+#define XGMAC_MAC_RXQ_CTRL2_PSRQ0_MASK		GENMASK(7, 0)
+
+#define XGMAC_MAC_HW_FEATURE1_TXFIFOSIZE_SHIFT	6
+#define XGMAC_MAC_HW_FEATURE1_TXFIFOSIZE_MASK	GENMASK(4, 0)
+#define XGMAC_MAC_HW_FEATURE1_RXFIFOSIZE_SHIFT	0
+#define XGMAC_MAC_HW_FEATURE1_RXFIFOSIZE_MASK	GENMASK(4, 0)
+
+#define XGMAC_MDIO_SINGLE_CMD_SHIFT		16
+#define XGMAC_MDIO_SINGLE_CMD_ADDR_CMD_READ	3 << XGMAC_MDIO_SINGLE_CMD_SHIFT
+#define XGMAC_MDIO_SINGLE_CMD_ADDR_CMD_WRITE	BIT(16)
+#define XGMAC_MAC_MDIO_ADDRESS_PA_SHIFT		16
+#define XGMAC_MAC_MDIO_ADDRESS_PA_MASK		GENMASK(15, 0)
+#define XGMAC_MAC_MDIO_ADDRESS_DA_SHIFT		21
+#define XGMAC_MAC_MDIO_ADDRESS_CR_SHIFT		19
+#define XGMAC_MAC_MDIO_ADDRESS_CR_100_150	0
+#define XGMAC_MAC_MDIO_ADDRESS_CR_150_250	1
+#define XGMAC_MAC_MDIO_ADDRESS_CR_250_300	2
+#define XGMAC_MAC_MDIO_ADDRESS_CR_300_350	3
+#define XGMAC_MAC_MDIO_ADDRESS_CR_350_400	4
+#define XGMAC_MAC_MDIO_ADDRESS_CR_400_500	5
+#define XGMAC_MAC_MDIO_ADDRESS_SADDR		BIT(18)
+#define XGMAC_MAC_MDIO_ADDRESS_SBUSY		BIT(22)
+#define XGMAC_MAC_MDIO_REG_ADDR_C22P_MASK	GENMASK(4, 0)
+#define XGMAC_MAC_MDIO_DATA_GD_MASK		GENMASK(15, 0)
+
+/* MTL Registers */
+
+#define XGMAC_MTL_REGS_BASE 0x1000
+
+struct xgmac_mtl_regs {
+	u32 mtl_operation_mode;			/* 0x1000 */
+	u32 unused_1004[(0x1030 - 0x1004) / 4];	/* 0x1004 */
+	u32 mtl_rxq_dma_map0;			/* 0x1030 */
+	u32 mtl_rxq_dma_map1;			/* 0x1034 */
+	u32 mtl_rxq_dma_map2;			/* 0x1038 */
+	u32 mtl_rxq_dma_map3;			/* 0x103c */
+	u32 mtl_tc_prty_map0;			/* 0x1040 */
+	u32 mtl_tc_prty_map1;			/* 0x1044 */
+	u32 unused_1048[(0x1100 - 0x1048) / 4]; /* 0x1048 */
+	u32 txq0_operation_mode;		/* 0x1100 */
+	u32 unused_1104;			/* 0x1104 */
+	u32 txq0_debug;				/* 0x1108 */
+	u32 unused_100c[(0x1118 - 0x110c) / 4];	/* 0x110c */
+	u32 txq0_quantum_weight;		/* 0x1118 */
+	u32 unused_111c[(0x1140 - 0x111c) / 4];	/* 0x111c */
+	u32 rxq0_operation_mode;		/* 0x1140 */
+	u32 unused_1144;			/* 0x1144 */
+	u32 rxq0_debug;				/* 0x1148 */
+};
+
+#define XGMAC_MTL_TXQ0_OPERATION_MODE_TQS_SHIFT		16
+#define XGMAC_MTL_TXQ0_OPERATION_MODE_TQS_MASK		GENMASK(8, 0)
+#define XGMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_SHIFT	2
+#define XGMAC_MTL_TXQ0_OPERATION_MODE_TXQEN_ENABLED	2
+#define XGMAC_MTL_TXQ0_OPERATION_MODE_TSF		BIT(1)
+#define XGMAC_MTL_TXQ0_OPERATION_MODE_FTQ		BIT(0)
+
+#define XGMAC_MTL_TXQ0_DEBUG_TXQSTS			BIT(4)
+#define XGMAC_MTL_TXQ0_DEBUG_TRCSTS_SHIFT		1
+#define XGMAC_MTL_TXQ0_DEBUG_TRCSTS_MASK		GENMASK(2, 0)
+#define XGMAC_MTL_TXQ0_DEBUG_TRCSTS_READ_STATE		0x1
+
+#define XGMAC_MTL_RXQ0_OPERATION_MODE_RQS_SHIFT		16
+#define XGMAC_MTL_RXQ0_OPERATION_MODE_RQS_MASK		GENMASK(9, 0)
+#define XGMAC_MTL_RXQ0_OPERATION_MODE_EHFC		BIT(7)
+#define XGMAC_MTL_RXQ0_OPERATION_MODE_RSF		BIT(5)
+
+#define XGMAC_MTL_RXQ0_DEBUG_PRXQ_SHIFT			16
+#define XGMAC_MTL_RXQ0_DEBUG_PRXQ_MASK			GENMASK(14, 0)
+#define XGMAC_MTL_RXQ0_DEBUG_RXQSTS_SHIFT		4
+#define XGMAC_MTL_RXQ0_DEBUG_RXQSTS_MASK		GENMASK(1, 0)
+
+/* DMA Registers */
+
+#define XGMAC_DMA_REGS_BASE 0x3000
+
+struct xgmac_dma_regs {
+	u32 mode;					/* 0x3000 */
+	u32 sysbus_mode;				/* 0x3004 */
+	u32 unused_3008[(0x3100 - 0x3008) / 4];		/* 0x3008 */
+	u32 ch0_control;				/* 0x3100 */
+	u32 ch0_tx_control;				/* 0x3104 */
+	u32 ch0_rx_control;				/* 0x3108 */
+	u32 slot_func_control_status;			/* 0x310c */
+	u32 ch0_txdesc_list_haddress;			/* 0x3110 */
+	u32 ch0_txdesc_list_address;			/* 0x3114 */
+	u32 ch0_rxdesc_list_haddress;			/* 0x3118 */
+	u32 ch0_rxdesc_list_address;			/* 0x311c */
+	/* 0x3120: register undocumented; maybe high address of ch0_txdesc_tail_pointer? */
+	u32 unused_3120;
+	u32 ch0_txdesc_tail_pointer;			/* 0x3124 */
+	/* 0x3128: register undocumented; maybe high address of ch0_rxdesc_tail_pointer? */
+	u32 unused_3128;
+	u32 ch0_rxdesc_tail_pointer;			/* 0x312c */
+	u32 ch0_txdesc_ring_length;			/* 0x3130 */
+	u32 ch0_rxdesc_ring_length;			/* 0x3134 */
+	u32 unused_3138[(0x3160 - 0x3138) / 4];		/* 0x3138 */
+	u32 ch0_status;					/* 0x3160 */
+};
+
+#define XGMAC_DMA_MODE_SWR				BIT(0)
+#define XGMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_SHIFT		24
+#define XGMAC_DMA_SYSBUS_MODE_WR_OSR_LMT_MASK		GENMASK(4, 0)
+#define XGMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_SHIFT		16
+#define XGMAC_DMA_SYSBUS_MODE_RD_OSR_LMT_MASK		GENMASK(4, 0)
+#define XGMAC_DMA_SYSBUS_MODE_AAL			BIT(12)
+#define XGMAC_DMA_SYSBUS_MODE_EAME			BIT(11)
+#define XGMAC_DMA_SYSBUS_MODE_BLEN32			BIT(4)
+#define XGMAC_DMA_SYSBUS_MODE_BLEN16			BIT(3)
+#define XGMAC_DMA_SYSBUS_MODE_BLEN8			BIT(2)
+#define XGMAC_DMA_SYSBUS_MODE_BLEN4			BIT(1)
+#define XGMAC_DMA_SYSBUS_MODE_UNDEF			BIT(0)
+
+#define XGMAC_DMA_CH0_CONTROL_DSL_SHIFT			18
+#define XGMAC_DMA_CH0_CONTROL_PBLX8			BIT(16)
+
+#define XGMAC_DMA_CH0_TX_CONTROL_TXPBL_SHIFT		16
+#define XGMAC_DMA_CH0_TX_CONTROL_TXPBL_MASK		GENMASK(5, 0)
+#define XGMAC_DMA_CH0_TX_CONTROL_OSP			BIT(4)
+#define XGMAC_DMA_CH0_TX_CONTROL_ST			BIT(0)
+
+#define XGMAC_DMA_CH0_RX_CONTROL_RXPBL_SHIFT		16
+#define XGMAC_DMA_CH0_RX_CONTROL_RXPBL_MASK		GENMASK(5, 0)
+#define XGMAC_DMA_CH0_RX_CONTROL_RBSZ_SHIFT		4
+#define XGMAC_DMA_CH0_RX_CONTROL_RBSZ_MASK		GENMASK(10, 0)
+#define XGMAC_DMA_CH0_RX_CONTROL_SR			BIT(0)
+
+/* Descriptors */
+#define XGMAC_DESCRIPTOR_WORDS		4
+#define XGMAC_DESCRIPTOR_SIZE		(XGMAC_DESCRIPTOR_WORDS * 4)
+#define XGMAC_DESCRIPTORS_NUM		8
+#define XGMAC_DESCRIPTOR_ALIGN		64
+#define XGMAC_DESCRIPTORS_SIZE		ALIGN(XGMAC_DESCRIPTORS_NUM * \
+					      XGMAC_DESCRIPTOR_SIZE, XGMAC_DESCRIPTOR_ALIGN)
+#define XGMAC_BUFFER_ALIGN		XGMAC_DESCRIPTOR_ALIGN
+#define XGMAC_MAX_PACKET_SIZE		ALIGN(1568, XGMAC_DESCRIPTOR_ALIGN)
+#define XGMAC_RX_BUFFER_SIZE		(XGMAC_DESCRIPTORS_NUM * XGMAC_MAX_PACKET_SIZE)
+
+#define XGMAC_RDES3_PKT_LENGTH_MASK	GENMASK(13, 0)
+
+struct xgmac_desc {
+	u32 des0;
+	u32 des1;
+	u32 des2;
+	u32 des3;
+};
+
+#define XGMAC_DESC3_OWN		BIT(31)
+#define XGMAC_DESC3_FD		BIT(29)
+#define XGMAC_DESC3_LD		BIT(28)
+
+#define XGMAC_AXI_WIDTH_32	4
+#define XGMAC_AXI_WIDTH_64	8
+#define XGMAC_AXI_WIDTH_128	16
+
+struct xgmac_config {
+	bool reg_access_always_ok;
+	int swr_wait;
+	int config_mac;
+	int config_mac_mdio;
+	unsigned int axi_bus_width;
+	phy_interface_t interface;
+	struct xgmac_ops *ops;
+};
+
+struct xgmac_ops {
+	int (*xgmac_probe_resources)(struct device *dev);
+	int (*xgmac_start_resets)(struct device *dev);
+	int (*xgmac_get_enetaddr)(struct device *dev);
+};
+
+struct xgmac_priv {
+	struct eth_device netdev;
+	struct device *dev;
+	const struct xgmac_config *config;
+	void __iomem *regs;
+	struct xgmac_mac_regs *mac_regs;
+	struct xgmac_mtl_regs *mtl_regs;
+	struct xgmac_dma_regs *dma_regs;
+	struct reset_control *rst;
+	struct reset_control *rst_ocp;
+	struct mii_bus miibus;
+	int phy_addr;
+	phy_interface_t interface;
+	int phy_reset_gpio;
+
+	u8 macaddr[6];
+
+	u32 reg_offset, reg_shift;
+	u32 max_speed;
+	struct xgmac_desc *tx_descs, *rx_descs;
+	dma_addr_t tx_descs_phys, rx_descs_phys;
+	dma_addr_t dma_rx_buf_phys[XGMAC_DESCRIPTORS_NUM];
+	void *dma_rx_buf_virt[XGMAC_DESCRIPTORS_NUM];
+	int tx_desc_idx, rx_desc_idx;
+	unsigned int desc_size;
+	unsigned int desc_per_cacheline;
+	void *rx_dma_buf;
+	bool started;
+	bool reg_access_ok;
+	bool clk_ck_enabled;
+};
+
+int xgmac_probe(struct device *dev);
+void xgmac_remove(struct device *dev);
+void xgmac_flush_desc_generic(void *desc);
+void xgmac_flush_buffer_generic(void *buf, size_t size);
+int xgmac_null_ops(struct device *dev);
+
+extern struct xgmac_config xgmac_socfpga_config;
diff --git a/drivers/net/designware_xgmac_socfpga.c b/drivers/net/designware_xgmac_socfpga.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d8dba3c17cdb3fe7c82a6fa9315fecfdbfcc32a
--- /dev/null
+++ b/drivers/net/designware_xgmac_socfpga.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2023, Intel Corporation
+ */
+#define DEBUG
+#include <common.h>
+#include <init.h>
+#include <errno.h>
+#include <malloc.h>
+#include <net.h>
+#include <linux/reset.h>
+#include <linux/phy.h>
+#include <mfd/syscon.h>
+#include <linux/clk.h>
+#include <mach/socfpga/soc64-system-manager.h>
+#include <mach/socfpga/secure_reg_helper.h>
+
+#include "designware_xgmac.h"
+
+#define SOCFPGA_XGMAC_SYSCON_ARG_COUNT 2
+
+static int dwxgmac_socfpga_do_setphy(struct device *dev, u32 modereg)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+	u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK;
+	u32 index = (xgmac->reg_offset - SYSMGR_SOC64_EMAC0) >> 2;
+	u32 id = SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC0 + index;
+	int ret;
+
+	ret = socfpga_secure_reg_update32(id, modemask, modereg);
+	if (ret) {
+		dev_err(dev, "Failed to set PHY register via SMC call\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int xgmac_probe_resources_socfpga(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+	phy_interface_t interface;
+	int ret;
+	u32 modereg;
+
+	interface = xgmac->interface;
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_MII:
+	case PHY_INTERFACE_MODE_GMII:
+		modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+		break;
+	case PHY_INTERFACE_MODE_RMII:
+		modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII;
+		break;
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+		modereg = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
+		break;
+	default:
+		dev_err(dev, "Unsupported PHY mode\n");
+		return -EINVAL;
+	}
+
+	/* Get PHY syscon */
+	ret = of_property_read_u32_index(dev->of_node, "altr,sysmgr-syscon",
+					 1, &xgmac->reg_offset);
+	if (ret) {
+		dev_err(dev, "Could not read reg_offset from sysmgr-syscon! Please update the devicetree.\n");
+
+		return -EINVAL;
+	}
+
+	ret = of_property_read_u32_index(dev->of_node, "altr,sysmgr-syscon",
+					 2, &xgmac->reg_shift);
+	if (ret) {
+		dev_err(dev, "Could not read reg_shift from sysmgr-syscon! Please update the devicetree.\n");
+		return -EINVAL;
+	}
+
+	xgmac->rst = reset_control_get(dev, "stmmaceth");
+	if (IS_ERR(xgmac->rst)) {
+		dev_err(dev, "Invalid reset line 'stmmaceth'.\n");
+		return PTR_ERR(xgmac->rst);
+	}
+	xgmac->rst_ocp = reset_control_get(dev, "stmmaceth-ocp");
+	if (IS_ERR(xgmac->rst_ocp)) {
+		dev_err(dev, "Invalid reset line 'stmmaceth-ocp'.\n");
+		return PTR_ERR(xgmac->rst_ocp);
+	}
+
+	reset_control_assert(xgmac->rst_ocp);
+	reset_control_assert(xgmac->rst);
+
+	ret = dwxgmac_socfpga_do_setphy(dev, modereg);
+	if (ret)
+		return ret;
+
+	reset_control_deassert(xgmac->rst_ocp);
+	reset_control_deassert(xgmac->rst);
+
+	return 0;
+}
+
+static int xgmac_get_enetaddr_socfpga(struct device *dev)
+{
+	return -ENOTSUPP;
+}
+
+static int xgmac_start_resets_socfpga(struct device *dev)
+{
+	struct xgmac_priv *xgmac = dev_get_priv(dev);
+
+	reset_control_assert(xgmac->rst);
+	reset_control_assert(xgmac->rst_ocp);
+
+	udelay(2);
+
+	reset_control_deassert(xgmac->rst);
+	reset_control_deassert(xgmac->rst_ocp);
+
+	return 0;
+}
+
+static struct xgmac_ops xgmac_socfpga_ops = {
+	.xgmac_probe_resources = xgmac_probe_resources_socfpga,
+	.xgmac_start_resets = xgmac_start_resets_socfpga,
+	.xgmac_get_enetaddr = xgmac_get_enetaddr_socfpga,
+};
+
+struct xgmac_config __maybe_unused xgmac_socfpga_config = {
+	.reg_access_always_ok = false,
+	.swr_wait = 50,
+	.config_mac = XGMAC_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
+	.config_mac_mdio = XGMAC_MAC_MDIO_ADDRESS_CR_350_400,
+	.axi_bus_width = XGMAC_AXI_WIDTH_64,
+	.ops = &xgmac_socfpga_ops
+};
+
+static __maybe_unused struct of_device_id xgmac_socfpga_compatible[] = {
+	{
+		.compatible = "intel,socfpga-dwxgmac",
+		.data = &xgmac_socfpga_config
+	}, {
+		/* sentinel */
+	}
+};
+MODULE_DEVICE_TABLE(of, xgmac_socfpga_compatible);
+
+static struct driver xgmac_socfpga_driver = {
+	.name = "designware-xgmac-socfpga",
+	.probe = xgmac_probe,
+	.remove = xgmac_remove,
+	.of_compatible = DRV_OF_COMPAT(xgmac_socfpga_compatible),
+};
+device_platform_driver(xgmac_socfpga_driver);

-- 
2.46.0



From s.trumtrar at pengutronix.de  Tue Feb 18 01:21:29 2025
From: s.trumtrar at pengutronix.de (Steffen Trumtrar)
Date: Tue, 18 Feb 2025 10:21:29 +0100
Subject: [PATCH v2 04/10] arm: socfgpa: add support for SoCFPGA Agilex5
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
Message-ID: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-4-30b6f507810b@pengutronix.de>

Add initial support for the Intel Agilex5 SoCFPGA platform.

The Agilex5 devices have:
  - Quad-core cluster consisting of Dual-core 64-bit Arm Cortex-A76, and dual-core 64-bit Arm Cortex-A55 (SoC only)
  - High-Speed transceivers, up to 17.1 Gbps (group B) and 28.1 Gbps (group A)
  - PCIe Gen4 x4
  - DDR4/LPDDR4/LPDDR5, and DDR5 (group A)
  - Native MIPI CSI-2 and D-PHY (multiple channels)
  - Secure Device Manager (SDM) to support secure configuration and tamper prevention, and hardened cryptographic engines
(from https://www.rocketboards.org/foswiki/Documentation/ArrowAXE5EagleDevelopmentKit)

Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
---
 arch/arm/Kconfig                              |   3 -
 arch/arm/dts/socfpga_agilex5.dtsi             |  71 ++++
 arch/arm/mach-socfpga/Kconfig                 |  37 +-
 arch/arm/mach-socfpga/Makefile                |  13 +
 arch/arm/mach-socfpga/agilex5-clock-manager.c | 383 ++++++++++++++++++
 arch/arm/mach-socfpga/agilex5-sdram.c         | 347 ++++++++++++++++
 arch/arm/mach-socfpga/agilex5-secreg.c        | 289 ++++++++++++++
 arch/arm/mach-socfpga/atf.c                   |  34 ++
 arch/arm/mach-socfpga/cpu_init.c              |  43 ++
 arch/arm/mach-socfpga/iossm_mailbox.c         | 511 ++++++++++++++++++++++++
 arch/arm/mach-socfpga/iossm_mailbox.h         | 157 ++++++++
 arch/arm/mach-socfpga/mailbox_s10.c           | 347 ++++++++++++++++
 arch/arm/mach-socfpga/secure_reg_helper.c     |  75 ++++
 arch/arm/mach-socfpga/smc_api.c               |  43 ++
 arch/arm/mach-socfpga/soc64-system-manager.c  | 102 +++++
 arch/arm/mach-socfpga/soc64-wrap-handoff.c    | 124 ++++++
 common/Kconfig.debug_ll                       |  17 +
 firmware/Kconfig                              |   3 +
 firmware/Makefile                             |   1 +
 images/Makefile.socfpga                       |   8 +
 include/mach/socfpga/agilex5-clk.h            | 266 +++++++++++++
 include/mach/socfpga/atf.h                    |  14 +
 include/mach/socfpga/generic.h                |   3 +
 include/mach/socfpga/init.h                   |   2 +
 include/mach/socfpga/intel-smc.h              | 545 ++++++++++++++++++++++++++
 include/mach/socfpga/mailbox_s10.h            | 191 +++++++++
 include/mach/socfpga/secure_reg_helper.h      |  19 +
 include/mach/socfpga/smc_api.h                |  12 +
 include/mach/socfpga/soc64-firewall.h         | 177 +++++++++
 include/mach/socfpga/soc64-handoff.h          |  50 +++
 include/mach/socfpga/soc64-regs.h             | 195 +++++++++
 include/mach/socfpga/soc64-reset-manager.h    |  40 ++
 include/mach/socfpga/soc64-sdram.h            | 203 ++++++++++
 include/mach/socfpga/soc64-system-manager.h   | 176 +++++++++
 34 files changed, 4494 insertions(+), 7 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 516cc721a5f603bf7f64979749b86955a3a20275..bdd23265397ef6ef29d3851adfcc6f4fe9a1c01c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -103,10 +103,7 @@ config ARCH_PXA
 
 config ARCH_SOCFPGA
 	bool "Altera SOCFPGA"
-	depends on 32BIT
 	select HAS_DEBUG_LL
-	select ARM_SMP_TWD
-	select CPU_V7
 	select COMMON_CLK
 
 config ARCH_TEGRA
diff --git a/arch/arm/dts/socfpga_agilex5.dtsi b/arch/arm/dts/socfpga_agilex5.dtsi
new file mode 100644
index 0000000000000000000000000000000000000000..24bebf7c3a951acaad03c9b43e14735a5923ca04
--- /dev/null
+++ b/arch/arm/dts/socfpga_agilex5.dtsi
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier:     GPL-2.0
+/*
+ * Copyright (C) 2019-2023 Intel Corporation <www.intel.com>
+ */
+
+&soc {
+	gmac0: ethernet at 10810000 {
+		compatible = "intel,socfpga-dwxgmac", "snps,dwxgmac-2.10", "snps,dwxgmac";
+		reg = <0x10810000 0x3500>;
+		interrupts = <0 190 4>;
+		interrupt-names = "macirq";
+		resets = <&rst EMAC0_RESET>, <&rst EMAC0_OCP_RESET>;
+		reset-names = "stmmaceth", "stmmaceth-ocp";
+		tx-fifo-depth = <32768>;
+		rx-fifo-depth = <16384>;
+		altr,sysmgr-syscon = <&sysmgr 0x44 0>;
+		clocks = <&clkmgr AGILEX5_EMAC0_CLK>;
+		clock-names = "stmmaceth";
+		status = "disabled";
+	};
+
+	gmac1: ethernet at 10820000 {
+		compatible = "intel,socfpga-dwxgmac", "snps,dwxgmac-2.10", "snps,dwxgmac";
+		reg = <0x10820000 0x3500>;
+		interrupts = <0 207 4>;
+		interrupt-names = "macirq";
+		resets = <&rst EMAC1_RESET>, <&rst EMAC1_OCP_RESET>;
+		reset-names = "stmmaceth", "stmmaceth-ocp";
+		tx-fifo-depth = <32768>;
+		rx-fifo-depth = <16384>;
+		altr,sysmgr-syscon = <&sysmgr 0x48 0>;
+		clocks = <&clkmgr AGILEX5_EMAC1_CLK>;
+		clock-names = "stmmaceth";
+		status = "disabled";
+	};
+
+	gmac2: ethernet at 10830000 {
+		compatible = "intel,socfpga-dwxgmac", "snps,dwxgmac-2.10", "snps,dwxgmac";
+		reg = <0x10830000 0x3500>;
+		interrupts = <0 224 4>;
+		interrupt-names = "macirq";
+		resets = <&rst EMAC2_RESET>, <&rst EMAC2_OCP_RESET>;
+		reset-names = "stmmaceth", "stmmaceth-ocp";
+		tx-fifo-depth = <32768>;
+		rx-fifo-depth = <16384>;
+		altr,sysmgr-syscon = <&sysmgr 0x4c 0>;
+		clocks = <&clkmgr AGILEX5_EMAC2_CLK>;
+		clock-names = "stmmaceth";
+		status = "disabled";
+	};
+
+	gpio0: gpio at 10c03200 {
+		compatible = "snps,dw-apb-gpio";
+		reg = <0x10c03200 0x100>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		resets = <&rst GPIO0_RESET>;
+		status = "disabled";
+
+		porta: gpio-controller at 0 {
+			compatible = "snps,dw-apb-gpio-port";
+			reg = <0>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			snps,nr-gpios = <24>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+		};
+	};
+};
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index 80a15377b2e4be4d1386904a298a9aadcffbab00..f0dce3bad0429d38840975a2f3c3640731e7a605 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -4,13 +4,17 @@ if ARCH_SOCFPGA
 
 config ARCH_SOCFPGA_XLOAD
 	bool
-	prompt "Build preloader image"
+	depends on ARCH_SOCFPGA_CYCLONE5
+	prompt "Build SoCFPGA preloader image"
 
-comment "Altera SoCFPGA System-on-Chip"
+menu "SoCFPGA boards"
+
+if 32BIT
 
 config ARCH_SOCFPGA_CYCLONE5
 	bool
 	select CPU_V7
+	select ARM_SMP_TWD
 	select OFDEVICE if !ARCH_SOCFPGA_XLOAD
 	select OFTREE if !ARCH_SOCFPGA_XLOAD
 	select GPIOLIB if !ARCH_SOCFPGA_XLOAD
@@ -18,13 +22,12 @@ config ARCH_SOCFPGA_CYCLONE5
 config ARCH_SOCFPGA_ARRIA10
 	bool
 	select CPU_V7
+	select ARM_SMP_TWD
 	select ARM_USE_COMPRESSED_DTB
 	select RESET_CONTROLLER
 	select OFDEVICE
 	select OFTREE
 
-if 32BIT
-
 comment "Cyclone5 boards"
 
 config MACH_SOCFPGA_ALTERA_SOCDK
@@ -58,4 +61,30 @@ config MACH_SOCFPGA_REFLEX_ACHILLES
 	bool "Reflex Achilles"
 
 endif
+
+if 64BIT
+
+config ARCH_SOCFPGA_AGILEX5
+	bool
+	select CPU_V8
+	select ARM_USE_COMPRESSED_DTB
+	select RESET_CONTROLLER
+	select RESET_SIMPLE
+	select OFDEVICE
+	select OFTREE
+	select FIRMWARE_AGILEX5_ATF
+	select ARM_ATF
+	select ARM_SMCCC
+
+
+comment "SoCFPGA Agilex5 boards"
+
+config MACH_SOCFPGA_ARROW_AXE5_EAGLE
+       bool "Arrow AXE5 Eagle"
+       select ARCH_SOCFPGA_AGILEX5
+
+endif
+
+endmenu
+
 endif
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 008dbc38877211fe1f317cb8eb660d8514611ddd..c54d2a2893417da5dfc92915d1ca7719be53a2e4 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -14,6 +14,19 @@ obj-pbl-$(CONFIG_ARCH_SOCFPGA_ARRIA10) += arria10-bootsource.o \
 					  arria10-init.o \
 					  arria10-sdram.o
 
+pbl-$(CONFIG_ARCH_SOCFPGA_AGILEX5) += soc64-system-manager.o \
+				soc64-wrap-handoff.o \
+				iossm_mailbox.o \
+				mailbox_s10.o \
+				agilex5-sdram.o \
+				agilex5-secreg.o \
+				agilex5-clock-manager.o \
+				atf.o
+
+obj-$(CONFIG_ARCH_SOCFPGA_AGILEX5) += secure_reg_helper.o \
+			        mailbox_s10.o \
+				      smc_api.o
+
 ifdef CONFIG_ARCH_SOCFPGA_CYCLONE5
 obj-$(CONFIG_ARCH_SOCFPGA_XLOAD) += xload.o
 endif
diff --git a/arch/arm/mach-socfpga/agilex5-clock-manager.c b/arch/arm/mach-socfpga/agilex5-clock-manager.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ce7a2d4a2e5af56bf1938157dc245eb0ae85795
--- /dev/null
+++ b/arch/arm/mach-socfpga/agilex5-clock-manager.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019-2023 Intel Corporation <www.intel.com>
+ */
+
+#include <common.h>
+#include <io.h>
+#include <asm/system.h>
+#include <dt-bindings/clock/intel,agilex5-clkmgr.h>
+#include <linux/bitops.h>
+#include <clock.h>
+#include <mach/socfpga/agilex5-clk.h>
+#include <mach/socfpga/generic.h>
+#include <mach/socfpga/soc64-handoff.h>
+#include <mach/socfpga/soc64-regs.h>
+
+#define MPIDR_AFF1_OFFSET	8
+#define MPIDR_AFF1_MASK		0x3
+#define CORE0		1
+#define CORE1		2
+#define CORE2		3
+#define CORE3		4
+
+/* Derived from l4_main_clk (PSS clock) */
+#define COUNTER_FREQUENCY_REAL	400000000
+
+struct socfpga_clk_plat {
+	void __iomem *regs;
+};
+
+static void cm_wait_for_lock(u32 mask)
+{
+	register uint32_t inter_val;
+
+	do {
+		inter_val = readl(SOCFPGA_CLKMGR_ADDRESS + CLKMGR_STAT) & mask;
+	} while (inter_val != mask);
+}
+
+/* function to poll in the fsm busy bit */
+static void cm_wait_for_fsm(void)
+{
+	register u32 inter_val;
+
+	do {
+		inter_val = readl(SOCFPGA_CLKMGR_ADDRESS + CLKMGR_STAT) &
+				CLKMGR_STAT_BUSY;
+	} while (inter_val);
+}
+
+/*
+ * function to write the bypass register which requires a poll of the
+ * busy bit
+ */
+static void clk_write_bypass_mainpll(struct socfpga_clk_plat *plat, u32 val)
+{
+	CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_BYPASS);
+	cm_wait_for_fsm();
+}
+
+static void clk_write_bypass_perpll(struct socfpga_clk_plat *plat, u32 val)
+{
+	CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_BYPASS);
+	cm_wait_for_fsm();
+}
+
+/* function to write the ctrl register which requires a poll of the busy bit */
+static void clk_write_ctrl(struct socfpga_clk_plat *plat, u32 val)
+{
+	CM_REG_WRITEL(plat, val, CLKMGR_CTRL);
+	cm_wait_for_fsm();
+}
+
+#define MEMBUS_MAINPLL				0
+#define MEMBUS_PERPLL				1
+#define MEMBUS_TIMEOUT				1000
+
+#define MEMBUS_CLKSLICE_REG				0x27
+#define MEMBUS_SYNTHCALFOSC_INIT_CENTERFREQ_REG		0xb3
+#define MEMBUS_SYNTHPPM_WATCHDOGTMR_VF01_REG		0xe6
+#define MEMBUS_CALCLKSLICE0_DUTY_LOCOVR_REG		0x03
+#define MEMBUS_CALCLKSLICE1_DUTY_LOCOVR_REG		0x07
+
+static const struct {
+	u32 reg;
+	u32 val;
+	u32 mask;
+} membus_pll[] = {
+	{
+		MEMBUS_CLKSLICE_REG,
+		/*
+		 * BIT[7:7]
+		 * Enable source synchronous mode
+		 */
+		BIT(7),
+		BIT(7)
+	},
+	{
+		MEMBUS_SYNTHCALFOSC_INIT_CENTERFREQ_REG,
+		/*
+		 * BIT[0:0]
+		 * Sets synthcalfosc_init_centerfreq=1 to limit overshoot
+		 * frequency during lock
+		 */
+		BIT(0),
+		BIT(0)
+	},
+	{
+		MEMBUS_SYNTHPPM_WATCHDOGTMR_VF01_REG,
+		/*
+		 * BIT[0:0]
+		 * Sets synthppm_watchdogtmr_vf0=1 to give the pll more time
+		 * to settle before lock is asserted.
+		 */
+		BIT(0),
+		BIT(0)
+	},
+	{
+		MEMBUS_CALCLKSLICE0_DUTY_LOCOVR_REG,
+		/*
+		 * BIT[6:0]
+		 * Centering duty cycle for clkslice0 output
+		 */
+		0x4a,
+		GENMASK(6, 0)
+	},
+	{
+		MEMBUS_CALCLKSLICE1_DUTY_LOCOVR_REG,
+		/*
+		 * BIT[6:0]
+		 * Centering duty cycle for clkslice1 output
+		 */
+		0x4a,
+		GENMASK(6, 0)
+	},
+};
+
+static int membus_wait_for_req(struct socfpga_clk_plat *plat, u32 pll,
+			       int timeout)
+{
+	int cnt = 0;
+	u32 req_status;
+
+	if (pll == MEMBUS_MAINPLL)
+		req_status = CM_REG_READL(plat, CLKMGR_MAINPLL_MEM);
+	else
+		req_status = CM_REG_READL(plat, CLKMGR_PERPLL_MEM);
+
+	while ((cnt < timeout) && (req_status & CLKMGR_MEM_REQ_SET_MSK)) {
+		if (pll == MEMBUS_MAINPLL)
+			req_status = CM_REG_READL(plat, CLKMGR_MAINPLL_MEM);
+		else
+			req_status = CM_REG_READL(plat, CLKMGR_PERPLL_MEM);
+		cnt++;
+	}
+
+	if (cnt >= timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int membus_write_pll(struct socfpga_clk_plat *plat, u32 pll,
+			    u32 addr_offset, u32 wdat, int timeout)
+{
+	u32 addr;
+	u32 val;
+
+	addr = ((addr_offset | CLKMGR_MEM_ADDR_START) & CLKMGR_MEM_ADDR_MASK);
+
+	val = (CLKMGR_MEM_REQ_SET_MSK | CLKMGR_MEM_WR_SET_MSK |
+	       (wdat << CLKMGR_MEM_WDAT_LSB_OFFSET) | addr);
+
+	if (pll == MEMBUS_MAINPLL)
+		CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_MEM);
+	else
+		CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_MEM);
+
+	return membus_wait_for_req(plat, pll, timeout);
+}
+
+static int membus_read_pll(struct socfpga_clk_plat *plat, u32 pll,
+			   u32 addr_offset, u32 *rdata, int timeout)
+{
+	u32 addr;
+	u32 val;
+
+	addr = ((addr_offset | CLKMGR_MEM_ADDR_START) & CLKMGR_MEM_ADDR_MASK);
+
+	val = ((CLKMGR_MEM_REQ_SET_MSK & ~CLKMGR_MEM_WR_SET_MSK) | addr);
+
+	if (pll == MEMBUS_MAINPLL)
+		CM_REG_WRITEL(plat, val, CLKMGR_MAINPLL_MEM);
+	else
+		CM_REG_WRITEL(plat, val, CLKMGR_PERPLL_MEM);
+
+	*rdata = 0;
+
+	if (membus_wait_for_req(plat, pll, timeout))
+		return -ETIMEDOUT;
+
+	if (pll == MEMBUS_MAINPLL)
+		*rdata = CM_REG_READL(plat, CLKMGR_MAINPLL_MEMSTAT);
+	else
+		*rdata = CM_REG_READL(plat, CLKMGR_PERPLL_MEMSTAT);
+
+	return 0;
+}
+
+static void membus_pll_configs(struct socfpga_clk_plat *plat, u32 pll)
+{
+	int i;
+	u32 rdata;
+
+	for (i = 0; i < ARRAY_SIZE(membus_pll); i++) {
+		membus_read_pll(plat, pll, membus_pll[i].reg,
+				&rdata, MEMBUS_TIMEOUT);
+		membus_write_pll(plat, pll, membus_pll[i].reg,
+			 ((rdata & ~membus_pll[i].mask) | membus_pll[i].val),
+			 MEMBUS_TIMEOUT);
+	}
+}
+
+static u32 calc_vocalib_pll(u32 pllm, u32 pllglob)
+{
+	u32 mdiv, refclkdiv, arefclkdiv, drefclkdiv, mscnt, hscnt, vcocalib;
+
+	mdiv = pllm & CLKMGR_PLLM_MDIV_MASK;
+	arefclkdiv = (pllglob & CLKMGR_PLLGLOB_AREFCLKDIV_MASK) >>
+		      CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET;
+	drefclkdiv = (pllglob & CLKMGR_PLLGLOB_DREFCLKDIV_MASK) >>
+		      CLKMGR_PLLGLOB_DREFCLKDIV_OFFSET;
+	refclkdiv = (pllglob & CLKMGR_PLLGLOB_REFCLKDIV_MASK) >>
+		     CLKMGR_PLLGLOB_REFCLKDIV_OFFSET;
+	mscnt = CLKMGR_VCOCALIB_MSCNT_CONST / (mdiv * BIT(drefclkdiv));
+	if (!mscnt)
+		mscnt = 1;
+	hscnt = (mdiv * mscnt * BIT(drefclkdiv) / refclkdiv) -
+		CLKMGR_VCOCALIB_HSCNT_CONST;
+	vcocalib = (hscnt & CLKMGR_VCOCALIB_HSCNT_MASK) |
+		   ((mscnt << CLKMGR_VCOCALIB_MSCNT_OFFSET) &
+		     CLKMGR_VCOCALIB_MSCNT_MASK);
+
+	return vcocalib;
+}
+
+/*
+ * Setup clocks while making no assumptions about previous state of the clocks.
+ */
+static void clk_basic_init(struct socfpga_clk_plat *plat,
+			   const struct cm_config * const cfg)
+{
+	u32 vcocalib;
+	u32 cntfrq = COUNTER_FREQUENCY_REAL;
+	u32 counter_freq = 0;
+
+
+	if (!cfg)
+		return;
+
+	/* Always force clock manager into boot mode before any configuration */
+	clk_write_ctrl(plat,
+		       CM_REG_READL(plat, CLKMGR_CTRL) | CLKMGR_CTRL_BOOTMODE);
+
+	/* Put both PLLs in bypass */
+	clk_write_bypass_mainpll(plat, CLKMGR_BYPASS_MAINPLL_ALL);
+	clk_write_bypass_perpll(plat, CLKMGR_BYPASS_PERPLL_ALL);
+
+	/* Put both PLLs in Reset and Power Down */
+	CM_REG_CLRBITS(plat, CLKMGR_MAINPLL_PLLGLOB,
+		       CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK);
+	CM_REG_CLRBITS(plat, CLKMGR_PERPLL_PLLGLOB,
+		       CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK);
+
+	/* setup main PLL dividers where calculate the vcocalib value */
+	vcocalib = calc_vocalib_pll(cfg->main_pll_pllm, cfg->main_pll_pllglob);
+	CM_REG_WRITEL(plat, cfg->main_pll_pllglob & ~CLKMGR_PLLGLOB_RST_MASK,
+		      CLKMGR_MAINPLL_PLLGLOB);
+	CM_REG_WRITEL(plat, cfg->main_pll_fdbck, CLKMGR_MAINPLL_FDBCK);
+	CM_REG_WRITEL(plat, vcocalib, CLKMGR_MAINPLL_VCOCALIB);
+	CM_REG_WRITEL(plat, cfg->main_pll_pllc0, CLKMGR_MAINPLL_PLLC0);
+	CM_REG_WRITEL(plat, cfg->main_pll_pllc1, CLKMGR_MAINPLL_PLLC1);
+	CM_REG_WRITEL(plat, cfg->main_pll_pllc2, CLKMGR_MAINPLL_PLLC2);
+	CM_REG_WRITEL(plat, cfg->main_pll_pllc3, CLKMGR_MAINPLL_PLLC3);
+	CM_REG_WRITEL(plat, cfg->main_pll_pllm, CLKMGR_MAINPLL_PLLM);
+	CM_REG_WRITEL(plat, cfg->main_pll_nocclk, CLKMGR_MAINPLL_NOCCLK);
+	CM_REG_WRITEL(plat, cfg->main_pll_nocdiv, CLKMGR_MAINPLL_NOCDIV);
+
+	/* setup peripheral PLL dividers where calculate the vcocalib value */
+	vcocalib = calc_vocalib_pll(cfg->per_pll_pllm, cfg->per_pll_pllglob);
+	CM_REG_WRITEL(plat, cfg->per_pll_pllglob & ~CLKMGR_PLLGLOB_RST_MASK,
+		      CLKMGR_PERPLL_PLLGLOB);
+	CM_REG_WRITEL(plat, cfg->per_pll_fdbck, CLKMGR_PERPLL_FDBCK);
+	CM_REG_WRITEL(plat, vcocalib, CLKMGR_PERPLL_VCOCALIB);
+	CM_REG_WRITEL(plat, cfg->per_pll_pllc0, CLKMGR_PERPLL_PLLC0);
+	CM_REG_WRITEL(plat, cfg->per_pll_pllc1, CLKMGR_PERPLL_PLLC1);
+	CM_REG_WRITEL(plat, cfg->per_pll_pllc2, CLKMGR_PERPLL_PLLC2);
+	CM_REG_WRITEL(plat, cfg->per_pll_pllc3, CLKMGR_PERPLL_PLLC3);
+	CM_REG_WRITEL(plat, cfg->per_pll_pllm, CLKMGR_PERPLL_PLLM);
+	CM_REG_WRITEL(plat, cfg->per_pll_emacctl, CLKMGR_PERPLL_EMACCTL);
+	CM_REG_WRITEL(plat, cfg->per_pll_gpiodiv, CLKMGR_PERPLL_GPIODIV);
+
+	/* Configure ping pong counters in control group */
+	CM_REG_WRITEL(plat, cfg->ctl_emacactr, CLKMGR_CTL_EMACACTR);
+	CM_REG_WRITEL(plat, cfg->ctl_emacbctr, CLKMGR_CTL_EMACBCTR);
+	CM_REG_WRITEL(plat, cfg->ctl_emacptpctr, CLKMGR_CTL_EMACPTPCTR);
+	CM_REG_WRITEL(plat, cfg->ctl_gpiodbctr, CLKMGR_CTL_GPIODBCTR);
+	CM_REG_WRITEL(plat, cfg->ctl_s2fuser0ctr, CLKMGR_CTL_S2FUSER0CTR);
+	CM_REG_WRITEL(plat, cfg->ctl_s2fuser1ctr, CLKMGR_CTL_S2FUSER1CTR);
+	CM_REG_WRITEL(plat, cfg->ctl_psirefctr, CLKMGR_CTL_PSIREFCTR);
+	CM_REG_WRITEL(plat, cfg->ctl_usb31ctr, CLKMGR_CTL_USB31CTR);
+	CM_REG_WRITEL(plat, cfg->ctl_dsuctr, CLKMGR_CTL_DSUCTR);
+	CM_REG_WRITEL(plat, cfg->ctl_core01ctr, CLKMGR_CTL_CORE01CTR);
+	CM_REG_WRITEL(plat, cfg->ctl_core23ctr, CLKMGR_CTL_CORE23CTR);
+	CM_REG_WRITEL(plat, cfg->ctl_core2ctr, CLKMGR_CTL_CORE2CTR);
+	CM_REG_WRITEL(plat, cfg->ctl_core3ctr, CLKMGR_CTL_CORE3CTR);
+
+	/* Take both PLL out of reset and power up */
+	CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLGLOB,
+		       CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK);
+	CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLGLOB,
+		       CLKMGR_PLLGLOB_PD_MASK | CLKMGR_PLLGLOB_RST_MASK);
+
+	/* Membus programming for mainpll */
+	membus_pll_configs(plat, MEMBUS_MAINPLL);
+	/* Membus programming for peripll */
+	membus_pll_configs(plat, MEMBUS_PERPLL);
+
+	/* Enable Main pll clkslices */
+	CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLC0, CLKMGR_PLLCX_EN_SET_MSK);
+	CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLC1, CLKMGR_PLLCX_EN_SET_MSK);
+	CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLC2, CLKMGR_PLLCX_EN_SET_MSK);
+	CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLC3, CLKMGR_PLLCX_EN_SET_MSK);
+
+	/* Enable Periph pll clkslices */
+	CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLC0, CLKMGR_PLLCX_EN_SET_MSK);
+	CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLC1, CLKMGR_PLLCX_EN_SET_MSK);
+	CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLC2, CLKMGR_PLLCX_EN_SET_MSK);
+	CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLC3, CLKMGR_PLLCX_EN_SET_MSK);
+
+	cm_wait_for_lock(CLKMGR_STAT_ALLPLL_LOCKED_MASK);
+
+	CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_MAINPLL_LOSTLOCK);
+	CM_REG_WRITEL(plat, CLKMGR_LOSTLOCK_SET_MASK, CLKMGR_PERPLL_LOSTLOCK);
+
+	CM_REG_SETBITS(plat, CLKMGR_MAINPLL_PLLGLOB, CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK);
+	CM_REG_SETBITS(plat, CLKMGR_PERPLL_PLLGLOB, CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK);
+
+	/* Take all PLLs out of bypass */
+	clk_write_bypass_mainpll(plat, 0);
+	clk_write_bypass_perpll(plat, 0);
+
+	/* Clear the loss of lock bits (write 1 to clear) */
+	CM_REG_CLRBITS(plat, CLKMGR_INTRCLR,
+		       CLKMGR_INTER_PERPLLLOST_MASK |
+		       CLKMGR_INTER_MAINPLLLOST_MASK);
+
+	/* Take all ping pong counters out of reset */
+	CM_REG_CLRBITS(plat, CLKMGR_CTL_EXTCNTRST,
+		       CLKMGR_CTL_EXTCNTRST_ALLCNTRST);
+
+	/* Update with accurate clock frequency */
+	if (current_el() == 3) {
+		asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");
+		asm volatile("mrs %0, cntfrq_el0" : "=r" (counter_freq));
+	}
+
+	/* Out of boot mode */
+	clk_write_ctrl(plat, CM_REG_READL(plat, CLKMGR_CTRL) &
+		       ~CLKMGR_CTRL_BOOTMODE);
+}
+
+int agilex5_clk_init(void)
+{
+	struct socfpga_clk_plat plat;
+	const struct cm_config *cm_default_cfg = cm_get_default_config();
+
+	plat.regs = (void __iomem *)SOCFPGA_CLKMGR_ADDRESS;
+
+	clk_basic_init(&plat, cm_default_cfg);
+
+	return 0;
+}
diff --git a/arch/arm/mach-socfpga/agilex5-sdram.c b/arch/arm/mach-socfpga/agilex5-sdram.c
new file mode 100644
index 0000000000000000000000000000000000000000..96b2b425315fdc0d410f053417944942b3ab8ca0
--- /dev/null
+++ b/arch/arm/mach-socfpga/agilex5-sdram.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019-2024 Intel Corporation <www.intel.com>
+ *
+ */
+#define pr_fmt(fmt) "agilex5-sdram: " fmt
+
+#include <common.h>
+#include <errno.h>
+#include "iossm_mailbox.h"
+#include <xfuncs.h>
+#include <linux/sizes.h>
+#include <linux/bitfield.h>
+#include <mach/socfpga/soc64-firewall.h>
+#include <mach/socfpga/soc64-handoff.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-sdram.h>
+#include <mach/socfpga/soc64-system-manager.h>
+
+/* MPFE NOC registers */
+#define F2SDRAM_SIDEBAND_FLAGOUTSET0	0x50
+#define F2SDRAM_SIDEBAND_FLAGOUTSTATUS0	0x58
+#define SIDEBANDMGR_FLAGOUTSET0_REG	SOCFPGA_F2SDRAM_MGR_ADDRESS +\
+					F2SDRAM_SIDEBAND_FLAGOUTSET0
+#define SIDEBANDMGR_FLAGOUTSTATUS0_REG	SOCFPGA_F2SDRAM_MGR_ADDRESS +\
+					F2SDRAM_SIDEBAND_FLAGOUTSTATUS0
+
+#define PORT_EMIF_CONFIG_OFFSET 4
+
+/* Reset type */
+enum reset_type {
+	POR_RESET,
+	WARM_RESET,
+	COLD_RESET,
+	NCONFIG,
+	JTAG_CONFIG,
+	RSU_RECONFIG
+};
+
+static phys_addr_t io96b_csr_reg_addr[] = {
+	0x18400000, /* IO96B_0 CSR registers address */
+	0x18800000  /* IO96B_1 CSR registers address */
+};
+
+static enum reset_type get_reset_type(u32 val)
+{
+	return (val & ALT_SYSMGR_SCRATCH_REG_3_DDR_RESET_TYPE_MASK) >>
+		ALT_SYSMGR_SCRATCH_REG_3_DDR_RESET_TYPE_SHIFT;
+}
+
+static int set_mpfe_config(void)
+{
+	/* Set mpfe_lite_intfcsel */
+	setbits_le32(IOMEM(SOCFPGA_SYSMGR_ADDRESS) + SYSMGR_SOC64_MPFE_CONFIG, BIT(2));
+
+	/* Set mpfe_lite_active */
+	setbits_le32(IOMEM(SOCFPGA_SYSMGR_ADDRESS) + SYSMGR_SOC64_MPFE_CONFIG, BIT(8));
+
+	pr_debug("%s: mpfe_config: 0x%x\n", __func__,
+	      readl(IOMEM(SOCFPGA_SYSMGR_ADDRESS) + SYSMGR_SOC64_MPFE_CONFIG));
+
+	return 0;
+}
+
+static bool is_ddr_init_hang(void)
+{
+	u32 reg = readl(IOMEM(SOCFPGA_SYSMGR_ADDRESS) +
+			SYSMGR_SOC64_BOOT_SCRATCH_POR0);
+
+	if (reg & ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK)
+		return true;
+
+	return false;
+}
+
+static void ddr_init_inprogress(bool start)
+{
+	if (start)
+		setbits_le32(IOMEM(SOCFPGA_SYSMGR_ADDRESS) +
+				SYSMGR_SOC64_BOOT_SCRATCH_POR0,
+				ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK);
+	else
+		clrbits_le32(IOMEM(SOCFPGA_SYSMGR_ADDRESS) +
+				SYSMGR_SOC64_BOOT_SCRATCH_POR0,
+				ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK);
+}
+
+static int populate_ddr_handoff(struct altera_sdram_plat *plat, struct io96b_info *io96b_ctrl)
+{
+	int i;
+	u32 len = SOC64_HANDOFF_SDRAM_LEN;
+	u32 handoff_table[len];
+
+	/* Read handoff for DDR configuration */
+	socfpga_handoff_read((void *)SOC64_HANDOFF_SDRAM, handoff_table, len);
+
+	/* Read handoff - dual port
+	   FIXME: Intel u-boot has a patch that HACKs this to 0
+	   https://github.com/altera-opensource/meta-intel-fpga-refdes/ \
+	   blob/master/recipes-bsp/u-boot/files/v1-0001-HSD-15015933655-ddr-altera-agilex5-Hack-dual-port-DO-NOT-MERGE.patch
+	   Patch doesn't say why or what is broken here: handoff files? dualport RAM access?
+	 */
+	//plat->dualport = FIELD_GET(BIT(0), handoff_table[PORT_EMIF_CONFIG_OFFSET]);
+	plat->dualport = 0;
+	pr_debug("%s: dualport from handoff: 0x%x\n", __func__, plat->dualport);
+
+	if (plat->dualport)
+		io96b_ctrl->num_port = 2;
+	else
+		io96b_ctrl->num_port = 1;
+
+	/* Read handoff - dual EMIF */
+	plat->dualemif = FIELD_GET(BIT(1), handoff_table[PORT_EMIF_CONFIG_OFFSET]);
+	pr_debug("%s: dualemif from handoff: 0x%x\n", __func__, plat->dualemif);
+
+	if (plat->dualemif)
+		io96b_ctrl->num_instance = 2;
+	else
+		io96b_ctrl->num_instance = 1;
+
+	/* Assign IO96B CSR base address if it is valid */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		io96b_ctrl->io96b[i].io96b_csr_addr = io96b_csr_reg_addr[i];
+		pr_debug("%s: IO96B 0x%llx CSR enabled\n", __func__
+			, io96b_ctrl->io96b[i].io96b_csr_addr);
+	}
+
+	return 0;
+}
+
+static int config_mpfe_sideband_mgr(struct altera_sdram_plat *plat)
+{
+	/* Dual port setting */
+	if (plat->dualport)
+		setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(4));
+
+	/* Dual EMIF setting */
+	if (plat->dualemif) {
+		set_mpfe_config();
+		setbits_le32(SIDEBANDMGR_FLAGOUTSET0_REG, BIT(5));
+	}
+
+	pr_debug("%s: SIDEBANDMGR_FLAGOUTSTATUS0: 0x%x\n", __func__,
+	      readl(SIDEBANDMGR_FLAGOUTSTATUS0_REG));
+
+	return 0;
+}
+
+static void config_ccu_mgr(struct altera_sdram_plat *plat)
+{
+	if (plat->dualport || plat->dualemif) {
+		pr_debug("%s: config interleaving on ccu reg\n", __func__);
+		agilex5_security_interleaving_on();
+	} else {
+		pr_debug("%s: config interleaving off ccu reg\n", __func__);
+		agilex5_security_interleaving_off();
+	}
+}
+
+static bool hps_ocram_dbe_status(void)
+{
+	u32 reg = readl(IOMEM(SOCFPGA_SYSMGR_ADDRESS) +
+			SYSMGR_SOC64_BOOT_SCRATCH_COLD3);
+
+	if (reg & ALT_SYSMGR_SCRATCH_REG_3_OCRAM_DBE_MASK)
+		return true;
+
+	return false;
+}
+
+static bool ddr_ecc_dbe_status(void)
+{
+	u32 reg = readl(IOMEM(SOCFPGA_SYSMGR_ADDRESS) +
+			SYSMGR_SOC64_BOOT_SCRATCH_COLD3);
+
+	if (reg & ALT_SYSMGR_SCRATCH_REG_3_DDR_DBE_MASK)
+		return true;
+
+	return false;
+}
+
+static void sdram_set_firewall(phys_size_t hw_size)
+{
+	phys_size_t value;
+	u32 lower, upper;
+
+	value = SOCFPGA_AGILEX5_DDR_BASE;
+	/* Keep first 1MB of SDRAM memory region as secure region when
+	 * using ATF flow, where the ATF code is located.
+	 */
+	value += SZ_1M;
+
+	/* Setting non-secure MPU region base and base extended */
+	lower = lower_32_bits(value);
+	upper = upper_32_bits(value);
+	FW_MPU_DDR_SCR_WRITEL(lower, FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE);
+	FW_MPU_DDR_SCR_WRITEL(upper & 0xff, FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT);
+	FW_F2SDRAM_DDR_SCR_WRITEL(lower, FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASE);
+	FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff, FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASEEXT);
+
+	/* Setting non-secure Non-MPU region base and base extended */
+	FW_MPU_DDR_SCR_WRITEL(lower, FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE);
+	FW_MPU_DDR_SCR_WRITEL(upper & 0xff, FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT);
+
+	/* Setting non-secure MPU limit and limit extended */
+	value = SOCFPGA_AGILEX5_DDR_BASE + hw_size - 1;
+
+	lower = lower_32_bits(value);
+	upper = upper_32_bits(value);
+
+	FW_MPU_DDR_SCR_WRITEL(lower, FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT);
+	FW_MPU_DDR_SCR_WRITEL(upper & 0xff, FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT);
+
+	/* Setting non-secure Non-MPU limit and limit extended */
+	FW_MPU_DDR_SCR_WRITEL(lower, FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT);
+	FW_MPU_DDR_SCR_WRITEL(upper & 0xff, FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT);
+	FW_MPU_DDR_SCR_WRITEL(BIT(0) | BIT(8), FW_MPU_DDR_SCR_EN_SET);
+
+	FW_F2SDRAM_DDR_SCR_WRITEL(lower, FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMIT);
+	FW_F2SDRAM_DDR_SCR_WRITEL(upper & 0xff, FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMITEXT);
+	FW_F2SDRAM_DDR_SCR_WRITEL(BIT(0), FW_F2SDRAM_DDR_SCR_EN_SET);
+}
+
+int agilex5_ddr_init_full(void)
+{
+	int ret;
+	int i;
+	phys_size_t hw_size;
+	struct altera_sdram_plat plat;
+	struct io96b_info io96b_ctrl;
+
+	enum reset_type reset_t = get_reset_type(SOCFPGA_SYSMGR_ADDRESS +
+						 SYSMGR_SOC64_BOOT_SCRATCH_COLD3);
+	bool full_mem_init = false;
+
+	/* DDR initialization progress status tracking */
+	bool is_ddr_hang_be4_rst = is_ddr_init_hang();
+
+	pr_debug("DDR: SDRAM init in progress ...\n");
+	ddr_init_inprogress(true);
+
+	plat.mpfe_base_addr = IOMEM(SOCFPGA_MPFE_CSR_ADDRESS);
+
+	pr_debug("DDR: Address MPFE 0x%p\n", plat.mpfe_base_addr);
+
+	/* Populating DDR handoff data */
+	pr_debug("DDR: Checking SDRAM configuration in progress ...\n");
+	ret = populate_ddr_handoff(&plat, &io96b_ctrl);
+	if (ret) {
+		pr_debug("DDR: Failed to populate DDR handoff\n");
+		return ret;
+	}
+
+	/* Configuring MPFE sideband manager registers - dual port & dual emif*/
+	ret = config_mpfe_sideband_mgr(&plat);
+	if (ret) {
+		pr_debug("DDR: Failed to configure dual port dual emif\n");
+		return ret;
+	}
+
+	/* Configuring Interleave/Non-interleave ccu registers */
+	config_ccu_mgr(&plat);
+
+	/* Configure if polling is needed for IO96B GEN PLL locked */
+	io96b_ctrl.ckgen_lock = true;
+
+	/* Ensure calibration status passing */
+	io96b_init_mem_cal(&io96b_ctrl);
+
+	/* Initiate IOSSM mailbox */
+	io96b_mb_init(&io96b_ctrl);
+
+	/* Need to trigger re-calibration for DDR DBE */
+	if (ddr_ecc_dbe_status()) {
+		for (i = 0; i < io96b_ctrl.num_instance; i++)
+			io96b_ctrl.io96b[i].cal_status = false;
+
+		io96b_ctrl.overall_cal_status = false;
+	}
+
+	/* Trigger re-calibration if calibration failed */
+	if (!(io96b_ctrl.overall_cal_status)) {
+		pr_debug("DDR: Re-calibration in progress...\n");
+		io96b_trig_mem_cal(&io96b_ctrl);
+	}
+
+	pr_debug("DDR: Calibration success\n");
+
+	/* DDR type, DDR size and ECC status) */
+	ret = io96b_get_mem_technology(&io96b_ctrl);
+	if (ret) {
+		pr_debug("DDR: Failed to get DDR type\n");
+		return ret;
+	}
+
+	ret = io96b_get_mem_width_info(&io96b_ctrl);
+	if (ret) {
+		pr_debug("DDR: Failed to get DDR size\n");
+		return ret;
+	}
+
+	hw_size = (phys_size_t)io96b_ctrl.overall_size * SZ_1G / SZ_8;
+
+	pr_debug("%s: %lld MiB\n", io96b_ctrl.ddr_type, hw_size >> 20);
+
+	ret = io96b_ecc_enable_status(&io96b_ctrl);
+	if (ret) {
+		pr_debug("DDR: Failed to get DDR ECC status\n");
+		return ret;
+	}
+
+	/* Is HPS cold or warm reset? If yes, Skip full memory initialization if ECC
+	 *  enabled to preserve memory content
+	 */
+	if (io96b_ctrl.ecc_status) {
+		full_mem_init = hps_ocram_dbe_status() | ddr_ecc_dbe_status() |
+				is_ddr_hang_be4_rst;
+		if (full_mem_init || !(reset_t == WARM_RESET || reset_t == COLD_RESET)) {
+			ret = io96b_bist_mem_init_start(&io96b_ctrl);
+			if (ret) {
+				pr_debug("DDR: Failed to fully initialize DDR memory\n");
+				return ret;
+			}
+		}
+
+		pr_debug("SDRAM-ECC: Initialized success\n");
+	}
+
+	sdram_set_firewall(hw_size);
+
+	/* Firewall setting for MPFE CSR */
+	/* IO96B0_reg */
+	writel(0x1, SOCFPGA_MPFE_CSR_ADDRESS + 0xd00);
+	/* IO96B1_reg */
+	writel(0x1, SOCFPGA_MPFE_CSR_ADDRESS + 0xd04);
+	/* noc_csr */
+	writel(0x1, SOCFPGA_MPFE_CSR_ADDRESS + 0xd08);
+
+	pr_debug("DDR: firewall init success\n");
+
+	/* Ending DDR driver initialization success tracking */
+	ddr_init_inprogress(false);
+
+	pr_debug("DDR: init success\n");
+
+	return 0;
+}
diff --git a/arch/arm/mach-socfpga/agilex5-secreg.c b/arch/arm/mach-socfpga/agilex5-secreg.c
new file mode 100644
index 0000000000000000000000000000000000000000..042ba10db71c6fbd4a7d164603d3a3600b9ccc1a
--- /dev/null
+++ b/arch/arm/mach-socfpga/agilex5-secreg.c
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <io.h>
+#include <mach/socfpga/debug_ll.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-system-manager.h>
+
+#define BUILD_SOC64_WRITE_SECREG(name, addr)				\
+	static inline void soc64_write_##name(const int offset,		\
+					      const int val,		\
+					      const int mask)		\
+	{								\
+		void __iomem *iomem = IOMEM(addr);			\
+		soc64_set(iomem, offset, val, mask);			\
+	}
+
+static inline void soc64_set(void __iomem *addr, int offset, u32 val, int mask)
+{
+	u32 set_mask;
+
+	if (mask == 0xffffffff)
+		writel(val, addr + offset);
+	else {
+		set_mask = mask & val;
+
+		clrsetbits_le32(addr + offset, mask, set_mask);
+	}
+
+	pr_debug("%s: set 0x%p = 0x%08x & 0x%08x\n", __func__,
+		 addr + offset, val, mask);
+}
+
+BUILD_SOC64_WRITE_SECREG(ccu, SOCFPGA_CCU_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(dce0, SOCFPGA_DCE0_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(dce1, SOCFPGA_DCE1_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(dmi0, SOCFPGA_DMI0_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(dmi1, SOCFPGA_DMI1_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(fpga2soc, SOCFPGA_FPGA2SOC_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(gic_m, SOCFPGA_GIC_M_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(iom, SOCFPGA_CCU_IOM_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(l4_per, SOCFPGA_FIREWALL_L4_PER_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(l4_sys, SOCFPGA_FIREWALL_L4_SYS_ADDRESS)
+BUILD_SOC64_WRITE_SECREG(tcu, SOCFPGA_TCU_ADDRESS)
+
+void agilex5_security_interleaving_off(void)
+{
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 3, 0x1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81300006, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81700006, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81b00006, 0xc1f03e1f);
+
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 3, 0x1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81300006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81700006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81b00006, 0xc1f03e1f);
+
+	soc64_write_gic_m(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 3, 0x1f);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81300006, 0xc1f03e1f);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81700006, 0xc1f03e1f);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81b00006, 0xc1f03e1f);
+
+	soc64_write_tcu(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 3, 0x1f);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81300006, 0xc1f03e1f);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81700006, 0xc1f03e1f);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81b00006, 0xc1f03e1f);
+
+	soc64_write_iom(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 3, 0x1f);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81300006, 0xc1f03e1f);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81700006, 0xc1f03e1f);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81b00006, 0xc1f03e1f);
+
+	soc64_write_dce0(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 3, 0x1f);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81300006, 0xc1f03e1f);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81700006, 0xc1f03e1f);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81b00006, 0xc1f03e1f);
+
+	soc64_write_dce1(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 3, 0x1f);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81300006, 0xc1f03e1f);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81700006, 0xc1f03e1f);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81b00006, 0xc1f03e1f);
+}
+
+void agilex5_security_interleaving_on(void)
+{
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 1, 0x1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81200006, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81600006, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81a00006, 0xc1f03e1f);
+
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 1, 0x1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81200006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81600006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81a00006, 0xc1f03e1f);
+
+	soc64_write_gic_m(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 1, 0x1f);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81200006, 0xc1f03e1f);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81600006, 0xc1f03e1f);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81a00006, 0xc1f03e1f);
+
+	soc64_write_tcu(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 1, 0x1f);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81200006, 0xc1f03e1f);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81600006, 0xc1f03e1f);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81a00006, 0xc1f03e1f);
+
+	soc64_write_iom(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 1, 0x1f);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81200006, 0xc1f03e1f);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81600006, 0xc1f03e1f);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81a00006, 0xc1f03e1f);
+
+	soc64_write_dce0(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 1, 0x1f);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81200006, 0xc1f03e1f);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81600006, 0xc1f03e1f);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81a00006, 0xc1f03e1f);
+
+	soc64_write_dce1(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 1, 0x1f);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG, 0x81200006, 0xc1f03e1f);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG, 0x81600006, 0xc1f03e1f);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG, 0x81a00006, 0xc1f03e1f);
+}
+
+void agilex5_initialize_security_policies(void)
+{
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU1AMIGR_REG, 0, 0x07070777);
+	soc64_write_ccu(SOCFPGA_SECREG_DII1_MPFE_LR_REG, 0x18000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_DII1_MPFE_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_SECREG_DII1_MPFE_BAR_REG, 0xc0e00200, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_CCU_DII2_GIC_LR_REG, 0x1d000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_CCU_DII2_GIC_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_CCU_DII2_GIC_BAR_REG, 0xc0800400, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_LR_REG, 0x20000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_BAR_REG, 0xc1100006, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_LR_REG, 0x40000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_BAR_REG, 0xc1200006, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG, 0x80000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_LR_REG, 0x400000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_BAR_REG, 0xc1600006, 0xc1f03e1f);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG, 0x800000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_LR_REG, 0x4000000, 0xffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_HR_REG, 0, 0xff);
+	soc64_write_ccu(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_BAR_REG, 0x6, 0xf); //
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG, 0x8000000, 0xffffffff);
+	soc64_write_ccu(SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG, 0, 0xff);
+
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU1MIFSR_REG, 0, 0x7070777);
+	soc64_write_fpga2soc(SOCFPGA_FPGA2SOC_PSS_LR_REG, 0x10000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_FPGA2SOC_PSS_HR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_FPGA2SOC_PSS_BAR_REG, 0xc0f00000, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DII1_MPFE_LR_REG, 0x18000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DII1_MPFE_HR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DII1_MPFE_BAR_REG, 0xc0e00200, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_BAR_REG, 0x20000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_LR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_HR_REG, 0xc1100006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_LR_REG, 0x40000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_HR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_BAR_REG, 0xc1200006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG, 0x80000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_LR_REG, 0x400000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_HR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_BAR_REG, 0xc1600006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG, 0x800000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_LR_REG, 0x4000000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_HR_REG, 0, 0xff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_BAR_REG, 0xc1a00006, 0xc1f03e1f);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG, 0x8000000, 0xffffffff);
+	soc64_write_fpga2soc(SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG, 0, 0xff);
+
+	soc64_write_gic_m(SOCFPGA_SECREG_NCAIU1MIFSR_REG, 0, 0x7070777);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG, 0x80000, 0xffffffff);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG, 0, 0xff);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG, 0x800000, 0xffffffff);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG, 0, 0xff);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG, 0x8000000, 0xffffffff);
+	soc64_write_gic_m(SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG, 0, 0xff);
+
+	soc64_write_tcu(SOCFPGA_SECREG_NCAIU1MIFSR_REG, 0, 0x7070777);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG, 0x80000, 0xffffffff);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG, 0, 0xff);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG, 0x800000, 0xffffffff);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG, 0, 0xff);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG, 0x8000000, 0xffffffff);
+	soc64_write_tcu(SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG, 0, 0xff);
+
+	soc64_write_iom(SOCFPGA_SECREG_NCAIU1MIFSR_REG, 0, 0x7070777);
+	soc64_write_iom(SOCFPGA_SECREG_DII1_MPFE_LR_REG, 0x18000, 0xffffffff);
+	soc64_write_iom(SOCFPGA_SECREG_DII1_MPFE_HR_REG, 0, 0xff);
+	soc64_write_iom(SOCFPGA_SECREG_DII1_MPFE_BAR_REG, 0xc0e00200, 0xc1f03e1f);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG, 0x80000, 0xffffffff);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG, 0, 0xff);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG, 0x800000, 0xffffffff);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG, 0, 0xff);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG, 0x8000000, 0xffffffff);
+	soc64_write_iom(SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG, 0, 0xff);
+
+	soc64_write_dce0(SOCFPGA_SECREG_NCAIU1MIFSR_REG, 0, 0x7070777);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG, 0x80000, 0xffffffff);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG, 0, 0xff);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG, 0x800000, 0xffffffff);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG, 0, 0xff);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG, 0x8000000, 0xffffffff);
+	soc64_write_dce0(SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG, 0, 0xff);
+	soc64_write_dce1(SOCFPGA_SECREG_NCAIU1MIFSR_REG, 0, 0x7070777);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG, 0x80000, 0xffffffff);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG, 0, 0xff);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG, 0x800000, 0xffffffff);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG, 0, 0xff);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG, 0x8000000, 0xffffffff);
+	soc64_write_dce1(SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG, 0, 0xff);
+	soc64_write_dmi0(SOCFPGA_DMI0_DMIUSMCTCR_REG, 1, 0x3);
+	soc64_write_dmi0(SOCFPGA_DMI0_DMIUSMCTCR_REG, 3, 0x3);
+	soc64_write_dmi1(SOCFPGA_DMI1_DMIUSMCTCR_REG, 1, 0x3);
+	soc64_write_dmi1(SOCFPGA_DMI1_DMIUSMCTCR_REG, 3, 0x3);
+
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_NAND_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_USB0_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_USB1_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_SPI_MAIN0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_SPI_MAIN1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_SPI_SEC0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_SPI_SEC1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_EMAC0_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_EMAC1_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_EMAC2_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_SDMMC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_GPIO0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_GPIO1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_I2C0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_I2C1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_I2C2_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_I2C3_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_I2C4_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_SP_TIMER0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_SP_TIMER1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_UART0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_UART1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_I3C0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_I3C1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_DMA0_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_DMA1_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_COMBO_PHY_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_per(SOCFPGA_FIREWALL_L4_PER_NAND_SDMA_REG, 0x1010301, 0x1010301);
+
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_DMA_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_EMAC0RX_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_EMAC0TX_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_EMAC1RX_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_EMAC1TX_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_EMAC2RX_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_EMAC2TX_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_NAND_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_NAND_READ_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_NAND_WRITE_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_OCRAM_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_SDMMC_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_USB0_ECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_USB1_CACHEECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_CLOCK_MANAGER_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_IO_MANAGER_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_RESET_MANAGER_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_SYSTEM_MANAGER_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_OSC0_TIMER_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_OSC1_TIMER0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_WATCHDOG0_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_WATCHDOG1_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_WATCHDOG2_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_WATCHDOG3_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_DAP_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_WATCHDOG4_REG, 0x1010301, 0x1010301);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_POWER_MANAGER_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_USB1_RXECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_USB1_TXECC_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_L4_NOC_PROBES_REG, 0x1010001, 0x1010001);
+	soc64_write_l4_sys(SOCFPGA_FIREWALL_L4_SYS_L4_NOC_QOS_REG, 0x1010001, 0x1010001);
+
+	soc64_set(IOMEM(SOCFPGA_FIREWALL_SOC2FPGA_ADDRESS), 0, 0xffe0301, 0xffe0301);
+	soc64_set(IOMEM(SOCFPGA_FIREWALL_LWSOC2FPGA_ADDRESS), 0, 0xffe0301, 0xffe0301);
+	soc64_set(IOMEM(SOCFPGA_FIREWALL_TCU_ADDRESS), 0, 0xffe0301, 0xffe0301);
+
+	/* Enable non-secure access to ocram */
+	clrbits_le32(SOCFPGA_OCRAM_FIREWALL_ADDRESS + 0x18, BIT(0));
+}
diff --git a/arch/arm/mach-socfpga/atf.c b/arch/arm/mach-socfpga/atf.c
new file mode 100644
index 0000000000000000000000000000000000000000..23e2fffdce59c6da4c4e1b632e5ddb9ba22889b1
--- /dev/null
+++ b/arch/arm/mach-socfpga/atf.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <asm/sections.h>
+#include <common.h>
+#include <firmware.h>
+#include <asm-generic/memory_layout.h>
+#include <asm/atf_common.h>
+#include <asm/barebox-arm.h>
+#include <mach/socfpga/atf.h>
+#include <mach/socfpga/generic.h>
+#include <mach/socfpga/soc64-regs.h>
+
+void __noreturn agilex5_load_and_start_image_via_tfa(unsigned long memsize)
+{
+	unsigned long atf_dest = AGILEX5_ATF_BL31_BASE_ADDR;
+	void __noreturn (*bl31)(void) = (void *)atf_dest;
+	const void *tfa;
+	size_t tfa_size;
+
+	pr_debug("Load TFA\n");
+
+	memcpy((void *)AGILEX5_ATF_BL33_BASE_ADDR, __image_start, barebox_image_size);
+
+	get_builtin_firmware(agilex5_bl31_bin, &tfa, &tfa_size);
+
+	memcpy(bl31, tfa, tfa_size);
+
+	asm volatile("msr sp_el2, %0" : :
+		     "r" (AGILEX5_ATF_BL33_BASE_ADDR - 16) :
+		     "cc");
+
+	pr_debug("Jumping to @0x%08lx\n", atf_dest);
+	bl31_entry((uintptr_t)bl31, 0, AGILEX5_ATF_BL33_BASE_ADDR, 0);
+	__builtin_unreachable();
+}
diff --git a/arch/arm/mach-socfpga/cpu_init.c b/arch/arm/mach-socfpga/cpu_init.c
index 73b69c34c56f86c045abc4916e68a6d8af0885cd..048bd0f867065cfa26dedb112a2667453d534af8 100644
--- a/arch/arm/mach-socfpga/cpu_init.c
+++ b/arch/arm/mach-socfpga/cpu_init.c
@@ -1,12 +1,55 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include <common.h>
+#include <io.h>
+#include <debug_ll.h>
 #include <asm/barebox-arm-head.h>
 #include <asm/errata.h>
 #include <mach/socfpga/init.h>
+#include <mach/socfpga/agilex5-clk.h>
+#include <mach/socfpga/mailbox_s10.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-reset-manager.h>
+#include <mach/socfpga/soc64-system-manager.h>
 
+#ifdef CONFIG_CPU_32
 void arria10_cpu_lowlevel_init(void)
 {
 	enable_arm_errata_794072_war();
 	enable_arm_errata_845369_war();
 }
+#else
+void socfpga_agilex5_cpu_lowlevel_init(void)
+{
+	int enable = 0x3;
+	int loadval = ~0;
+	int val;
+
+	arm_cpu_lowlevel_init();
+
+	agilex5_sysmgr_pinmux_init();
+
+	/* Disable all watchdogs */
+	writel(SYSMGR_WDDBG_PAUSE_ALL_CPU, SOCFPGA_SYSMGR_ADDRESS +
+			SYSMGR_SOC64_WDDBG);
+	/* Let everything out of reset but the watchdogs */
+	val = 0xf;
+	writel(val, SOCFPGA_RSTMGR_ADDRESS + RSTMGR_SOC64_PER1MODRST);
+
+	/* de-assert resets */
+	writel(0, SOCFPGA_RSTMGR_ADDRESS + RSTMGR_SOC64_BRGMODRST);
+
+	/* configure DFI_SEL for SDMMC */
+	writel(SYSMGR_SOC64_COMBOPHY_DFISEL_SDMMC,
+	       SOCFPGA_SYSMGR_ADDRESS+ SYSMGR_SOC64_COMBOPHY_DFISEL);
+
+	writel(enable, SOCFPGA_GTIMER_SEC_ADDRESS);
+	asm volatile("msr cntp_ctl_el0, %0" : : "r" (enable));
+	asm volatile("msr cntp_tval_el0, %0" : : "r" (loadval));
+
+	/* configure default base clkmgr clock - 200MHz */
+	val = readl(SOCFPGA_CLKMGR_ADDRESS + CLKMGR_MAINPLL_NOCDIV);
+	val &= 0xfffcffff | (CLKMGR_NOCDIV_SOFTPHY_DIV_ONE << CLKMGR_NOCDIV_SOFTPHY_OFFSET);
+	writel(val, SOCFPGA_CLKMGR_ADDRESS + CLKMGR_MAINPLL_NOCDIV);
+}
+#endif
diff --git a/arch/arm/mach-socfpga/iossm_mailbox.c b/arch/arm/mach-socfpga/iossm_mailbox.c
new file mode 100644
index 0000000000000000000000000000000000000000..0e8c9e36017dd8b0d5b98d73d0c201f3bfb02edd
--- /dev/null
+++ b/arch/arm/mach-socfpga/iossm_mailbox.c
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2022-2024 Intel Corporation <www.intel.com>
+ *
+ */
+
+#define pr_fmt(fmt) "iossm_mailbox: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <linux/bitfield.h>
+#include "iossm_mailbox.h"
+#include <mach/socfpga/generic.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-system-manager.h>
+
+#define ECC_INTSTATUS_SERR SOCFPGA_SYSMGR_ADDRESS + 0x9C
+#define ECC_INISTATUS_DERR SOCFPGA_SYSMGR_ADDRESS + 0xA0
+#define DDR_CSR_CLKGEN_LOCKED_IO96B0_MASK BIT(16)
+#define DDR_CSR_CLKGEN_LOCKED_IO96B1_MASK BIT(17)
+
+#define DDR_CSR_CLKGEN_LOCKED_IO96B_MASK(x)	(i == 0 ? DDR_CSR_CLKGEN_LOCKED_IO96B0_MASK : \
+							DDR_CSR_CLKGEN_LOCKED_IO96B1_MASK)
+#define MAX_RETRY_COUNT 3
+#define NUM_CMD_RESPONSE_DATA 3
+
+#define INTF_IP_TYPE_MASK	GENMASK(31, 29)
+#define INTF_INSTANCE_ID_MASK	GENMASK(28, 24)
+
+/* supported DDR type list */
+static const char *ddr_type_list[7] = {
+		"DDR4", "DDR5", "DDR5_RDIMM", "LPDDR4", "LPDDR5", "QDRIV", "UNKNOWN"
+};
+
+static int wait_for_timeout(const void __iomem *reg, u32 mask, bool set)
+{
+	int timeout = 1000000;
+	int val;
+
+	while (timeout > 0) {
+		val = readl(IOMEM(reg));
+		if (!set)
+			val = ~val;
+
+		if ((val & mask) == mask)
+			return 0;
+		__udelay(10);
+		timeout--;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int is_ddr_csr_clkgen_locked(u32 clkgen_mask, u8 num_port)
+{
+	int ret;
+
+	ret = wait_for_timeout(IOMEM(ECC_INTSTATUS_SERR), clkgen_mask, true);
+	if (ret) {
+		pr_debug("%s: ddr csr clkgena locked is timeout\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Mailbox request function
+ * This function will send the request to IOSSM mailbox and wait for response return
+ *
+ * @io96b_csr_addr: CSR address for the target IO96B
+ * @ip_type:	    IP type for the specified memory interface
+ * @instance_id:    IP instance ID for the specified memory interface
+ * @usr_cmd_type:   User desire IOSSM mailbox command type
+ * @usr_cmd_opcode: User desire IOSSM mailbox command opcode
+ * @cmd_param_*:    Parameters (if applicable) for the requested IOSSM mailbox command
+ * @resp:			Structure contain responses returned from the requested IOSSM
+ *					mailbox command
+ */
+int io96b_mb_req(phys_addr_t io96b_csr_addr, u32 ip_type, u32 instance_id,
+		 u32 usr_cmd_type, u32 usr_cmd_opcode, u32 cmd_param_0,
+		 u32 cmd_param_1, u32 cmd_param_2, u32 cmd_param_3,
+		 u32 cmd_param_4, u32 cmd_param_5, u32 cmd_param_6,
+		 struct io96b_mb_resp *resp)
+{
+	int i;
+	int ret;
+	u32 cmd_req, cmd_resp;
+
+	/* Initialized zeros for responses*/
+	memset(resp, 0x0, sizeof(*resp));
+
+	/* Ensure CMD_REQ is cleared before write any command request */
+	ret = wait_for_timeout((IOMEM(io96b_csr_addr) + IOSSM_CMD_REQ_OFFSET), GENMASK(31, 0), false);
+	if (ret) {
+		pr_err("%s: CMD_REQ not ready\n", __func__);
+		return -1;
+	}
+
+	/* Write CMD_PARAM_* */
+	if (cmd_param_0)
+		writel(cmd_param_0, io96b_csr_addr + IOSSM_CMD_PARAM_0_OFFSET);
+	if (cmd_param_1)
+		writel(cmd_param_1, io96b_csr_addr + IOSSM_CMD_PARAM_1_OFFSET);
+	if (cmd_param_2)
+		writel(cmd_param_2, io96b_csr_addr + IOSSM_CMD_PARAM_2_OFFSET);
+	if (cmd_param_3)
+		writel(cmd_param_3, io96b_csr_addr + IOSSM_CMD_PARAM_3_OFFSET);
+	if (cmd_param_4)
+		writel(cmd_param_4, io96b_csr_addr + IOSSM_CMD_PARAM_4_OFFSET);
+	if (cmd_param_5)
+		writel(cmd_param_5, io96b_csr_addr + IOSSM_CMD_PARAM_5_OFFSET);
+	if (cmd_param_6)
+		writel(cmd_param_6, io96b_csr_addr + IOSSM_CMD_PARAM_6_OFFSET);
+
+	/* Write CMD_REQ (IP_TYPE, IP_INSTANCE_ID, CMD_TYPE and CMD_OPCODE) */
+	cmd_req = (usr_cmd_opcode << 0) | (usr_cmd_type << 16) | (instance_id << 24) |
+		(ip_type << 29);
+	writel(cmd_req, io96b_csr_addr + IOSSM_CMD_REQ_OFFSET);
+	pr_debug("%s: Write 0x%x to IOSSM_CMD_REQ_OFFSET 0x%llx\n", __func__,
+		 cmd_req, io96b_csr_addr + IOSSM_CMD_REQ_OFFSET);
+
+	/* Read CMD_RESPONSE_READY in CMD_RESPONSE_STATUS*/
+	ret = wait_for_timeout((IOMEM(io96b_csr_addr) + IOSSM_CMD_RESPONSE_STATUS_OFFSET),
+			       IOSSM_STATUS_COMMAND_RESPONSE_READY, true);
+	if (ret) {
+		pr_err("%s: CMD_RESPONSE ERROR:\n", __func__);
+		cmd_resp = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+		pr_err("%s: STATUS_GENERAL_ERROR: 0x%x\n", __func__, (cmd_resp >> 1) & 0xF);
+		pr_err("%s: STATUS_CMD_RESPONSE_ERROR: 0x%x\n", __func__, (cmd_resp >> 5) & 0x7);
+	}
+
+	/* read CMD_RESPONSE_STATUS*/
+	resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	pr_debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n", __func__, io96b_csr_addr +
+		IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+	/* read CMD_RESPONSE_DATA_* */
+	resp->cmd_resp_data[0] = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET);
+	pr_debug("%s: IOSSM_CMD_RESPONSE_DATA_0_OFFSET 0x%llx: 0x%x\n",
+		 __func__, io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_0_OFFSET,
+		 resp->cmd_resp_data[i]);
+	resp->cmd_resp_data[1] = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET);
+	pr_debug("%s: IOSSM_CMD_RESPONSE_DATA_1_OFFSET 0x%llx: 0x%x\n",
+		 __func__, io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_1_OFFSET,
+		 resp->cmd_resp_data[i]);
+	resp->cmd_resp_data[2] = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET);
+	pr_debug("%s: IOSSM_CMD_RESPONSE_DATA_2_OFFSET 0x%llx: 0x%x\n",
+		 __func__, io96b_csr_addr + IOSSM_CMD_RESPONSE_DATA_2_OFFSET,
+		 resp->cmd_resp_data[i]);
+
+	resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	pr_debug("%s: CMD_RESPONSE_STATUS 0x%llx: 0x%x\n", __func__,
+		 io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET,
+		 resp->cmd_resp_status);
+
+	/* write CMD_RESPONSE_READY = 0 */
+	clrbits_le32((u32 *)(uintptr_t)(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET),
+		     IOSSM_STATUS_COMMAND_RESPONSE_READY);
+
+	resp->cmd_resp_status = readl(io96b_csr_addr + IOSSM_CMD_RESPONSE_STATUS_OFFSET);
+	pr_debug("%s: CMD_RESPONSE_READY 0x%llx: 0x%x\n", __func__, io96b_csr_addr +
+		 IOSSM_CMD_RESPONSE_STATUS_OFFSET, resp->cmd_resp_status);
+
+	return 0;
+}
+
+/*
+ * Initial function to be called to set memory interface IP type and instance ID
+ * IP type and instance ID need to be determined before sending mailbox command
+ */
+void io96b_mb_init(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	u8 ip_type_ret, instance_id_ret;
+	int i, j, k;
+
+	pr_debug("%s: num_instance %d\n", __func__, io96b_ctrl->num_instance);
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		pr_debug("%s: get memory interface IO96B %d\n", __func__, i);
+		/* Get memory interface IP type and instance ID (IP identifier) */
+		io96b_mb_req_no_param(io96b_ctrl->io96b[i].io96b_csr_addr, 0, 0,
+				      CMD_GET_SYS_INFO, GET_MEM_INTF_INFO, &usr_resp);
+		pr_debug("%s: get response from memory interface IO96B %d\n", __func__, i);
+		/* Retrieve number of memory interface(s) */
+		io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface =
+			IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) & 0x3;
+		pr_debug("%s: IO96B %d: num_mem_interface: 0x%x\n", __func__,
+			 i, io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface);
+
+		/* Retrieve memory interface IP type and instance ID (IP identifier) */
+		j = 0;
+		for (k = 0; k < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; k++) {
+			ip_type_ret = FIELD_GET(INTF_IP_TYPE_MASK, usr_resp.cmd_resp_data[k]);
+			instance_id_ret = FIELD_GET(INTF_INSTANCE_ID_MASK,
+						    usr_resp.cmd_resp_data[k]);
+
+			if (ip_type_ret) {
+				io96b_ctrl->io96b[i].mb_ctrl.ip_type[j] = ip_type_ret;
+				io96b_ctrl->io96b[i].mb_ctrl.ip_instance_id[j] = instance_id_ret;
+				pr_debug("%s: IO96B %d mem_interface %d: ip_type_ret: 0x%x\n",
+					 __func__, i, j, ip_type_ret);
+				pr_debug("%s: IO96B %d mem_interface %d: instance_id_ret: 0x%x\n",
+					 __func__, i, j, instance_id_ret);
+				j++;
+			}
+		}
+	}
+}
+
+int io96b_cal_status(phys_addr_t addr)
+{
+	int ret;
+	u32 cal_success, cal_fail;
+	phys_addr_t status_addr = addr + IOSSM_STATUS_OFFSET;
+	/* Ensure calibration completed */
+	ret = wait_for_timeout(IOMEM(status_addr), IOSSM_STATUS_CAL_BUSY, false);
+	if (ret) {
+		pr_err("%s: SDRAM calibration IO96b instance 0x%llx timeout\n",
+		       __func__, status_addr);
+		hang();
+	}
+
+	/* Calibration status */
+	cal_success = readl(status_addr) & IOSSM_STATUS_CAL_SUCCESS;
+	cal_fail = readl(status_addr) & IOSSM_STATUS_CAL_FAIL;
+
+	if (cal_success && !cal_fail)
+		return 0;
+	else
+		return -EPERM;
+}
+
+void io96b_init_mem_cal(struct io96b_info *io96b_ctrl)
+{
+	int count, i, ret;
+
+	/* Initialize overall calibration status */
+	io96b_ctrl->overall_cal_status = false;
+
+	/* Check initial calibration status for the assigned IO96B*/
+	count = 0;
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		if (io96b_ctrl->ckgen_lock) {
+			ret = is_ddr_csr_clkgen_locked(DDR_CSR_CLKGEN_LOCKED_IO96B_MASK(i),
+						       io96b_ctrl->num_port);
+			if (ret) {
+				pr_err("%s: ckgena_lock iossm IO96B_%d is not locked\n",
+				       __func__, i);
+				hang();
+			}
+		}
+		ret = io96b_cal_status(io96b_ctrl->io96b[i].io96b_csr_addr);
+		if (ret) {
+			io96b_ctrl->io96b[i].cal_status = false;
+			pr_err("%s: Initial DDR calibration IO96B_%d failed %d\n",
+			       __func__, i, ret);
+			hang();
+		}
+		io96b_ctrl->io96b[i].cal_status = true;
+		pr_info("%s: Initial DDR calibration IO96B_%d succeed\n",
+		       __func__, i);
+		count++;
+	}
+
+	io96b_ctrl->overall_cal_status = true;
+}
+
+/*
+ * Trying 3 times re-calibration if initial calibration failed
+ */
+int io96b_trig_mem_cal(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	bool recal_success;
+	int i, j, k;
+	u32 cal_stat_offset;
+	u8 cal_stat;
+	u8 trig_cal_stat;
+	int count = 0;
+
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		if (io96b_ctrl->io96b[i].cal_status)
+			continue;
+
+		for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+			recal_success = false;
+
+			/* Re-calibration first memory interface with failed calibration */
+			for (k = 0; k < MAX_RETRY_COUNT; k++) {
+				/* Get the memory calibration status for memory interface */
+				io96b_mb_req_no_param(io96b_ctrl->io96b[i].io96b_csr_addr,
+					     0, 0, CMD_TRIG_MEM_CAL_OP,
+					     GET_MEM_CAL_STATUS, &usr_resp);
+
+				cal_stat_offset = usr_resp.cmd_resp_data[j];
+				cal_stat = readl(io96b_ctrl->io96b[i].io96b_csr_addr +
+						 cal_stat_offset);
+				if (cal_stat == INTF_MEM_CAL_STATUS_SUCCESS) {
+					recal_success = true;
+					break;
+				}
+				io96b_mb_req_no_param(io96b_ctrl->io96b[i].io96b_csr_addr,
+						      io96b_ctrl->io96b[i].mb_ctrl.ip_type[j],
+						      io96b_ctrl->io96b[i].mb_ctrl.ip_instance_id[j],
+						      CMD_TRIG_MEM_CAL_OP,
+						      TRIG_MEM_CAL, &usr_resp);
+
+				trig_cal_stat =
+					IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status) &
+					BIT(0);
+				pr_debug("%s: Memory calibration triggered status = %d\n",
+					 __func__, trig_cal_stat);
+
+				udelay(1);
+			}
+
+			if (!recal_success) {
+				pr_err("%s: Error as SDRAM calibration failed\n", __func__);
+				hang();
+			}
+		}
+
+		io96b_ctrl->io96b[i].cal_status = true;
+		io96b_ctrl->overall_cal_status = io96b_ctrl->io96b[i].cal_status;
+		pr_info("%s: Initial DDR calibration IO96B_%d succeed\n", __func__, i);
+		count++;
+	}
+
+	if (io96b_ctrl->overall_cal_status)
+		pr_debug("%s: Overall SDRAM calibration success\n", __func__);
+
+	return 0;
+}
+
+int io96b_get_mem_technology(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	u8 ddr_type_ret;
+
+	/* Initialize ddr type */
+	io96b_ctrl->ddr_type = ddr_type_list[6];
+
+	/* Get and ensure all memory interface(s) same DDR type */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+			io96b_mb_req_no_param(io96b_ctrl->io96b[i].io96b_csr_addr,
+					      io96b_ctrl->io96b[i].mb_ctrl.ip_type[j],
+					      io96b_ctrl->io96b[i].mb_ctrl.ip_instance_id[j],
+					      CMD_GET_MEM_INFO, GET_MEM_TECHNOLOGY, &usr_resp);
+
+			ddr_type_ret =
+				IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+				& GENMASK(2, 0);
+
+			if (!strcmp(io96b_ctrl->ddr_type, "UNKNOWN"))
+				io96b_ctrl->ddr_type = ddr_type_list[ddr_type_ret];
+
+			if (ddr_type_list[ddr_type_ret] != io96b_ctrl->ddr_type) {
+				pr_err("%s: Mismatch DDR type on IO96B_%d\n", __func__, i);
+				return -ENOEXEC;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int io96b_get_mem_width_info(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	u16 memory_size;
+	u16 total_memory_size = 0;
+
+	/* Get all memory interface(s) total memory size on all instance(s) */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		memory_size = 0;
+		for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+			io96b_mb_req_no_param(io96b_ctrl->io96b[i].io96b_csr_addr,
+					      io96b_ctrl->io96b[i].mb_ctrl.ip_type[j],
+					      io96b_ctrl->io96b[i].mb_ctrl.ip_instance_id[j],
+					      CMD_GET_MEM_INFO, GET_MEM_WIDTH_INFO, &usr_resp);
+
+			memory_size = memory_size +
+				(usr_resp.cmd_resp_data[1] & GENMASK(7, 0));
+		}
+
+		if (!memory_size) {
+			pr_err("%s: Failed to get valid memory size\n", __func__);
+			return -ENOEXEC;
+		}
+
+		io96b_ctrl->io96b[i].size = memory_size;
+
+		total_memory_size = total_memory_size + memory_size;
+	}
+
+	if (!total_memory_size) {
+		pr_err("%s: Failed to get valid memory size\n", __func__);
+		return -ENOEXEC;
+	}
+
+	io96b_ctrl->overall_size = total_memory_size;
+
+	return 0;
+}
+
+int io96b_ecc_enable_status(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	bool ecc_stat_set = false;
+	bool ecc_stat;
+
+	/* Initialize ECC status */
+	io96b_ctrl->ecc_status = false;
+
+	/* Get and ensure all memory interface(s) same ECC status */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+			io96b_mb_req_no_param(io96b_ctrl->io96b[i].io96b_csr_addr,
+					      io96b_ctrl->io96b[i].mb_ctrl.ip_type[j],
+					      io96b_ctrl->io96b[i].mb_ctrl.ip_instance_id[j],
+					      CMD_TRIG_CONTROLLER_OP, ECC_ENABLE_STATUS,
+					      &usr_resp);
+
+			ecc_stat = ((IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+				     & GENMASK(1, 0)) == 0 ? false : true);
+
+			if (!ecc_stat_set) {
+				io96b_ctrl->ecc_status = ecc_stat;
+				ecc_stat_set = true;
+			}
+
+			if (ecc_stat != io96b_ctrl->ecc_status) {
+				pr_err("%s: Mismatch DDR ECC status on IO96B_%d\n",
+				       __func__, i);
+				return -ENOEXEC;
+			}
+		}
+	}
+
+	pr_debug("%s: ECC enable status: %d\n", __func__, io96b_ctrl->ecc_status);
+
+	return 0;
+}
+
+int io96b_bist_mem_init_start(struct io96b_info *io96b_ctrl)
+{
+	struct io96b_mb_resp usr_resp;
+	int i, j;
+	bool bist_start, bist_success;
+	int timeout = 1000000;
+
+	/* Full memory initialization BIST performed on all memory interface(s) */
+	for (i = 0; i < io96b_ctrl->num_instance; i++) {
+		for (j = 0; j < io96b_ctrl->io96b[i].mb_ctrl.num_mem_interface; j++) {
+			bist_start = false;
+			bist_success = false;
+
+			/* Start memory initialization BIST on full memory address */
+			io96b_mb_req(io96b_ctrl->io96b[i].io96b_csr_addr,
+				     io96b_ctrl->io96b[i].mb_ctrl.ip_type[j],
+				     io96b_ctrl->io96b[i].mb_ctrl.ip_instance_id[j],
+				     CMD_TRIG_CONTROLLER_OP, BIST_MEM_INIT_START,
+				     0x40, 0, 0, 0, 0, 0, 0, &usr_resp);
+
+			bist_start =
+				(IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+				 & BIT(0));
+
+			if (!bist_start) {
+				pr_err("%s: Failed to initialized memory on IO96B_%d\n",
+				       __func__, i);
+				pr_err("%s: BIST_MEM_INIT_START Error code 0x%x\n",
+				       __func__,
+				       (IOSSM_CMD_RESPONSE_DATA_SHORT(usr_resp.cmd_resp_status)
+					& GENMASK(2, 1)) > 0x1);
+				return -ENOEXEC;
+			}
+
+			/* Polling for the initiated memory initialization BIST status */
+			while (!bist_success) {
+				io96b_mb_req_no_param(io96b_ctrl->io96b[i].io96b_csr_addr,
+						      io96b_ctrl->io96b[i].mb_ctrl.ip_type[j],
+						      io96b_ctrl->io96b[i].mb_ctrl.ip_instance_id[j],
+						      CMD_TRIG_CONTROLLER_OP,
+						      BIST_MEM_INIT_STATUS, &usr_resp);
+
+				bist_success = (IOSSM_CMD_RESPONSE_DATA_SHORT
+						(usr_resp.cmd_resp_status) & BIT(0));
+
+				if (!bist_success && (timeout-- < 0)) {
+					pr_err("%s: Timeout initialize memory on IO96B_%d\n",
+					       __func__, i);
+					pr_err("%s: BIST_MEM_INIT_STATUS Error code 0x%x\n",
+					       __func__, (IOSSM_CMD_RESPONSE_DATA_SHORT
+							  (usr_resp.cmd_resp_status) &
+							  GENMASK(2, 1)) > 0x1);
+					return -ETIMEDOUT;
+				}
+
+				__udelay(1);
+			}
+		}
+
+		pr_debug("%s: Memory initialized successfully on IO96B_%d\n", __func__, i);
+	}
+	return 0;
+}
diff --git a/arch/arm/mach-socfpga/iossm_mailbox.h b/arch/arm/mach-socfpga/iossm_mailbox.h
new file mode 100644
index 0000000000000000000000000000000000000000..46704ad6c9dd45d98979631127ad771fc610bb95
--- /dev/null
+++ b/arch/arm/mach-socfpga/iossm_mailbox.h
@@ -0,0 +1,157 @@
+#ifndef IOSSM_MAILBOX_H_
+#define IOSSM_MAILBOX_H_
+
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2022-2023 Intel Corporation <www.intel.com>
+ */
+
+#define IOSSM_STATUS_CAL_SUCCESS		BIT(0)
+#define IOSSM_STATUS_CAL_FAIL			BIT(1)
+#define IOSSM_STATUS_CAL_BUSY			BIT(2)
+#define IOSSM_STATUS_COMMAND_RESPONSE_READY	BIT(0)
+#define IOSSM_CMD_RESPONSE_STATUS_OFFSET	0x45C
+#define IOSSM_CMD_RESPONSE_DATA_0_OFFSET	0x458
+#define IOSSM_CMD_RESPONSE_DATA_1_OFFSET	0x454
+#define IOSSM_CMD_RESPONSE_DATA_2_OFFSET	0x450
+#define IOSSM_CMD_REQ_OFFSET			0x43C
+#define IOSSM_CMD_PARAM_0_OFFSET		0x438
+#define IOSSM_CMD_PARAM_1_OFFSET		0x434
+#define IOSSM_CMD_PARAM_2_OFFSET		0x430
+#define IOSSM_CMD_PARAM_3_OFFSET		0x42C
+#define IOSSM_CMD_PARAM_4_OFFSET		0x428
+#define IOSSM_CMD_PARAM_5_OFFSET		0x424
+#define IOSSM_CMD_PARAM_6_OFFSET		0x420
+#define IOSSM_STATUS_OFFSET			0x400
+#define IOSSM_CMD_RESPONSE_DATA_SHORT_MASK	GENMASK(31, 16)
+#define IOSSM_CMD_RESPONSE_DATA_SHORT(data)	(((data) & IOSSM_CMD_RESPONSE_DATA_SHORT_MASK) >> 16)
+#define MAX_IO96B_SUPPORTED			2
+
+/* supported mailbox command type */
+enum iossm_mailbox_cmd_type  {
+	CMD_NOP,
+	CMD_GET_SYS_INFO,
+	CMD_GET_MEM_INFO,
+	CMD_GET_MEM_CAL_INFO,
+	CMD_TRIG_CONTROLLER_OP,
+	CMD_TRIG_MEM_CAL_OP
+};
+
+/* supported mailbox command opcode */
+enum iossm_mailbox_cmd_opcode  {
+	GET_MEM_INTF_INFO	     = 0x0001,
+	GET_MEM_TECHNOLOGY,
+	GET_MEMCLK_FREQ_KHZ,
+	GET_MEM_WIDTH_INFO,
+	ECC_ENABLE_SET		     = 0x0101,
+	ECC_ENABLE_STATUS,
+	ECC_INTERRUPT_STATUS,
+	ECC_INTERRUPT_ACK,
+	ECC_INTERRUPT_MASK,
+	ECC_WRITEBACK_ENABLE,
+	ECC_SCRUB_IN_PROGRESS_STATUS = 0x0201,
+	ECC_SCRUB_MODE_0_START,
+	ECC_SCRUB_MODE_1_START,
+	BIST_STANDARD_MODE_START     = 0x0301,
+	BIST_RESULTS_STATUS,
+	BIST_MEM_INIT_START,
+	BIST_MEM_INIT_STATUS,
+	BIST_SET_DATA_PATTERN_UPPER,
+	BIST_SET_DATA_PATTERN_LOWER,
+	TRIG_MEM_CAL		     = 0x000a,
+	GET_MEM_CAL_STATUS
+};
+
+/* response data of cmd opcode GET_MEM_CAL_STATUS */
+#define INTF_UNUSED			0x0
+#define INTF_MEM_CAL_STATUS_SUCCESS	0x1
+#define INTF_MEM_CAL_STATUS_FAIL	0x2
+#define INTF_MEM_CAL_STATUS_ONGOING	0x4
+
+/*
+ * IOSSM mailbox required information
+ *
+ * @num_mem_interface:	Number of memory interfaces instantiated
+ * @ip_type:		IP type implemented on the IO96B
+ * @ip_instance_id:	IP identifier for every IP instance implemented on the IO96B
+ */
+struct io96b_mb_ctrl {
+	u32 num_mem_interface;
+	u32 ip_type[2];
+	u32 ip_instance_id[2];
+};
+
+/*
+ * IOSSM mailbox response outputs
+ *
+ * @cmd_resp_status: Command Interface status
+ * @cmd_resp_data_*: More spaces for command response
+ */
+struct io96b_mb_resp {
+	u32 cmd_resp_status;
+	u32 cmd_resp_data[3];
+};
+
+/*
+ * IO96B instance specific information
+ *
+ * @size:		Memory size
+ * @io96b_csr_addr:	IO96B instance CSR address
+ * @cal_status:		IO96B instance calibration status
+ * @mb_ctrl:		IOSSM mailbox required information
+ */
+struct io96b_instance {
+	u16 size;
+	phys_addr_t io96b_csr_addr;
+	bool cal_status;
+	struct io96b_mb_ctrl mb_ctrl;
+};
+
+/*
+ * Overall IO96B instance(s) information
+ *
+ * @num_instance:	Number of instance(s) assigned to HPS
+ * @overall_cal_status: Overall calibration status for all IO96B instance(s)
+ * @ddr_type:		DDR memory type
+ * @ecc_status:		ECC enable status (false = disabled, true = enabled)
+ * @overall_size:	Total DDR memory size
+ * @io96b[]:		IO96B instance specific information
+ * @ckgen_lock:		IO96B GEN PLL lock (false = not locked, true = locked)
+ * @num_port:		Number of IO96B port.
+ */
+struct io96b_info {
+	u8			 num_instance;
+	bool			 overall_cal_status;
+	const char		*ddr_type;
+	bool			 ecc_status;
+	u16			 overall_size;
+	struct io96b_instance	 io96b[MAX_IO96B_SUPPORTED];
+	bool			 ckgen_lock;
+	u8			 num_port;
+};
+
+int io96b_mb_req(phys_addr_t io96b_csr_addr, u32 ip_type, u32 instance_id,
+		 u32 usr_cmd_type, u32 usr_cmd_opcode, u32 cmd_param_0,
+		 u32 cmd_param_1, u32 cmd_param_2, u32 cmd_param_3,
+		 u32 cmd_param_4, u32 cmd_param_5, u32 cmd_param_6,
+		 struct io96b_mb_resp *resp);
+
+static inline int io96b_mb_req_no_param(phys_addr_t io96b_csr_addr, u32 ip_type,
+					u32 instance_id, u32 usr_cmd_type,
+					u32 usr_cmd_opcode, struct io96b_mb_resp *resp)
+{
+	return io96b_mb_req(io96b_csr_addr, ip_type, instance_id, usr_cmd_type,
+			    usr_cmd_opcode, 0, 0, 0, 0, 0, 0, 0, resp);
+}
+
+/* Supported IOSSM mailbox function */
+void io96b_mb_init(struct io96b_info *io96b_ctrl);
+int io96b_cal_status(phys_addr_t addr);
+void io96b_init_mem_cal(struct io96b_info *io96b_ctrl);
+int io96b_trig_mem_cal(struct io96b_info *io96b_ctrl);
+int io96b_get_mem_technology(struct io96b_info *io96b_ctrl);
+int io96b_get_mem_width_info(struct io96b_info *io96b_ctrl);
+int io96b_ecc_enable_status(struct io96b_info *io96b_ctrl);
+int io96b_bist_mem_init_start(struct io96b_info *io96b_ctrl);
+
+#endif // IOSSM_MAILBOX_H_
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c
new file mode 100644
index 0000000000000000000000000000000000000000..01a57c1fa5ed1b1d1f65742cff34a93d723f3473
--- /dev/null
+++ b/arch/arm/mach-socfpga/mailbox_s10.c
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2023 Intel Corporation <www.intel.com>
+ *
+ */
+
+#define pr_fmt(fmt) "mailbox_s10: " fmt
+
+#include <common.h>
+#include <io.h>
+#include <mach/socfpga/mailbox_s10.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-system-manager.h>
+
+#define MBOX_READL(reg)			\
+	 readl(SOCFPGA_MAILBOX_ADDRESS + (reg))
+
+#define MBOX_WRITEL(data, reg)		\
+	writel(data, SOCFPGA_MAILBOX_ADDRESS + (reg))
+
+#define MBOX_READ_RESP_BUF(rout)	\
+	MBOX_READL(MBOX_RESP_BUF + ((rout) * sizeof(u32)))
+
+#define MBOX_WRITE_CMD_BUF(data, cin)	\
+	MBOX_WRITEL(data, MBOX_CMD_BUF + ((cin) * sizeof(u32)))
+
+static int mbox_polling_resp(u32 rout)
+{
+	u32 rin;
+	unsigned long i = 2000;
+
+	while (i) {
+		rin = MBOX_READL(MBOX_RIN);
+		if (rout != rin)
+			return 0;
+
+		udelay(1000);
+		i--;
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int mbox_is_cmdbuf_full(u32 cin)
+{
+	return (((cin + 1) % MBOX_CMD_BUFFER_SIZE) == MBOX_READL(MBOX_COUT));
+}
+
+static int mbox_write_cmd_buffer(u32 *cin, u32 data)
+{
+	int timeout = 1000;
+	int is_cmdbuf_overflow = 0;
+
+	while (timeout) {
+		if (mbox_is_cmdbuf_full(*cin)) {
+			if (is_cmdbuf_overflow == 0) {
+				/* Trigger SDM doorbell */
+				MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
+				is_cmdbuf_overflow = 1;
+			}
+			udelay(1000);
+		} else {
+			/* write header to circular buffer */
+			MBOX_WRITE_CMD_BUF(data, (*cin)++);
+			*cin %= MBOX_CMD_BUFFER_SIZE;
+			MBOX_WRITEL(*cin, MBOX_CIN);
+			if (is_cmdbuf_overflow)
+				is_cmdbuf_overflow = 0;
+			break;
+		}
+		timeout--;
+	}
+
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+/* Check for available slot and write to circular buffer.
+ * It also update command valid offset (cin) register.
+ */
+static int mbox_fill_cmd_circular_buff(u32 header, u32 len,
+				       u32 *arg)
+{
+	int i, ret;
+	u32 cin = MBOX_READL(MBOX_CIN) % MBOX_CMD_BUFFER_SIZE;
+
+	ret = mbox_write_cmd_buffer(&cin, header);
+	if (ret)
+		return ret;
+
+	/* write arguments */
+	for (i = 0; i < len; i++) {
+		ret = mbox_write_cmd_buffer(&cin, arg[i]);
+		if (ret)
+			return ret;
+	}
+
+	/* Always trigger the SDM doorbell at the end to ensure SDM able to read
+	 * the remaining data.
+	 */
+	MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
+
+	return 0;
+}
+
+/* Check the command and fill it into circular buffer */
+static int mbox_prepare_cmd_only(u8 id, u32 cmd,
+				 u8 is_indirect, u32 len,
+				 u32 *arg)
+{
+	u32 header;
+	int ret;
+
+	if (cmd > MBOX_MAX_CMD_INDEX)
+		return -EINVAL;
+
+	header = MBOX_CMD_HEADER(MBOX_CLIENT_ID_BAREBOX, id, len,
+				 (is_indirect) ? 1 : 0, cmd);
+
+	ret = mbox_fill_cmd_circular_buff(header, len, arg);
+
+	return ret;
+}
+
+/* Support one command and up to 31 words argument length only */
+static int mbox_send_cmd_common(u8 id, u32 cmd, u8 is_indirect,
+				u32 len, u32 *arg, u8 urgent,
+				u32 *resp_buf_len,
+				u32 *resp_buf)
+{
+	u32 rin;
+	u32 resp;
+	u32 rout;
+	u32 status;
+	u32 resp_len;
+	u32 buf_len;
+	int ret;
+
+	if (urgent) {
+		/* Read status because it is toggled */
+		status = MBOX_READL(MBOX_STATUS) & MBOX_STATUS_UA_MSK;
+		/* Write urgent command to urgent register */
+		MBOX_WRITEL(cmd, MBOX_URG);
+		/* write doorbell */
+		MBOX_WRITEL(1, MBOX_DOORBELL_TO_SDM);
+	} else {
+		ret = mbox_prepare_cmd_only(id, cmd, is_indirect, len, arg);
+		if (ret)
+			return ret;
+	}
+
+	while (1) {
+		ret = 1000;
+
+		/* Wait for doorbell from SDM */
+		do {
+			if (MBOX_READL(MBOX_DOORBELL_FROM_SDM))
+				break;
+			udelay(1000);
+		} while (--ret);
+
+		if (!ret)
+			return -ETIMEDOUT;
+
+		/* clear interrupt */
+		MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
+
+		if (urgent) {
+			u32 new_status = MBOX_READL(MBOX_STATUS);
+
+			/* Urgent ACK is toggled */
+			if ((new_status & MBOX_STATUS_UA_MSK) ^ status)
+				return 0;
+
+			return -ECOMM;
+		}
+
+		/* read current response offset */
+		rout = MBOX_READL(MBOX_ROUT);
+
+		/* read response valid offset */
+		rin = MBOX_READL(MBOX_RIN);
+
+		if (rout != rin) {
+			/* Response received */
+			resp = MBOX_READ_RESP_BUF(rout);
+			rout++;
+			/* wrapping around when it reach the buffer size */
+			rout %= MBOX_RESP_BUFFER_SIZE;
+			/* update next ROUT */
+			MBOX_WRITEL(rout, MBOX_ROUT);
+
+			/* check client ID and ID */
+			if ((MBOX_RESP_CLIENT_GET(resp) ==
+			     MBOX_CLIENT_ID_BAREBOX) &&
+			    (MBOX_RESP_ID_GET(resp) == id)) {
+				int resp_err = MBOX_RESP_ERR_GET(resp);
+
+				if (resp_buf_len) {
+					buf_len = *resp_buf_len;
+					*resp_buf_len = 0;
+				} else {
+					buf_len = 0;
+				}
+
+				resp_len = MBOX_RESP_LEN_GET(resp);
+				while (resp_len) {
+					ret = mbox_polling_resp(rout);
+					if (ret)
+						return ret;
+					/* we need to process response buffer
+					 * even caller doesn't need it
+					 */
+					resp = MBOX_READ_RESP_BUF(rout);
+					rout++;
+					resp_len--;
+					rout %= MBOX_RESP_BUFFER_SIZE;
+					MBOX_WRITEL(rout, MBOX_ROUT);
+					if (buf_len) {
+						/* copy response to buffer */
+						resp_buf[*resp_buf_len] = resp;
+						(*resp_buf_len)++;
+						buf_len--;
+					}
+				}
+				return resp_err;
+			}
+		}
+	}
+
+	return -EIO;
+}
+
+static int mbox_send_cmd_common_retry(u8 id, u32 cmd,
+				      u8 is_indirect,
+				      u32 len, u32 *arg,
+				      u8 urgent,
+				      u32 *resp_buf_len,
+				      u32 *resp_buf)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		ret = mbox_send_cmd_common(id, cmd, is_indirect, len, arg,
+					   urgent, resp_buf_len, resp_buf);
+		if (ret == MBOX_RESP_TIMEOUT || ret == MBOX_RESP_DEVICE_BUSY)
+			udelay(2000); /* wait for 2ms before resend */
+		else
+			break;
+	}
+
+	return ret;
+}
+
+static int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
+			 u8 urgent, u32 *resp_buf_len, u32 *resp_buf)
+{
+	return mbox_send_cmd_common_retry(id, cmd, is_indirect, len, arg,
+					  urgent, resp_buf_len, resp_buf);
+}
+
+int socfpga_mailbox_s10_init(void)
+{
+	int ret;
+
+	/* enable mailbox interrupts */
+	MBOX_WRITEL(MBOX_ALL_INTRS, MBOX_FLAGS);
+
+	/* Ensure urgent request is cleared */
+	MBOX_WRITEL(0, MBOX_URG);
+
+	/* Ensure the Doorbell Interrupt is cleared */
+	MBOX_WRITEL(0, MBOX_DOORBELL_FROM_SDM);
+
+	ret = mbox_send_cmd(MBOX_ID_BAREBOX, MBOX_RESTART, MBOX_CMD_DIRECT, 0,
+		 	    NULL, 1, 0, NULL);
+	if (ret)
+		return ret;
+
+	pr_debug("%s: success...\n", __func__);
+
+	/* Renable mailbox interrupts after MBOX_RESTART */
+	MBOX_WRITEL(MBOX_ALL_INTRS, MBOX_FLAGS);
+
+	return 0;
+}
+
+int socfpga_mailbox_s10_qspi_close(void)
+{
+	return mbox_send_cmd(MBOX_ID_BAREBOX, MBOX_QSPI_CLOSE, MBOX_CMD_DIRECT,
+			     0, NULL, 0, 0, NULL);
+}
+
+int socfpga_mailbox_s10_qspi_open(void)
+{
+	int ret;
+	u32 resp_buf[1];
+	u32 resp_buf_len;
+	u32 reg;
+	u32 clk_khz;
+
+	ret = mbox_send_cmd(MBOX_ID_BAREBOX, MBOX_QSPI_OPEN, MBOX_CMD_DIRECT,
+			    0, NULL, 0, 0, NULL);
+	if (ret) {
+		/* retry again by closing and reopen the QSPI again */
+		ret = socfpga_mailbox_s10_qspi_close();
+		if (ret)
+			return ret;
+
+		ret = mbox_send_cmd(MBOX_ID_BAREBOX, MBOX_QSPI_OPEN,
+				    MBOX_CMD_DIRECT, 0, NULL, 0, 0, NULL);
+		if (ret)
+			return ret;
+	}
+
+	/* HPS will directly control the QSPI controller, no longer mailbox */
+	resp_buf_len = 1;
+	ret = mbox_send_cmd(MBOX_ID_BAREBOX, MBOX_QSPI_DIRECT, MBOX_CMD_DIRECT,
+			    0, NULL, 0, (u32 *)&resp_buf_len,
+			    (u32 *)&resp_buf);
+	if (ret)
+		goto error;
+
+	/* Get the QSPI clock from SDM response and save for later use */
+	clk_khz = resp_buf[0];
+	if (clk_khz < 1000)
+		return -EINVAL;
+
+	clk_khz /= 1000;
+	pr_info("QSPI: reference clock at %d kHZ\n", clk_khz);
+
+	reg = (readl(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_SOC64_BOOT_SCRATCH_COLD0)) &
+		     ~(SYSMGR_SCRATCH_REG_0_QSPI_REFCLK_MASK);
+
+	writel((clk_khz & SYSMGR_SCRATCH_REG_0_QSPI_REFCLK_MASK) | reg,
+	       SOCFPGA_SYSMGR_ADDRESS + SYSMGR_SOC64_BOOT_SCRATCH_COLD0);
+
+	return 0;
+
+error:
+	socfpga_mailbox_s10_qspi_close();
+
+	return ret;
+}
diff --git a/arch/arm/mach-socfpga/secure_reg_helper.c b/arch/arm/mach-socfpga/secure_reg_helper.c
new file mode 100644
index 0000000000000000000000000000000000000000..54d84e84731f87d9cf5fce84c83afb8774d619d0
--- /dev/null
+++ b/arch/arm/mach-socfpga/secure_reg_helper.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2022 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <io.h>
+#include <mach/socfpga/intel-smc.h>
+#include <mach/socfpga/secure_reg_helper.h>
+#include <mach/socfpga/smc_api.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-system-manager.h>
+#include <linux/errno.h>
+
+static int socfpga_secure_convert_reg_id_to_addr(u32 id, phys_addr_t *reg_addr)
+{
+	switch (id) {
+	case SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC0:
+		*reg_addr = SOCFPGA_SYSMGR_ADDRESS + SYSMGR_SOC64_EMAC0;
+		break;
+	case SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC1:
+		*reg_addr = SOCFPGA_SYSMGR_ADDRESS + SYSMGR_SOC64_EMAC1;
+		break;
+	case SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC2:
+		*reg_addr = SOCFPGA_SYSMGR_ADDRESS + SYSMGR_SOC64_EMAC2;
+		break;
+	default:
+		return -EADDRNOTAVAIL;
+	}
+	return 0;
+}
+
+int socfpga_secure_reg_read32(u32 id, u32 *val)
+{
+	int ret;
+	u32 ret_arg[4];
+	phys_addr_t reg_addr;
+
+	ret = socfpga_secure_convert_reg_id_to_addr(id, &reg_addr);
+	if (ret)
+		return ret;
+
+	ret = invoke_smc(INTEL_SIP_SMC_REG_READ, reg_addr, 0, 0, ret_arg);
+	if (ret)
+		return ret;
+
+	*val = ret_arg[0];
+
+	return 0;
+}
+
+int socfpga_secure_reg_write32(u32 id, u32 val)
+{
+	int ret;
+	phys_addr_t reg_addr;
+
+	ret = socfpga_secure_convert_reg_id_to_addr(id, &reg_addr);
+	if (ret)
+		return ret;
+
+	return invoke_smc(INTEL_SIP_SMC_REG_WRITE, reg_addr, (u64) val, 0, 0);
+}
+
+int socfpga_secure_reg_update32(u32 id, u32 mask, u32 val)
+{
+	int ret;
+	phys_addr_t reg_addr;
+
+	ret = socfpga_secure_convert_reg_id_to_addr(id, &reg_addr);
+	if (ret)
+		return ret;
+
+	return invoke_smc(INTEL_SIP_SMC_REG_UPDATE, reg_addr, (u64) mask, (u64) val, 0);
+}
diff --git a/arch/arm/mach-socfpga/smc_api.c b/arch/arm/mach-socfpga/smc_api.c
new file mode 100644
index 0000000000000000000000000000000000000000..98c6dd42d2e22f4231a0e9cdcd833ef4990227a7
--- /dev/null
+++ b/arch/arm/mach-socfpga/smc_api.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020-2024 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <mach/socfpga/intel-smc.h>
+#include <mach/socfpga/smc_api.h>
+#include <linux/arm-smccc.h>
+#include <linux/kernel.h>
+
+int invoke_smc(u32 func_id, u64 arg0, u64 arg1, u64 arg2, u32 *ret_payload)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_smc(func_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+
+	if (ret_payload) {
+		ret_payload[0] = lower_32_bits(res.a0);
+		ret_payload[1] = upper_32_bits(res.a0);
+		ret_payload[2] = lower_32_bits(res.a1);
+		ret_payload[3] = upper_32_bits(res.a1);
+	}
+
+	return res.a0;
+}
+
+int smc_get_usercode(u32 *usercode)
+{
+	u32 res;
+	int ret;
+
+	if (!usercode)
+		return -EINVAL;
+
+	ret = invoke_smc(INTEL_SIP_SMC_GET_USERCODE, 0, 0, 0, &res);
+
+	if (ret == INTEL_SIP_SMC_STATUS_OK)
+		*usercode = res;
+
+	return ret;
+}
diff --git a/arch/arm/mach-socfpga/soc64-system-manager.c b/arch/arm/mach-socfpga/soc64-system-manager.c
new file mode 100644
index 0000000000000000000000000000000000000000..b66a7556975558fe460523322a00a366c9fc68a9
--- /dev/null
+++ b/arch/arm/mach-socfpga/soc64-system-manager.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2021 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <io.h>
+#include <mach/socfpga/soc64-handoff.h>
+#include <mach/socfpga/soc64-regs.h>
+#include <mach/socfpga/soc64-system-manager.h>
+
+/*
+ * Populate the value for SYSMGR.FPGAINTF.MODULE based on pinmux setting.
+ * The value is not wrote to SYSMGR.FPGAINTF.MODULE but
+ * CONFIG_SYSMGR_ISWGRP_HANDOFF.
+ */
+static void populate_sysmgr_fpgaintf_module(void)
+{
+	void __iomem *sysmgr = IOMEM(SOCFPGA_SYSMGR_ADDRESS);
+	u32 handoff_val = 0;
+
+	/* Enable the signal for those HPS peripherals that use FPGA. */
+	if (readl(sysmgr + SYSMGR_SOC64_NAND_USEFPGA) == SYSMGR_FPGAINTF_USEFPGA)
+		handoff_val |= SYSMGR_FPGAINTF_NAND;
+	if (readl(sysmgr + SYSMGR_SOC64_SDMMC_USEFPGA) == SYSMGR_FPGAINTF_USEFPGA)
+		handoff_val |= SYSMGR_FPGAINTF_SDMMC;
+	if (readl(sysmgr + SYSMGR_SOC64_SPIM0_USEFPGA) == SYSMGR_FPGAINTF_USEFPGA)
+		handoff_val |= SYSMGR_FPGAINTF_SPIM0;
+	if (readl(sysmgr + SYSMGR_SOC64_SPIM1_USEFPGA) == SYSMGR_FPGAINTF_USEFPGA)
+		handoff_val |= SYSMGR_FPGAINTF_SPIM1;
+	writel(handoff_val, sysmgr + SYSMGR_SOC64_FPGAINTF_EN2);
+
+	handoff_val = 0;
+	if (readl(sysmgr + SYSMGR_SOC64_EMAC0_USEFPGA) == SYSMGR_FPGAINTF_USEFPGA)
+		handoff_val |= SYSMGR_FPGAINTF_EMAC0;
+	if (readl(sysmgr + SYSMGR_SOC64_EMAC1_USEFPGA) == SYSMGR_FPGAINTF_USEFPGA)
+		handoff_val |= SYSMGR_FPGAINTF_EMAC1;
+	if (readl(sysmgr + SYSMGR_SOC64_EMAC2_USEFPGA) == SYSMGR_FPGAINTF_USEFPGA)
+		handoff_val |= SYSMGR_FPGAINTF_EMAC2;
+	writel(handoff_val, sysmgr + SYSMGR_SOC64_FPGAINTF_EN3);
+}
+
+/*
+ * Configure all the pin muxes
+ */
+static void populate_sysmgr_pinmux(void)
+{
+	u32 len, i;
+	void __iomem *sysmgr = IOMEM(SOCFPGA_SYSMGR_ADDRESS);
+	u32 len_mux = socfpga_get_handoff_size((void __iomem *)SOC64_HANDOFF_MUX);
+	u32 len_ioctl = socfpga_get_handoff_size((void __iomem *)SOC64_HANDOFF_IOCTL);
+	u32 len_fpga = socfpga_get_handoff_size((void __iomem *)SOC64_HANDOFF_FPGA);
+	u32 len_delay = socfpga_get_handoff_size((void __iomem *)SOC64_HANDOFF_DELAY);
+
+	len = (len_mux > len_ioctl) ? len_mux : len_ioctl;
+	len = (len > len_fpga) ? len : len_fpga;
+	len = (len > len_delay) ? len : len_delay;
+
+	u32 handoff_table[len];
+
+	/* setup the pin sel */
+	len = (len_mux < SOC64_HANDOFF_MUX_LEN) ? len_mux : SOC64_HANDOFF_MUX_LEN;
+	socfpga_handoff_read(IOMEM(SOC64_HANDOFF_MUX), handoff_table, len);
+	for (i = 0; i < len; i = i + 2) {
+		writel(handoff_table[i + 1], handoff_table[i] + sysmgr +
+				SYSMGR_SOC64_PINSEL0);
+	}
+
+	/* setup the pin ctrl */
+	len = (len_ioctl < SOC64_HANDOFF_IOCTL_LEN) ? len_ioctl : SOC64_HANDOFF_IOCTL_LEN;
+	socfpga_handoff_read(IOMEM(SOC64_HANDOFF_IOCTL), handoff_table, len);
+	for (i = 0; i < len; i = i + 2) {
+		writel(handoff_table[i + 1], handoff_table[i] + sysmgr +
+				SYSMGR_SOC64_IOCTRL0);
+	}
+
+	/* setup the fpga use */
+	len = (len_fpga < SOC64_HANDOFF_FPGA_LEN) ? len_fpga : SOC64_HANDOFF_FPGA_LEN;
+	socfpga_handoff_read(IOMEM(SOC64_HANDOFF_FPGA), handoff_table, len);
+	for (i = 0; i < len; i = i + 2) {
+		writel(handoff_table[i + 1], handoff_table[i] + sysmgr +
+				SYSMGR_SOC64_EMAC0_USEFPGA);
+	}
+
+	/* setup the IO delay */
+	len = (len_delay < SOC64_HANDOFF_DELAY_LEN) ? len_delay : SOC64_HANDOFF_DELAY_LEN;
+	socfpga_handoff_read(IOMEM(SOC64_HANDOFF_DELAY), handoff_table, len);
+	for (i = 0; i < len; i = i + 2) {
+		writel(handoff_table[i + 1], handoff_table[i] + sysmgr +
+				SYSMGR_SOC64_IODELAY0);
+	}
+}
+
+/*
+ * Configure all the pin muxes
+ */
+void agilex5_sysmgr_pinmux_init(void)
+{
+	populate_sysmgr_pinmux();
+	populate_sysmgr_fpgaintf_module();
+}
diff --git a/arch/arm/mach-socfpga/soc64-wrap-handoff.c b/arch/arm/mach-socfpga/soc64-wrap-handoff.c
new file mode 100644
index 0000000000000000000000000000000000000000..c506e21001f677dd23fb5eb6cc11d06952acf20d
--- /dev/null
+++ b/arch/arm/mach-socfpga/soc64-wrap-handoff.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020-2022 Intel Corporation <www.intel.com>
+ *
+ */
+
+#include <common.h>
+#include <io.h>
+#include <errno.h>
+#include <mach/socfpga/agilex5-clk.h>
+#include <mach/socfpga/soc64-handoff.h>
+
+enum endianness {
+	LITTLE_ENDIAN = 0,
+	BIG_ENDIAN,
+	UNKNOWN_ENDIANNESS
+};
+
+static enum endianness check_endianness(u32 handoff)
+{
+	switch (handoff) {
+	case SOC64_HANDOFF_MAGIC_BOOT:
+	case SOC64_HANDOFF_MAGIC_MUX:
+	case SOC64_HANDOFF_MAGIC_IOCTL:
+	case SOC64_HANDOFF_MAGIC_FPGA:
+	case SOC64_HANDOFF_MAGIC_DELAY:
+	case SOC64_HANDOFF_MAGIC_PERI:
+	case SOC64_HANDOFF_MAGIC_SDRAM:
+	case SOC64_HANDOFF_MAGIC_CLOCK:
+		return BIG_ENDIAN;
+	default:
+		return UNKNOWN_ENDIANNESS;
+	}
+}
+
+static int getting_endianness(void __iomem *handoff_address, enum endianness *endian_t)
+{
+	/* Checking handoff data is little endian ? */
+	*endian_t = check_endianness(readl(handoff_address));
+
+	if (*endian_t == UNKNOWN_ENDIANNESS) {
+		/* Trying to check handoff data is big endian? */
+		*endian_t = check_endianness(swab32(readl(handoff_address)));
+		if (*endian_t == UNKNOWN_ENDIANNESS)
+			return -EPERM;
+	}
+
+	return 0;
+}
+
+const struct cm_config * const cm_get_default_config(void)
+{
+        struct cm_config *cm_handoff_cfg = (struct cm_config *)
+                (SOC64_HANDOFF_CLOCK + SOC64_HANDOFF_OFFSET_DATA);
+        u32 *conversion = (u32 *)cm_handoff_cfg;
+        u32 handoff_clk = readl(SOC64_HANDOFF_CLOCK);
+        u32 i;
+
+        if (swab32(handoff_clk) == SOC64_HANDOFF_MAGIC_CLOCK) {
+                writel(swab32(handoff_clk), SOC64_HANDOFF_CLOCK);
+                for (i = 0; i < (sizeof(*cm_handoff_cfg) / sizeof(u32)); i++)
+                        conversion[i] = swab32(conversion[i]);
+                return cm_handoff_cfg;
+        } else if (handoff_clk == SOC64_HANDOFF_MAGIC_CLOCK) {
+                return cm_handoff_cfg;
+        }
+
+        return NULL;
+}
+
+int socfpga_get_handoff_size(void __iomem *handoff_address)
+{
+	u32 size;
+	int ret;
+	enum endianness endian_t;
+
+	ret = getting_endianness(handoff_address, &endian_t);
+	if (ret)
+		return ret;
+
+	size = readl(handoff_address + SOC64_HANDOFF_OFFSET_LENGTH);
+	if (endian_t == BIG_ENDIAN)
+		size = swab32(size);
+
+	size = (size - SOC64_HANDOFF_OFFSET_DATA) / sizeof(u32);
+
+	return size;
+}
+
+int socfpga_handoff_read(void __iomem *handoff_address, void *table, u32 table_len)
+{
+	u32 temp;
+	u32 *table_x32 = table;
+	u32 i = 0;
+	int ret;
+	enum endianness endian_t;
+
+	ret = getting_endianness(handoff_address, &endian_t);
+	if (ret)
+		return ret;
+
+	temp = readl(handoff_address + SOC64_HANDOFF_OFFSET_DATA +
+		    (i * sizeof(u32)));
+
+	if (endian_t == BIG_ENDIAN)
+		*table_x32 = swab32(temp);
+	else if (endian_t == LITTLE_ENDIAN)
+		*table_x32 = temp;
+
+	for (i = 1; i < table_len; i++) {
+		table_x32++;
+
+		temp = readl(handoff_address +
+			     SOC64_HANDOFF_OFFSET_DATA +
+			     (i * sizeof(u32)));
+
+		if (endian_t == BIG_ENDIAN)
+			*table_x32 = swab32(temp);
+		else if (endian_t == LITTLE_ENDIAN)
+			*table_x32 = temp;
+	}
+
+	return 0;
+}
diff --git a/common/Kconfig.debug_ll b/common/Kconfig.debug_ll
index 1f9255b1a45bce4f432ca8a3462352ded7dc5504..28c0ed496d915a25a3fbdee07a71eb80a45bde7d 100644
--- a/common/Kconfig.debug_ll
+++ b/common/Kconfig.debug_ll
@@ -239,6 +239,20 @@ config DEBUG_SOCFPGA_UART1
 	  Say Y here if you want kernel low-level debugging support
 	  on SOCFPGA(Arria 10) based platforms.
 
+config DEBUG_SOCFPGA_AGILEX5_UART0
+	bool "Use Agilex5 UART0 for low-level debug"
+	depends on ARCH_SOCFPGA_AGILEX5
+	help
+	  Say Y here if you want kernel low-level debugging support
+	  on Agilex5 based platforms.
+
+config DEBUG_SOCFPGA_AGILEX5_UART1
+	bool "Use Agilex5 UART1 for low-level debug"
+	depends on ARCH_SOCFPGA_AGILEX5
+	help
+	  Say Y here if you want kernel low-level debugging support
+	  on Agilex5 based platforms.
+
 config DEBUG_STM32MP_UART
 	bool "Use STM32MP UART4 for low-level debug"
 	depends on ARCH_STM32
@@ -420,12 +434,15 @@ config DEBUG_SOCFPGA_UART_PHYS_ADDR
 	hex "Physical base address of debug UART" if DEBUG_LL
 	default 0xffc02000 if DEBUG_SOCFPGA_UART0
 	default 0xffc02100 if DEBUG_SOCFPGA_UART1
+	default 0x10c02000 if DEBUG_SOCFPGA_AGILEX5_UART0
+	default 0x10c02100 if DEBUG_SOCFPGA_AGILEX5_UART1
 	depends on ARCH_SOCFPGA
 
 config DEBUG_SOCFPGA_UART_CLOCK
 	int "SoCFPGA UART debug clock" if DEBUG_LL
 	default 100000000 if ARCH_SOCFPGA_CYCLONE5
 	default  50000000 if ARCH_SOCFPGA_ARRIA10
+	default 100000000 if ARCH_SOCFPGA_AGILEX5
 	depends on ARCH_SOCFPGA
 	help
 	  Choose UART root clock.
diff --git a/firmware/Kconfig b/firmware/Kconfig
index d068e6d983ca27542a692eb4ff9c8a7d2a9fbc64..61d29e7d917514a999091c442d667c34755ac2f1 100644
--- a/firmware/Kconfig
+++ b/firmware/Kconfig
@@ -41,6 +41,9 @@ config FIRMWARE_IMX8MQ_ATF
 config FIRMWARE_IMX93_ATF
 	bool
 
+config FIRMWARE_AGILEX5_ATF
+	bool
+
 config FIRMWARE_IMX8MM_OPTEE
 	bool "install OP-TEE on i.MX8MM boards"
 	depends on FIRMWARE_IMX8MM_ATF && PBL_OPTEE
diff --git a/firmware/Makefile b/firmware/Makefile
index 2f47e04bee416e2a5c8eea43c01d29e7c83f8056..adb8bb51c8d8c4b2d77ddd93b9df974f5dbfb333 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -17,6 +17,7 @@ pbl-firmware-$(CONFIG_FIRMWARE_IMX8MN_ATF) += imx8mn-bl31.bin$(if $(CONFIG_FIRMW
 pbl-firmware-$(CONFIG_FIRMWARE_IMX8MP_ATF) += imx8mp-bl31.bin$(if $(CONFIG_FIRMWARE_IMX8MP_OPTEE),-optee,)
 pbl-firmware-$(CONFIG_FIRMWARE_IMX8MQ_ATF) += imx8mq-bl31.bin
 pbl-firmware-$(CONFIG_FIRMWARE_IMX93_ATF) += imx93-bl31.bin$(if $(CONFIG_FIRMWARE_IMX93_OPTEE),-optee,)
+pbl-firmware-$(CONFIG_FIRMWARE_AGILEX5_ATF) += agilex5-bl31.bin
 fw-external-$(CONFIG_FIRMWARE_IMX8MM_OPTEE) += imx8mm-bl32.bin
 fw-external-$(CONFIG_FIRMWARE_IMX8MN_OPTEE) += imx8mn-bl32.bin
 fw-external-$(CONFIG_FIRMWARE_IMX8MP_OPTEE) += imx8mp-bl32.bin
diff --git a/images/Makefile.socfpga b/images/Makefile.socfpga
index 7f95bed03297e616532ffb38cb36742b155146f5..807ca78e4ac8636382107f844eeb83ba9007a583 100644
--- a/images/Makefile.socfpga
+++ b/images/Makefile.socfpga
@@ -14,6 +14,14 @@ quiet_cmd_socfpga_image = SOCFPGA-IMG $@
 $(obj)/%.socfpgaimg: $(obj)/% FORCE
 	$(call if_changed,socfpga_image)
 
+# %.hex - convert into Intel hex format
+# ----------------------------------------------------------------
+quiet_cmd_socfpga_objcopy = SOCFPGA-OBJCOPY $@
+      cmd_socfpga_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) -I binary -O ihex --change-address=0x0 $< $@
+
+$(obj)/%.hex: $(obj)/% FORCE
+	$(call if_changed,socfpga_objcopy)
+
 # ----------------------- Cyclone5 based boards ---------------------------
 pblb-$(CONFIG_MACH_SOCFPGA_ALTERA_SOCDK) += start_socfpga_socdk_xload
 FILE_barebox-socfpga-socdk-xload.img = start_socfpga_socdk_xload.pblb.socfpgaimg
diff --git a/include/mach/socfpga/agilex5-clk.h b/include/mach/socfpga/agilex5-clk.h
new file mode 100644
index 0000000000000000000000000000000000000000..9f689db4f0481c0ec353843b15387d94066337d5
--- /dev/null
+++ b/include/mach/socfpga/agilex5-clk.h
@@ -0,0 +1,266 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019-2022 Intel Corporation <www.intel.com>
+ */
+
+#ifndef	_CLK_AGILEX5_
+#define	_CLK_AGILEX5_
+
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#endif
+
+#define CLKMGR_INTOSC_HZ	400000000
+
+#define CM_REG_READL(plat, reg)				\
+	readl((plat)->regs + (reg))
+
+#define CM_REG_WRITEL(plat, data, reg)			\
+	writel(data, (plat)->regs + (reg))
+
+#define CM_REG_CLRBITS(plat, reg, clear)		\
+	clrbits_le32((plat)->regs + (reg), (clear))
+
+#define CM_REG_SETBITS(plat, reg, set)			\
+	setbits_le32((plat)->regs + (reg), (set))
+
+struct cm_config {
+	/* main group */
+	u32 main_pll_nocclk;
+	u32 main_pll_nocdiv;
+	u32 main_pll_pllglob;
+	u32 main_pll_fdbck;
+	u32 main_pll_pllc0;
+	u32 main_pll_pllc1;
+	u32 main_pll_pllc2;
+	u32 main_pll_pllc3;
+	u32 main_pll_pllm;
+
+	/* peripheral group */
+	u32 per_pll_emacctl;
+	u32 per_pll_gpiodiv;
+	u32 per_pll_pllglob;
+	u32 per_pll_fdbck;
+	u32 per_pll_pllc0;
+	u32 per_pll_pllc1;
+	u32 per_pll_pllc2;
+	u32 per_pll_pllc3;
+	u32 per_pll_pllm;
+
+	/* control group */
+	u32 ctl_emacactr;
+	u32 ctl_emacbctr;
+	u32 ctl_emacptpctr;
+	u32 ctl_gpiodbctr;
+	u32 ctl_s2fuser0ctr;
+	u32 ctl_s2fuser1ctr;
+	u32 ctl_psirefctr;
+	u32 ctl_usb31ctr;
+	u32 ctl_dsuctr;
+	u32 ctl_core01ctr;
+	u32 ctl_core23ctr;
+	u32 ctl_core2ctr;
+	u32 ctl_core3ctr;
+
+
+	/* incoming clock */
+	u32 hps_osc_clk_hz;
+	u32 fpga_clk_hz;
+	u32 spare[3];
+};
+
+/* Clock Manager registers */
+#define CLKMGR_CTRL				0
+#define CLKMGR_STAT				4
+#define CLKMGR_TESTIOCTRL			8
+#define CLKMGR_INTRGEN				0x0c
+#define CLKMGR_INTRMSK				0x10
+#define CLKMGR_INTRCLR				0x14
+#define CLKMGR_INTRSTS				0x18
+#define CLKMGR_INTRSTK				0x1c
+#define CLKMGR_INTRRAW				0x20
+
+/* Clock Manager Main PPL group registers */
+#define CLKMGR_MAINPLL_EN			0x24
+#define CLKMGR_MAINPLL_ENS			0x28
+#define CLKMGR_MAINPLL_ENR			0x2c
+#define CLKMGR_MAINPLL_BYPASS			0x30
+#define CLKMGR_MAINPLL_BYPASSS			0x34
+#define CLKMGR_MAINPLL_BYPASSR			0x38
+#define CLKMGR_MAINPLL_NOCCLK			0x40
+#define CLKMGR_MAINPLL_NOCDIV			0x44
+#define CLKMGR_MAINPLL_PLLGLOB			0x48
+#define CLKMGR_MAINPLL_FDBCK			0x4c
+#define CLKMGR_MAINPLL_MEM			0x50
+#define CLKMGR_MAINPLL_MEMSTAT			0x54
+#define CLKMGR_MAINPLL_VCOCALIB			0x58
+#define CLKMGR_MAINPLL_PLLC0			0x5c
+#define CLKMGR_MAINPLL_PLLC1			0x60
+#define CLKMGR_MAINPLL_PLLC2			0x64
+#define CLKMGR_MAINPLL_PLLC3			0x68
+#define CLKMGR_MAINPLL_PLLM			0x6c
+#define CLKMGR_MAINPLL_FHOP			0x70
+#define CLKMGR_MAINPLL_SSC			0x74
+#define CLKMGR_MAINPLL_LOSTLOCK			0x78
+
+/* Clock Manager Peripheral PPL group registers */
+#define CLKMGR_PERPLL_EN			0x7c
+#define CLKMGR_PERPLL_ENS			0x80
+#define CLKMGR_PERPLL_ENR			0x84
+#define CLKMGR_PERPLL_BYPASS			0x88
+#define CLKMGR_PERPLL_BYPASSS			0x8c
+#define CLKMGR_PERPLL_BYPASSR			0x90
+#define CLKMGR_PERPLL_EMACCTL			0x94
+#define CLKMGR_PERPLL_GPIODIV			0x98
+#define CLKMGR_PERPLL_PLLGLOB			0x9c
+#define CLKMGR_PERPLL_FDBCK			0xa0
+#define CLKMGR_PERPLL_MEM			0xa4
+#define CLKMGR_PERPLL_MEMSTAT			0xa8
+#define CLKMGR_PERPLL_VCOCALIB			0xac
+#define CLKMGR_PERPLL_PLLC0			0xb0
+#define CLKMGR_PERPLL_PLLC1			0xb4
+#define CLKMGR_PERPLL_PLLC2			0xb8
+#define CLKMGR_PERPLL_PLLC3			0xbc
+#define CLKMGR_PERPLL_PLLM			0xc0
+#define CLKMGR_PERPLL_FHOP			0xc4
+#define CLKMGR_PERPLL_SSC			0xc8
+#define CLKMGR_PERPLL_LOSTLOCK			0xcc
+
+/* Clock Manager Control group registers */
+#define CLKMGR_CTL_JTAG			0xd0
+#define CLKMGR_CTL_EMACACTR			0xd4
+#define CLKMGR_CTL_EMACBCTR			0xd8
+#define CLKMGR_CTL_EMACPTPCTR			0xdc
+#define CLKMGR_CTL_GPIODBCTR			0xe0
+#define CLKMGR_CTL_S2FUSER0CTR			0xe8
+#define CLKMGR_CTL_S2FUSER1CTR			0xec
+#define CLKMGR_CTL_PSIREFCTR			0xf0
+#define CLKMGR_CTL_EXTCNTRST			0xf4
+#define CLKMGR_CTL_USB31CTR				0xf8
+#define CLKMGR_CTL_DSUCTR				0xfc
+#define CLKMGR_CTL_CORE01CTR			0x100
+#define CLKMGR_CTL_CORE23CTR			0x104
+#define CLKMGR_CTL_CORE2CTR				0x108
+#define CLKMGR_CTL_CORE3CTR				0x10C
+
+#define CLKMGR_CTRL_BOOTMODE			BIT(0)
+
+#define CLKMGR_STAT_BUSY			BIT(0)
+#define CLKMGR_STAT_MAINPLL_LOCKED		BIT(8)
+#define CLKMGR_STAT_MAIN_TRANS			BIT(9)
+#define CLKMGR_STAT_PERPLL_LOCKED		BIT(16)
+#define CLKMGR_STAT_PERF_TRANS			BIT(17)
+#define CLKMGR_STAT_BOOTMODE			BIT(24)
+#define CLKMGR_STAT_BOOTCLKSRC			BIT(25)
+
+#define CLKMGR_STAT_ALLPLL_LOCKED_MASK		\
+	(CLKMGR_STAT_MAINPLL_LOCKED | CLKMGR_STAT_PERPLL_LOCKED)
+
+#define CLKMGR_INTER_MAINPLLLOCKED_MASK		0x00000001
+#define CLKMGR_INTER_PERPLLLOCKED_MASK		0x00000002
+#define CLKMGR_INTER_MAINPLLLOST_MASK		0x00000004
+#define CLKMGR_INTER_PERPLLLOST_MASK		0x00000008
+
+#define CLKMGR_CLKSRC_MASK			GENMASK(18, 16)
+#define CLKMGR_CLKSRC_OFFSET			16
+#define CLKMGR_CLKSRC_MAIN			0
+#define CLKMGR_CLKSRC_PER			1
+#define CLKMGR_CLKSRC_OSC1			2
+#define CLKMGR_CLKSRC_INTOSC			3
+#define CLKMGR_CLKSRC_FPGA			4
+#define CLKMGR_CLKCNT_MSK			GENMASK(10, 0)
+
+#define CLKMGR_BYPASS_MAINPLL_ALL		0xf6
+#define CLKMGR_BYPASS_PERPLL_ALL		0xef
+
+#define CLKMGR_NOCDIV_SOFTPHY_DIV_ONE		0
+#define CLKMGR_NOCDIV_SOFTPHY_DIV_TWO		1
+#define CLKMGR_NOCDIV_SOFTPHY_DIV_FOUR		2
+#define CLKMGR_NOCDIV_L4SYSFREECLK_OFFSET		0
+#define CLKMGR_NOCDIV_L4MPCLK_OFFSET		4
+#define CLKMGR_NOCDIV_L4SPCLK_OFFSET		6
+#define CLKMGR_NOCDIV_SOFTPHY_OFFSET		16
+#define CLKMGR_NOCDIV_CCU_OFFSET			18
+#define CLKMGR_NOCDIV_MPUPERIPH_OFFSET		20
+#define CLKMGR_NOCDIV_CSATCLK_OFFSET		24
+#define CLKMGR_NOCDIV_CSTRACECLK_OFFSET		26
+#define CLKMGR_NOCDIV_CSPDBGCLK_OFFSET		28
+#define CLKMGR_NOCDIV_DIVIDER_MASK		0x3
+
+#define CLKMGR_PLLGLOB_PD_MASK				BIT(0)
+#define CLKMGR_PLLGLOB_RST_MASK				BIT(1)
+#define CLKMGR_PLLGLOB_AREFCLKDIV_MASK			GENMASK(11, 8)
+#define CLKMGR_PLLGLOB_DREFCLKDIV_MASK			GENMASK(13, 12)
+#define CLKMGR_PLLGLOB_REFCLKDIV_MASK			GENMASK(13, 8)
+#define CLKMGR_PLLGLOB_MODCLKDIV_MASK			GENMASK(24, 27)
+#define CLKMGR_PLLGLOB_AREFCLKDIV_OFFSET		8
+#define CLKMGR_PLLGLOB_DREFCLKDIV_OFFSET		12
+#define CLKMGR_PLLGLOB_REFCLKDIV_OFFSET			8
+#define CLKMGR_PLLGLOB_MODCLKDIV_OFFSET			24
+#define CLKMGR_PLLGLOB_VCO_PSRC_MASK			GENMASK(17, 16)
+#define CLKMGR_PLLGLOB_VCO_PSRC_OFFSET			16
+#define CLKMGR_PLLGLOB_CLR_LOSTLOCK_BYPASS_MASK		BIT(29)
+
+#define CLKMGR_VCO_PSRC_EOSC1			0
+#define CLKMGR_VCO_PSRC_INTOSC			1
+#define CLKMGR_VCO_PSRC_F2S			2
+
+#define CLKMGR_MEM_REQ_SET_MSK			BIT(24)
+#define CLKMGR_MEM_WR_SET_MSK			BIT(25)
+#define CLKMGR_MEM_ERR_MSK			BIT(26)
+#define CLKMGR_MEM_WDAT_LSB_OFFSET		16
+#define CLKMGR_MEM_ADDR_MASK			GENMASK(15, 0)
+#define CLKMGR_MEM_ADDR_START			0x00004000
+
+#define CLKMGR_PLLCX_EN_SET_MSK			BIT(27)
+#define CLKMGR_PLLCX_MUTE_SET_MSK		BIT(28)
+
+#define CLKMGR_VCOCALIB_MSCNT_MASK		GENMASK(23, 16)
+#define CLKMGR_VCOCALIB_MSCNT_OFFSET		16
+#define CLKMGR_VCOCALIB_HSCNT_MASK		GENMASK(9, 0)
+#define CLKMGR_VCOCALIB_MSCNT_CONST		100
+#define CLKMGR_VCOCALIB_HSCNT_CONST		4
+
+#define CLKMGR_PLLM_MDIV_MASK			GENMASK(9, 0)
+
+#define CLKMGR_LOSTLOCK_SET_MASK		BIT(0)
+
+#define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK		BIT(5)
+#define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET	26
+#define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK		BIT(26)
+#define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET	27
+#define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK		BIT(27)
+#define CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_OFFSET	28
+#define CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK		BIT(28)
+
+#define CLKMGR_CTL_EMACCTR_SRC_OFFSET		16
+#define CLKMGR_CTL_EMACCTR_SRC_MASK		GENMASK(18, 16)
+#define CLKMGR_CTL_EMACCTR_CNT_OFFSET		0
+#define CLKMGR_CTL_EMACCTR_CNT_MASK		GENMASK(10, 0)
+
+#define CLKMGR_CTL_EXTCNTRST_EMACACNTRST	BIT(0)
+#define CLKMGR_CTL_EXTCNTRST_EMACBCNTRST	BIT(1)
+#define CLKMGR_CTL_EXTCNTRST_EMACPTPCNTRST	BIT(2)
+#define CLKMGR_CTL_EXTCNTRST_GPIODBCNTRST	BIT(3)
+#define CLKMGR_CTL_EXTCNTRST_S2FUSER0CNTRST	BIT(5)
+#define CLKMGR_CTL_EXTCNTRST_S2FUSER1CNTRST	BIT(6)
+#define CLKMGR_CTL_EXTCNTRST_PSIREFCNTRST	BIT(7)
+#define CLKMGR_CTL_EXTCNTRST_USB31REFCNTRST	BIT(8)
+#define CLKMGR_CTL_EXTCNTRST_DSUCNTRST		BIT(10)
+#define CLKMGR_CTL_EXTCNTRST_CORE01CNTRST	BIT(11)
+#define CLKMGR_CTL_EXTCNTRST_CORE2CNTRST	BIT(12)
+#define CLKMGR_CTL_EXTCNTRST_CORE3CNTRST	BIT(13)
+#define CLKMGR_CTL_EXTCNTRST_ALLCNTRST		\
+	(CLKMGR_CTL_EXTCNTRST_EMACACNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_EMACBCNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_EMACPTPCNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_GPIODBCNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_S2FUSER0CNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_S2FUSER1CNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_PSIREFCNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_USB31REFCNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_DSUCNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_CORE01CNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_CORE2CNTRST |	\
+	 CLKMGR_CTL_EXTCNTRST_CORE3CNTRST)
+#endif /* _CLK_AGILEX5_ */
diff --git a/include/mach/socfpga/atf.h b/include/mach/socfpga/atf.h
new file mode 100644
index 0000000000000000000000000000000000000000..a1ae878015bc48613cbdca73ac971f3f3dd844fe
--- /dev/null
+++ b/include/mach/socfpga/atf.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef ATF_H_
+#define ATF_H_
+
+#include <linux/sizes.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/system.h>
+
+#define AGILEX5_ATF_BL31_BASE_ADDR	0x80000000
+#define AGILEX5_ATF_BL33_BASE_ADDR	0x80200000
+
+#endif
diff --git a/include/mach/socfpga/generic.h b/include/mach/socfpga/generic.h
index 40224897c1d2e05b934cd49963ac4ddeaeb28a25..673ccf90a19cda93b0856b7e494c5e519a00b83c 100644
--- a/include/mach/socfpga/generic.h
+++ b/include/mach/socfpga/generic.h
@@ -99,6 +99,9 @@ static inline void arria10_kick_l4wd0(void) {}
 static inline void arria10_watchdog_disable(void) {}
 #endif
 
+int agilex5_clk_init(void);
+void __noreturn agilex5_load_and_start_image_via_tfa(unsigned long memsize);
+
 static inline void __udelay(unsigned us)
 {
 	volatile unsigned int i;
diff --git a/include/mach/socfpga/init.h b/include/mach/socfpga/init.h
index c0e073ee1347cb4d76d74aeb3f513b1764996a59..06c480fe42f131d4f785643cd30e58780b3a0e52 100644
--- a/include/mach/socfpga/init.h
+++ b/include/mach/socfpga/init.h
@@ -5,4 +5,6 @@
 
 void arria10_cpu_lowlevel_init(void);
 
+void socfpga_agilex5_cpu_lowlevel_init(void);
+
 #endif
diff --git a/include/mach/socfpga/intel-smc.h b/include/mach/socfpga/intel-smc.h
new file mode 100644
index 0000000000000000000000000000000000000000..e15fa3d4da21a4da61c759bf26d66a9f4d769210
--- /dev/null
+++ b/include/mach/socfpga/intel-smc.h
@@ -0,0 +1,545 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017-2018, Intel Corporation
+ */
+
+#ifndef __INTEL_SMC_H
+#define __INTEL_SMC_H
+
+#include <linux/arm-smccc.h>
+#include <linux/bitops.h>
+
+/*
+ * This file defines the Secure Monitor Call (SMC) message protocol used for
+ * service layer driver in normal world (EL1) to communicate with secure
+ * monitor software in Secure Monitor Exception Level 3 (EL3).
+ *
+ * This file is shared with secure firmware (FW) which is out of u-boot tree.
+ *
+ * An ARM SMC instruction takes a function identifier and up to 6 64-bit
+ * register values as arguments, and can return up to 4 64-bit register
+ * values. The operation of the secure monitor is determined by the parameter
+ * values passed in through registers.
+
+ * EL1 and EL3 communicates pointer as physical address rather than the
+ * virtual address.
+ */
+
+/*
+ * Functions specified by ARM SMC Calling convention:
+ *
+ * FAST call executes atomic operations, returns when the requested operation
+ * has completed.
+ * STD call starts a operation which can be preempted by a non-secure
+ * interrupt. The call can return before the requested operation has
+ * completed.
+ *
+ * a0..a7 is used as register names in the descriptions below, on arm32
+ * that translates to r0..r7 and on arm64 to w0..w7.
+ */
+
+#define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \
+	ARM_SMCCC_OWNER_SIP, (func_num))
+
+#define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \
+	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
+	ARM_SMCCC_OWNER_SIP, (func_num))
+
+/*
+ * Return values in INTEL_SIP_SMC_* call
+ *
+ * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION:
+ * Secure monitor software doesn't recognize the request.
+ *
+ * INTEL_SIP_SMC_STATUS_OK:
+ * SMC call completed successfully,
+ * In case of FPGA configuration write operation, it means secure monitor
+ * software can accept the next chunk of FPGA configuration data.
+ *
+ * INTEL_SIP_SMC_STATUS_BUSY:
+ * In case of FPGA configuration write operation, it means secure monitor
+ * software is still processing previous data & can't accept the next chunk
+ * of data. Service driver needs to issue
+ * INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE call to query the
+ * completed block(s).
+ *
+ * INTEL_SIP_SMC_STATUS_ERROR:
+ * There is error during the SMC call process.
+ *
+ * INTEL_SIP_SMC_REG_ERROR:
+ * There is error during a read or write operation of the protected
+ * registers.
+ */
+#define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION		0xFFFFFFFF
+#define INTEL_SIP_SMC_STATUS_OK				0x0
+#define INTEL_SIP_SMC_STATUS_BUSY			0x1
+#define INTEL_SIP_SMC_STATUS_REJECTED			0x2
+#define INTEL_SIP_SMC_STATUS_ERROR			0x4
+#define INTEL_SIP_SMC_REG_ERROR				0x5
+#define INTEL_SIP_SMC_RSU_ERROR				0x7
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_START
+ *
+ * Sync call used by service driver at EL1 to request the FPGA in EL3 to
+ * be prepare to receive a new configuration.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_START.
+ * a1: flag for full or partial configuration
+ *    0 full reconfiguration.
+ *    1 partial reconfiguration.
+ * a2-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, or INTEL_SIP_SMC_STATUS_ERROR.
+ * a1-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START 1
+#define INTEL_SIP_SMC_FPGA_CONFIG_START \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START)
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_WRITE
+ *
+ * Async call used by service driver at EL1 to provide FPGA configuration data
+ * to secure world.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_WRITE.
+ * a1: 64bit physical address of the configuration data memory block
+ * a2: Size of configuration data block.
+ * a3-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_STATUS_BUSY,
+ * INTEL_SIP_SMC_STATUS_REJECTED or INTEL_SIP_SMC_STATUS_ERROR.
+ * a1: 64bit physical address of 1st completed memory block if any completed
+ * block, otherwise zero value.
+ * a2: 64bit physical address of 2nd completed memory block if any completed
+ * block, otherwise zero value.
+ * a3: 64bit physical address of 3rd completed memory block if any completed
+ * block, otherwise zero value.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE 2
+#define INTEL_SIP_SMC_FPGA_CONFIG_WRITE \
+	INTEL_SIP_SMC_STD_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE)
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE
+ *
+ * Sync call used by service driver at EL1 to track the completed write
+ * transactions. This request is called after INTEL_SIP_SMC_FPGA_CONFIG_WRITE
+ * call returns INTEL_SIP_SMC_STATUS_BUSY.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_STATUS_BUSY or
+ * INTEL_SIP_SMC_STATUS_ERROR.
+ * a1: 64bit physical address of 1st completed memory block.
+ * a2: 64bit physical address of 2nd completed memory block if
+ * any completed block, otherwise zero value.
+ * a3: 64bit physical address of 3rd completed memory block if
+ * any completed block, otherwise zero value.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE 3
+#define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE \
+INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_ISDONE
+ *
+ * Sync call used by service driver at EL1 to inform secure world that all
+ * data are sent, to check whether or not the secure world had completed
+ * the FPGA configuration process.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_ISDONE.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_STATUS_BUSY or
+ * INTEL_SIP_SMC_STATUS_ERROR.
+ * a1-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE 4
+#define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE)
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM
+ *
+ * Sync call used by service driver at EL1 to query the physical address of
+ * memory block reserved by secure monitor software.
+ *
+ * Call register usage:
+ * a0:INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_STATUS_ERROR.
+ * a1: start of physical address of reserved memory block.
+ * a2: size of reserved memory block.
+ * a3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM 5
+#define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM)
+
+/*
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK
+ *
+ * For SMC loop-back mode only, used for internal integration, debugging
+ * or troubleshooting.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_STATUS_ERROR.
+ * a1-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_LOOPBACK 6
+#define INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_LOOPBACK)
+
+/*
+ * Request INTEL_SIP_SMC_REG_READ
+ *
+ * Read a protected register using SMCCC
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_REG_READ.
+ * a1: register address.
+ * a2-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_REG_ERROR.
+ * a1: Value in the register
+ * a2-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_REG_READ 7
+#define INTEL_SIP_SMC_REG_READ \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_READ)
+
+/*
+ * Request INTEL_SIP_SMC_REG_WRITE
+ *
+ * Write a protected register using SMCCC
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_REG_WRITE.
+ * a1: register address
+ * a2: value to program into register.
+ * a3-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_REG_ERROR.
+ * a1-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_REG_WRITE 8
+#define INTEL_SIP_SMC_REG_WRITE \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_WRITE)
+
+/*
+ * Request INTEL_SIP_SMC_FUNCID_REG_UPDATE
+ *
+ * Update one or more bits in a protected register using a
+ * read-modify-write operation.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_REG_UPDATE.
+ * a1: register address
+ * a2: Write Mask.
+ * a3: Value to write.
+ * a4-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_REG_ERROR.
+ * a1-3: Not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_REG_UPDATE 9
+#define INTEL_SIP_SMC_REG_UPDATE \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_REG_UPDATE)
+
+/*
+* Request INTEL_SIP_SMC_RSU_STATUS
+*
+* Sync call used by service driver at EL1 to query the RSU status
+*
+* Call register usage:
+* a0 INTEL_SIP_SMC_RSU_STATUS
+* a1-7 not used
+*
+* Return status
+* a0: Current Image
+* a1: Last Failing Image
+* a2: Version [width 32 bit] | State [width 32 bit]
+* a3: Error details [width 32 bit] | Error location [width 32 bit]
+*
+* Or
+*
+* a0: INTEL_SIP_SMC_RSU_ERROR
+*/
+#define INTEL_SIP_SMC_FUNCID_RSU_STATUS 11
+#define INTEL_SIP_SMC_RSU_STATUS \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_STATUS)
+
+/*
+* Request INTEL_SIP_SMC_RSU_UPDATE
+*
+* Sync call used by service driver at EL1 to tell you next reboot is RSU_UPDATE
+*
+* Call register usage:
+* a0 INTEL_SIP_SMC_RSU_UPDATE
+* a1 64bit physical address of the configuration data memory in flash
+* a2-7 not used
+*
+* Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+*/
+#define INTEL_SIP_SMC_FUNCID_RSU_UPDATE 12
+#define INTEL_SIP_SMC_RSU_UPDATE \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_UPDATE)
+
+/*
+ * Request INTEL_SIP_SMC_ECC_DBE
+ *
+ * Sync call used by service driver at EL1 alert EL3 that a Double Bit
+ * ECC error has occurred.
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_ECC_DBE
+ * a1 SysManager Double Bit Error value
+ * a2-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ */
+#define INTEL_SIP_SMC_FUNCID_ECC_DBE 13
+#define INTEL_SIP_SMC_ECC_DBE \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_ECC_DBE)
+
+/*
+* Request INTEL_SIP_SMC_RSU_NOTIFY
+*
+* Sync call used by service driver at EL1 to report HPS software execution stage
+*
+* Call register usage:
+* a0 INTEL_SIP_SMC_RSU_NOTIFY
+* a1 32bit HPS software execution stage
+* a2-7 not used
+*
+* Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_REG_ERROR.
+*/
+#define INTEL_SIP_SMC_FUNCID_RSU_NOTIFY 14
+#define INTEL_SIP_SMC_RSU_NOTIFY \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_NOTIFY)
+
+/*
+ * Request INTEL_SIP_SMC_RSU_RETRY_COUNTER
+ *
+ * Sync call used by service driver at EL1 to query the RSU retry counter
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_RSU_RETRY_COUNTER
+ * a1-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_RSU_ERROR.
+ * a1 retry counter
+*/
+#define INTEL_SIP_SMC_FUNCID_RSU_RETRY_COUNTER 15
+#define INTEL_SIP_SMC_RSU_RETRY_COUNTER \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_RETRY_COUNTER)
+
+/*
+ * Request INTEL_SIP_SMC_RSU_DCMF_VERSION
+ *
+ * Sync call used by service driver at EL1 to query DCMF version
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_RSU_DCMF_VERSION
+ * a1-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ * a1 dcmf1 version | dcmf0 version
+ * a2 dcmf3 version | dcmf2 version
+ *
+ * Or
+ *
+ * a0 INTEL_SIP_SMC_RSU_ERROR
+ */
+#define INTEL_SIP_SMC_FUNCID_RSU_DCMF_VERSION 16
+#define INTEL_SIP_SMC_RSU_DCMF_VERSION \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_DCMF_VERSION)
+
+/*
+ * Request INTEL_SIP_SMC_RSU_COPY_DCMF_VERSION
+ *
+ * Sync call used by SSBL (EL2) to copy DCMF version to ATF memory
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_RSU_COPY_DCMF_VERSION
+ * a1 dcmf1 version | dcmf0 version
+ * a2 dcmf3 version | dcmf2 version
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ */
+#define INTEL_SIP_SMC_FUNCID_RSU_COPY_DCMF_VERSION 17
+#define INTEL_SIP_SMC_RSU_COPY_DCMF_VERSION \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_COPY_DCMF_VERSION)
+
+/*
+ * Request INTEL_SIP_SMC_RSU_MAX_RETRY
+ *
+ * Sync call used by service driver at EL1 to query max_retry parameter
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_RSU_MAX_RETRY
+ * a1-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ * a1 max_retry
+ *
+ * Or
+ *
+ * a0 INTEL_SIP_SMC_RSU_ERROR
+ */
+#define INTEL_SIP_SMC_FUNCID_RSU_MAX_RETRY 18
+#define INTEL_SIP_SMC_RSU_MAX_RETRY \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_MAX_RETRY)
+
+/*
+ * Request INTEL_SIP_SMC_RSU_COPY_MAX_RETRY
+ *
+ * Sync call used by SSBL (EL2) to copy RSU 'max retry' to ATF memory
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_RSU_COPY_MAX_RETRY
+ * a1 max retry
+ * a2-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ */
+#define INTEL_SIP_SMC_FUNCID_RSU_COPY_MAX_RETRY 19
+#define INTEL_SIP_SMC_RSU_COPY_MAX_RETRY \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_COPY_MAX_RETRY)
+
+/*
+ * Request INTEL_SIP_SMC_RSU_DCMF_STATUS
+ *
+ * Sync call used by service driver at EL1 to query DCMF status
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_RSU_DCMF_STATUS
+ * a1-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ * a1 dcmf3 status | dcmf2 status | dcmf1 status | dcmf0 status
+ *
+ * Or
+ *
+ * a0 INTEL_SIP_SMC_RSU_ERROR
+ */
+#define INTEL_SIP_SMC_FUNCID_RSU_DCMF_STATUS 20
+#define INTEL_SIP_SMC_RSU_DCMF_STATUS \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_DCMF_STATUS)
+
+/*
+ * Request INTEL_SIP_SMC_RSU_COPY_DCMF_STATUS
+ *
+ * Sync call used by SSBL (EL2) to copy RSU 'dcmf status' to ATF memory
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_RSU_COPY_DCMF_STATUS
+ * a1 dcmf status
+ * a2-7 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ */
+#define INTEL_SIP_SMC_FUNCID_RSU_COPY_DCMF_STATUS 21
+#define INTEL_SIP_SMC_RSU_COPY_DCMF_STATUS \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_RSU_COPY_DCMF_STATUS)
+
+/*
+ * Request INTEL_SIP_SMC_HPS_SET_BRIDGES
+ *
+ * Enable/disable the SoC FPGA bridges
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_HPS_SET_BRIDGES
+ * a1 Set bridges status:
+ *	Bit 0: 0 - Disable, 1 - Enable
+ *	Bit 1: 1 - Has mask value in a2
+ * a2 Mask value
+ *	Bit 0: soc2fpga
+ *	Bit 1: lwhps2fpga
+ *	Bit 2: fpga2soc
+ *	Bit 3: f2sdram0	(For Stratix 10 only)
+ *	Bit 4: f2sdram1	(For Stratix 10 only)
+ *	Bit 5: f2sdram2	(For Stratix 10 only)
+ * a3-7 not used
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK
+ */
+#define INTEL_SIP_SMC_FUNCID_HPS_SET_BRIDGES	50
+#define INTEL_SIP_SMC_HPS_SET_BRIDGES \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_HPS_SET_BRIDGES)
+
+/*
+ * Request INTEL_SIP_SMC_MBOX_SEND_CMD
+ *
+ * Send mailbox command to SDM
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_MBOX_SEND_CMD
+ * a1 Mailbox command
+ * a2 64bit physical address pointer to command's arguments
+ * a3 Length of the argument
+ * a4 Urgent command:
+ *      0 - Disable
+ *      1 - Enable
+ * a5 64bit physical address pointer to a buffer for receiving responses
+ * a6 Length of the buffer
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_STATUS_ERROR
+ * a1 Status of mailbox response
+ * a2 Received length in the buffer
+ */
+#define INTEL_SIP_SMC_FUNCID_MBOX_SEND_CMD	60
+#define INTEL_SIP_SMC_MBOX_SEND_CMD \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_MBOX_SEND_CMD)
+
+/*
+ * Request INTEL_SIP_SMC_GET_USERCODE
+ *
+ * Send mailbox command to get usercode from SDM
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_GET_USERCODE
+ * a1-7 not used.
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_STATUS_ERROR
+ * a1 User code
+ * a2-3 not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_GET_USERCODE	61
+#define INTEL_SIP_SMC_GET_USERCODE \
+	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_GET_USERCODE)
+
+#endif
diff --git a/include/mach/socfpga/mailbox_s10.h b/include/mach/socfpga/mailbox_s10.h
new file mode 100644
index 0000000000000000000000000000000000000000..bba4adbbe87731a011cb84834894c7ba48c4e9b1
--- /dev/null
+++ b/include/mach/socfpga/mailbox_s10.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2023 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef _MAILBOX_S10_H_
+#define _MAILBOX_S10_H_
+
+/* user define barebox ID */
+#include <linux/bitops.h>
+#define MBOX_CLIENT_ID_BAREBOX	0x2
+#define MBOX_ID_BAREBOX		0x2
+
+#define MBOX_CMD_DIRECT	0
+#define MBOX_CMD_INDIRECT	1
+
+#define MBOX_MAX_CMD_INDEX	2047
+#define MBOX_CMD_BUFFER_SIZE	32
+#define MBOX_RESP_BUFFER_SIZE	16
+
+#define MBOX_HDR_CMD_LSB	0
+#define MBOX_HDR_CMD_MSK	(BIT(11) - 1)
+#define MBOX_HDR_I_LSB		11
+#define MBOX_HDR_I_MSK		BIT(11)
+#define MBOX_HDR_LEN_LSB	12
+#define MBOX_HDR_LEN_MSK	0x007FF000
+#define MBOX_HDR_ID_LSB		24
+#define MBOX_HDR_ID_MSK		0x0F000000
+#define MBOX_HDR_CLIENT_LSB	28
+#define MBOX_HDR_CLIENT_MSK	0xF0000000
+
+/* Interrupt flags */
+#define MBOX_FLAGS_INT_COE	BIT(0)	/* COUT update interrupt enable */
+#define MBOX_FLAGS_INT_RIE	BIT(1)	/* RIN update interrupt enable */
+#define MBOX_FLAGS_INT_UAE	BIT(8)	/* Urgent ACK interrupt enable */
+#define MBOX_ALL_INTRS		(MBOX_FLAGS_INT_COE | \
+				 MBOX_FLAGS_INT_RIE | \
+				 MBOX_FLAGS_INT_UAE)
+
+/* Status */
+#define MBOX_STATUS_UA_MSK	BIT(8)
+
+#define MBOX_CMD_HEADER(client, id, len, indirect, cmd)     \
+	((((cmd) << MBOX_HDR_CMD_LSB) & MBOX_HDR_CMD_MSK) | \
+	(((indirect) << MBOX_HDR_I_LSB) & MBOX_HDR_I_MSK) | \
+	(((len) << MBOX_HDR_LEN_LSB) & MBOX_HDR_LEN_MSK)  | \
+	(((id) << MBOX_HDR_ID_LSB) & MBOX_HDR_ID_MSK)     | \
+	(((client) << MBOX_HDR_CLIENT_LSB) & MBOX_HDR_CLIENT_MSK))
+
+#define MBOX_RESP_ERR_GET(resp)				\
+	(((resp) & MBOX_HDR_CMD_MSK) >> MBOX_HDR_CMD_LSB)
+#define MBOX_RESP_LEN_GET(resp)			\
+	(((resp) & MBOX_HDR_LEN_MSK) >> MBOX_HDR_LEN_LSB)
+#define MBOX_RESP_ID_GET(resp)				\
+	(((resp) & MBOX_HDR_ID_MSK) >> MBOX_HDR_ID_LSB)
+#define MBOX_RESP_CLIENT_GET(resp)			\
+	(((resp) & MBOX_HDR_CLIENT_MSK) >> MBOX_HDR_CLIENT_LSB)
+
+/* Response error list */
+enum ALT_SDM_MBOX_RESP_CODE {
+	/* CMD completed successfully, but check resp ARGS for any errors */
+	MBOX_RESP_STATOK = 0,
+	/* CMD is incorrectly formatted in some way */
+	MBOX_RESP_INVALID_COMMAND = 1,
+	/* BootROM Command code not undesrtood */
+	MBOX_RESP_UNKNOWN_BR = 2,
+	/* CMD code not recognized by firmware */
+	MBOX_RESP_UNKNOWN = 3,
+	/* Length setting is not a valid length for this CMD type */
+	MBOX_RESP_INVALID_LEN = 4,
+	/* Indirect setting is not valid for this CMD type */
+	MBOX_RESP_INVALID_INDIRECT_SETTING = 5,
+	/* HW source which is not allowed to send CMD type */
+	MBOX_RESP_CMD_INVALID_ON_SRC = 6,
+	/* Client with ID not associated with any running PR CMD tries to run
+	 * RECONFIG_DATA RECONFIG_STATUS and accessing QSPI / SDMMC using ID
+	 * without exclusive access
+	 */
+	MBOX_RESP_CLIENT_ID_NO_MATCH = 8,
+	/* Address provided to the system is invalid (alignment, range
+	 * permission)
+	 */
+	MBOX_RESP_INVALID_ADDR = 0x9,
+	/* Signature authentication failed */
+	MBOX_RESP_AUTH_FAIL = 0xA,
+	/* CMD timed out */
+	MBOX_RESP_TIMEOUT = 0xB,
+	/* HW (i.e. QSPI) is not ready (initialized or configured) */
+	MBOX_RESP_HW_NOT_RDY = 0xC,
+	/* Function is not supported in this firmware */
+	MBOX_FUNC_NOT_SUPPORTED = 0xF,
+	/* Invalid license for IID registration */
+	MBOX_RESP_PUF_ACCCES_FAILED = 0x80,
+	MBOX_PUF_ENROLL_DISABLE = 0x81,
+	MBOX_RESP_PUF_ENROLL_FAIL = 0x82,
+	MBOX_RESP_PUF_RAM_TEST_FAIL = 0x83,
+	MBOX_RESP_ATTEST_CERT_GEN_FAIL = 0x84,
+	/* Operation not allowed under current security settings */
+	MBOX_RESP_NOT_ALLOWED_UNDER_SECURITY_SETTINGS = 0x85,
+	MBOX_RESP_PUF_TRNG_FAIL = 0x86,
+	MBOX_RESP_FUSE_ALREADY_BLOWN = 0x87,
+	MBOX_RESP_INVALID_SIGNATURE = 0x88,
+	MBOX_RESP_INVALID_HASH = 0x8b,
+	MBOX_RESP_INVALID_CERTIFICATE = 0x91,
+	/* Indicates that the device (FPGA or HPS) is not configured */
+	MBOX_RESP_NOT_CONFIGURED = 0x100,
+	/* Indicates that the device is busy */
+	MBOX_RESP_DEVICE_BUSY = 0x1FF,
+	/* Indicates that there is no valid response available */
+	MBOX_RESP_NO_VALID_RESP_AVAILABLE = 0x2FF,
+	/* General Error */
+	MBOX_RESP_ERROR = 0x3FF,
+};
+
+/* Mailbox command list */
+#define MBOX_RESTART			2
+#define MBOX_CONFIG_STATUS		4
+#define MBOX_RECONFIG			6
+#define MBOX_RECONFIG_MSEL		7
+#define MBOX_RECONFIG_DATA		8
+#define MBOX_RECONFIG_STATUS		9
+#define MBOX_VAB_SRC_CERT		11
+#define MBOX_GET_USERCODE		19
+#define MBOX_QSPI_OPEN			50
+#define MBOX_QSPI_CLOSE			51
+#define MBOX_QSPI_DIRECT		59
+#define MBOX_REBOOT_HPS			71
+#define MBOX_GET_SUBPARTITION_TABLE	90
+#define MBOX_RSU_STATUS			91
+#define MBOX_RSU_UPDATE			92
+#define MBOX_HPS_STAGE_NOTIFY		93
+#define MBOX_QSPI_GET_DEVICE_INFO	116 /* get QSPI size and erasesize */
+
+/* Mailbox response len */
+#define QSPI_GET_DEVICE_INFO_RESP_LEN	8
+
+/* Mailbox registers */
+#define MBOX_CIN			0	/* command valid offset */
+#define MBOX_ROUT			4	/* response output offset */
+#define MBOX_URG			8	/* urgent command */
+#define MBOX_FLAGS			0x0c	/* interrupt enables */
+#define MBOX_COUT			0x20	/* command free offset */
+#define MBOX_RIN			0x24	/* respond valid offset */
+#define MBOX_STATUS			0x2c	/* mailbox status */
+#define MBOX_CMD_BUF			0x40	/* circular command buffer */
+#define MBOX_RESP_BUF			0xc0	/* circular response buffer */
+#define MBOX_DOORBELL_TO_SDM		0x400	/* Doorbell to SDM */
+#define MBOX_DOORBELL_FROM_SDM		0x480	/* Doorbell from SDM */
+
+/* Status and bit information returned by RECONFIG_STATUS */
+#define RECONFIG_STATUS_RESPONSE_LEN			6
+#define RECONFIG_STATUS_STATE				0
+#define RECONFIG_STATUS_PIN_STATUS			2
+#define RECONFIG_STATUS_SOFTFUNC_STATUS			3
+
+/* Macros for specifying number of arguments in mailbox command */
+#define MBOX_NUM_ARGS(n, b)				(((n) & 0xFF) << (b))
+#define MBOX_DIRECT_COUNT(n)				MBOX_NUM_ARGS((n), 0)
+#define MBOX_ARG_DESC_COUNT(n)				MBOX_NUM_ARGS((n), 8)
+#define MBOX_RESP_DESC_COUNT(n)				MBOX_NUM_ARGS((n), 16)
+
+#define MBOX_CFGSTAT_STATE_IDLE				0x00000000
+#define MBOX_CFGSTAT_STATE_CONFIG			0x10000000
+#define MBOX_CFGSTAT_STATE_FAILACK			0x08000000
+#define MBOX_CFGSTAT_STATE_ERROR_INVALID		0xf0000001
+#define MBOX_CFGSTAT_STATE_ERROR_CORRUPT		0xf0000002
+#define MBOX_CFGSTAT_STATE_ERROR_AUTH			0xf0000003
+#define MBOX_CFGSTAT_STATE_ERROR_CORE_IO		0xf0000004
+#define MBOX_CFGSTAT_STATE_ERROR_HARDWARE		0xf0000005
+#define MBOX_CFGSTAT_STATE_ERROR_FAKE			0xf0000006
+#define MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO		0xf0000007
+#define MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR		0xf0000008
+
+#define RCF_SOFTFUNC_STATUS_CONF_DONE			BIT(0)
+#define RCF_SOFTFUNC_STATUS_INIT_DONE			BIT(1)
+#define RCF_SOFTFUNC_STATUS_SEU_ERROR			BIT(3)
+#define RCF_PIN_STATUS_NSTATUS				BIT(31)
+
+/* Defines for HPS_STAGE_NOTIFY */
+#define HPS_EXECUTION_STATE_FSBL	0
+#define HPS_EXECUTION_STATE_SSBL	1
+#define HPS_EXECUTION_STATE_OS		2
+
+int socfpga_mailbox_s10_init(void);
+
+int socfpga_mailbox_s10_qspi_close(void);
+int socfpga_mailbox_s10_qspi_open(void);
+int socfpga_mailbox_s10_qspi_get_device_info(u32 *resp_buf, u32 resp_buf_len);
+
+#endif /* _MAILBOX_S10_H_ */
diff --git a/include/mach/socfpga/secure_reg_helper.h b/include/mach/socfpga/secure_reg_helper.h
new file mode 100644
index 0000000000000000000000000000000000000000..d5a11122c723b22b6d1b93833e494909f758f3b5
--- /dev/null
+++ b/include/mach/socfpga/secure_reg_helper.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2020 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef	_SECURE_REG_HELPER_H_
+#define	_SECURE_REG_HELPER_H_
+
+#define SOCFPGA_SECURE_REG_SYSMGR_SOC64_SDMMC 1
+#define SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC0 2
+#define SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC1 3
+#define SOCFPGA_SECURE_REG_SYSMGR_SOC64_EMAC2 4
+
+int socfpga_secure_reg_read32(u32 id, u32 *val);
+int socfpga_secure_reg_write32(u32 id, u32 val);
+int socfpga_secure_reg_update32(u32 id, u32 mask, u32 val);
+
+#endif /* _SECURE_REG_HELPER_H_ */
diff --git a/include/mach/socfpga/smc_api.h b/include/mach/socfpga/smc_api.h
new file mode 100644
index 0000000000000000000000000000000000000000..491bcaeb019aac986013bb98c59b6109dda719f0
--- /dev/null
+++ b/include/mach/socfpga/smc_api.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2020 Intel Corporation
+ */
+
+#ifndef _SMC_API_H_
+#define _SMC_API_H_
+
+int invoke_smc(u32 func_id, u64 arg0, u64 arg1, u64 arg2, u32 *ret_payload);
+int smc_get_usercode(u32 *usercode);
+
+#endif /* _SMC_API_H_ */
diff --git a/include/mach/socfpga/soc64-firewall.h b/include/mach/socfpga/soc64-firewall.h
new file mode 100644
index 0000000000000000000000000000000000000000..659b84ca1f3f20ede52ed9b0bc0b03d9611e4d26
--- /dev/null
+++ b/include/mach/socfpga/soc64-firewall.h
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2017-2023 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef	_FIREWALL_H_
+#define	_FIREWALL_H_
+
+#include <linux/bitops.h>
+
+struct socfpga_firwall_l4_per {
+	u32	nand;		/* 0x00 */
+	u32	nand_data;
+	u32	_pad_0x8;
+	u32	usb0;
+	u32	usb1;		/* 0x10 */
+	u32	_pad_0x14;
+	u32	_pad_0x18;
+	u32	spim0;
+	u32	spim1;		/* 0x20 */
+	u32	spis0;
+	u32	spis1;
+	u32	emac0;
+	u32	emac1;		/* 0x30 */
+	u32	emac2;
+	u32	_pad_0x38;
+	u32	_pad_0x3c;
+	u32	sdmmc;		/* 0x40 */
+	u32	gpio0;
+	u32	gpio1;
+	u32	_pad_0x4c;
+	u32	i2c0;		/* 0x50 */
+	u32	i2c1;
+	u32	i2c2;
+	u32	i2c3;
+	u32	i2c4;		/* 0x60 */
+	u32	timer0;
+	u32	timer1;
+	u32	uart0;
+	u32	uart1;		/* 0x70 */
+};
+
+struct socfpga_firwall_l4_sys {
+	u32	_pad_0x00;		/* 0x00 */
+	u32	_pad_0x04;
+	u32	dma_ecc;
+	u32	emac0rx_ecc;
+	u32	emac0tx_ecc;		/* 0x10 */
+	u32	emac1rx_ecc;
+	u32	emac1tx_ecc;
+	u32	emac2rx_ecc;
+	u32	emac2tx_ecc;		/* 0x20 */
+	u32	_pad_0x24;
+	u32	_pad_0x28;
+	u32	nand_ecc;
+	u32	nand_read_ecc;		/* 0x30 */
+	u32	nand_write_ecc;
+	u32	ocram_ecc;
+	u32	_pad_0x3c;
+	u32	sdmmc_ecc;		/* 0x40 */
+	u32	usb0_ecc;
+	u32	usb1_ecc;
+	u32	clock_manager;
+	u32	_pad_0x50;		/* 0x50 */
+	u32	io_manager;
+	u32	reset_manager;
+	u32	system_manager;
+	u32	osc0_timer;		/* 0x60 */
+	u32	osc1_timer;
+	u32	watchdog0;
+	u32	watchdog1;
+	u32	watchdog2;		/* 0x70 */
+	u32	watchdog3;
+};
+
+#define FIREWALL_L4_DISABLE_ALL		(BIT(0) | BIT(24) | BIT(16))
+#define FIREWALL_MPFE_SCR_DISABLE_ALL	(BIT(0) | BIT(8) | BIT(16))
+#define FIREWALL_MPFE_SCR_DISABLE_MPU	BIT(0)
+#define FIREWALL_BRIDGE_DISABLE_ALL	(~0)
+
+/* Cache coherency unit (CCU) registers */
+#define CCU_CPU0_MPRT_ADBASE_DDRREG		0x4400
+#define CCU_CPU0_MPRT_ADBASE_MEMSPACE0		0x45c0
+#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1A		0x45e0
+#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1B		0x4600
+#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1C		0x4620
+#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1D		0x4640
+#define CCU_CPU0_MPRT_ADBASE_MEMSPACE1E		0x4660
+
+#define CCU_CPU0_MPRT_ADMASK_MEM_RAM0		0x4688
+
+#define CCU_IOM_MPRT_ADBASE_MEMSPACE0		0x18560
+#define CCU_IOM_MPRT_ADBASE_MEMSPACE1A		0x18580
+#define CCU_IOM_MPRT_ADBASE_MEMSPACE1B		0x185a0
+#define CCU_IOM_MPRT_ADBASE_MEMSPACE1C		0x185c0
+#define CCU_IOM_MPRT_ADBASE_MEMSPACE1D		0x185e0
+#define CCU_IOM_MPRT_ADBASE_MEMSPACE1E		0x18600
+
+#define CCU_IOM_MPRT_ADMASK_MEM_RAM0		0x18628
+
+#define CCU_TCU_MPRT_ADBASE_MEMSPACE0		0x2c520
+#define CCU_TCU_MPRT_ADBASE_MEMSPACE1A		0x2c540
+#define CCU_TCU_MPRT_ADBASE_MEMSPACE1B		0x2c560
+#define CCU_TCU_MPRT_ADBASE_MEMSPACE1C		0x2c580
+#define CCU_TCU_MPRT_ADBASE_MEMSPACE1D		0x2c5a0
+#define CCU_TCU_MPRT_ADBASE_MEMSPACE1E		0x2c5c0
+
+#define CCU_FPGA_MPRT_ADBASE_MEMSPACE0		0x105a0
+#define CCU_FPGA_MPRT_ADBASE_MEMSPACE1A		0x105c0
+#define CCU_FPGA_MPRT_ADBASE_MEMSPACE1B		0x105e0
+#define CCU_FPGA_MPRT_ADBASE_MEMSPACE1C		0x10600
+#define CCU_FPGA_MPRT_ADBASE_MEMSPACE1D		0x10620
+#define CCU_FPGA_MPRT_ADBASE_MEMSPACE1E		0x10640
+
+
+#define CCU_ADMASK_P_MASK			BIT(0)
+#define CCU_ADMASK_NS_MASK			BIT(1)
+
+#define CCU_ADBASE_DI_MASK			BIT(4)
+
+#define CCU_REG_ADDR(reg)			\
+	(SOCFPGA_CCU_ADDRESS + (reg))
+
+/* Firewall MPU DDR SCR registers */
+#define FW_MPU_DDR_SCR_EN				0x00
+#define FW_MPU_DDR_SCR_EN_SET				0x04
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_BASE		0x10
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_BASEEXT		0x14
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT		0x18
+#define FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMITEXT		0x1c
+
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASE		0x90
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_BASEEXT	0x94
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMIT		0x98
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT	0x9c
+#define FW_MPU_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT_FIELD	0xff
+
+/* Firewall F2SDRAM DDR SCR registers */
+#define FW_F2SDRAM_DDR_SCR_EN				0x00
+#define FW_F2SDRAM_DDR_SCR_EN_SET			0x04
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASE		0x10
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_BASEEXT		0x14
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMIT		0x18
+#define FW_F2SDRAM_DDR_SCR_REGION0ADDR_LIMITEXT		0x1c
+
+/* Firewall MPFE SCR Registers */
+#define FW_MPFE_SCR_HMC					0x00
+#define FW_MPFE_SCR_HMC_ADAPTOR				0x04
+
+#define MPUREGION0_ENABLE				BIT(0)
+#define NONMPUREGION0_ENABLE				BIT(8)
+
+#define FW_MPU_DDR_SCR_WRITEL(data, reg)		\
+	writel(data, SOCFPGA_FW_DDR_CCU_DMI0_ADDRESS + (reg)); \
+	writel(data, SOCFPGA_FW_DDR_CCU_DMI1_ADDRESS + (reg))
+#define FW_F2SDRAM_DDR_SCR_WRITEL(data, reg)		\
+	writel(data, SOCFPGA_FW_TBU2NOC_ADDRESS + (reg))
+
+#define FW_MPU_DDR_DMI0_SCR_READL(reg)		readl(SOCFPGA_FW_DDR_CCU_DMI0_ADDRESS + (reg));
+#define FW_MPU_DDR_DMI1_SCR_READL(reg)		readl(SOCFPGA_FW_DDR_CCU_DMI1_ADDRESS + (reg));
+#define FW_F2SDRAM_DDR_SCR_READL(reg)		readl(SOCFPGA_FW_TBU2NOC_ADDRESS + (reg))
+
+/* Secure Transaction Register */
+#define SECURE_TRANS_OFFS		0x190
+#define SECURE_TRANS_REG		SOCFPGA_SYSMGR_ADDRESS +\
+					SECURE_TRANS_OFFS
+#define SECURE_TRANS_RESET		0x0
+#define SECURE_TRANS_SET		0x33
+#define OCRAM_SECURE_REGION1_OFFS	0x18
+#define OCRAM_SECURE_REGION1_REG	SOCFPGA_OCRAM_FIREWALL_ADDRESS +\
+					OCRAM_SECURE_REGION1_OFFS
+#define NON_SECURE_ACCESS		0x0
+
+void firewall_setup(void);
+
+#endif /* _FIREWALL_H_ */
diff --git a/include/mach/socfpga/soc64-handoff.h b/include/mach/socfpga/soc64-handoff.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e079b34b84fd874f70cdb664de3c90f7464d111
--- /dev/null
+++ b/include/mach/socfpga/soc64-handoff.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2016-2024 Intel Corporation <www.intel.com>
+ *
+ */
+
+#ifndef _HANDOFF_SOC64_H_
+#define _HANDOFF_SOC64_H_
+
+/*
+ * Offset for HW handoff from Quartus tools
+ */
+/* HPS handoff */
+#define SOC64_HANDOFF_MAGIC_BOOT	0x424F4F54
+#define SOC64_HANDOFF_MAGIC_MUX		0x504D5558
+#define SOC64_HANDOFF_MAGIC_IOCTL	0x494F4354
+#define SOC64_HANDOFF_MAGIC_FPGA	0x46504741
+#define SOC64_HANDOFF_MAGIC_DELAY	0x444C4159
+#define SOC64_HANDOFF_MAGIC_CLOCK	0x434C4B53
+#define SOC64_HANDOFF_MAGIC_PERI	0x50455249
+#define SOC64_HANDOFF_MAGIC_SDRAM	0x5344524d
+
+#define SOC64_HANDOFF_OFFSET_LENGTH	0x4
+#define SOC64_HANDOFF_OFFSET_DATA	0x10
+#define SOC64_HANDOFF_SIZE		4096
+
+#define SOC64_HANDOFF_BASE		0x0007F000
+
+#define SOC64_HANDOFF_MUX		(SOC64_HANDOFF_BASE + 0x10)
+#define SOC64_HANDOFF_IOCTL		(SOC64_HANDOFF_BASE + 0x1A0)
+#define SOC64_HANDOFF_FPGA		(SOC64_HANDOFF_BASE + 0x330)
+#define SOC64_HANDOFF_DELAY		(SOC64_HANDOFF_BASE + 0x3F0)
+#define SOC64_HANDOFF_CLOCK		(SOC64_HANDOFF_BASE + 0x580)
+#define SOC64_HANDOFF_PERI		(SOC64_HANDOFF_BASE + 0x620)
+#define SOC64_HANDOFF_SDRAM		(SOC64_HANDOFF_BASE + 0x634)
+#define SOC64_HANDOFF_SDRAM_LEN		5
+
+#define SOC64_HANDOFF_CLOCK_OSC		(SOC64_HANDOFF_BASE + 0x60c)
+#define SOC64_HANDOFF_CLOCK_FPGA	(SOC64_HANDOFF_BASE + 0x610)
+
+#define SOC64_HANDOFF_MUX_LEN		96
+#define SOC64_HANDOFF_IOCTL_LEN		96
+#define SOC64_HANDOFF_FPGA_LEN		40
+#define SOC64_HANDOFF_DELAY_LEN		96
+
+int socfpga_get_handoff_size(void *handoff_address);
+int socfpga_handoff_read(void *handoff_address, void *table, u32 table_len);
+const struct cm_config * const cm_get_default_config(void);
+
+#endif /* _HANDOFF_SOC64_H_ */
diff --git a/include/mach/socfpga/soc64-regs.h b/include/mach/socfpga/soc64-regs.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd8cfa17ba1bf0c62a02c9db39dc09347131dd61
--- /dev/null
+++ b/include/mach/socfpga/soc64-regs.h
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2016-2023 Intel Corporation <www.intel.com>
+ */
+
+#ifndef _SOCFPGA_SOC64_BASE_HARDWARE_H_
+#define _SOCFPGA_SOC64_BASE_HARDWARE_H_
+
+#if IS_ENABLED(CONFIG_ARCH_SOCFPGA_AGILEX5)
+#define SOCFPGA_CCU_ADDRESS			0x1c000000
+#define SOCFPGA_CCU_DII2_GIC_BAR_REG		0x420
+#define SOCFPGA_CCU_DII2_GIC_LR_REG		0x424
+#define SOCFPGA_CCU_DII2_GIC_HR_REG		0x428
+
+#define SOCFPGA_FPGA2SOC_ADDRESS		0x1c001000
+#define SOCFPGA_FPGA2SOC_PSS_BAR_REG		0x400
+#define SOCFPGA_FPGA2SOC_PSS_LR_REG		0x404
+#define SOCFPGA_FPGA2SOC_PSS_HR_REG		0x408
+
+#define SOCFPGA_GIC_M_ADDRESS			0x1c002000
+#define SOCFPGA_TCU_ADDRESS			0x1c003000
+#define SOCFPGA_CCU_IOM_ADDRESS			0x1c004000
+#define SOCFPGA_DCE0_ADDRESS			0x1c005000
+#define SOCFPGA_DCE1_ADDRESS			0x1c006000
+
+#define SOCFPGA_SECREG_NCAIU1AMIGR_REG			0x3c0
+#define SOCFPGA_SECREG_NCAIU1MIFSR_REG			0x3c4
+#define SOCFPGA_SECREG_DII1_MPFE_BAR_REG		0x410
+#define SOCFPGA_SECREG_DII1_MPFE_LR_REG			0x414
+#define SOCFPGA_SECREG_DII1_MPFE_HR_REG			0x418
+#define SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_BAR_REG	0x440
+#define SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_LR_REG		0x444
+#define SOCFPGA_SECREG_NCAIU0_LWSOC2FPGA_HR_REG		0x448
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_BAR_REG	0x450
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_LR_REG	0x454
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_1G_HR_REG	0x458
+#define SOCFPGA_SECREG_DMI_SDRAM_2G_BAR_REG		0x460
+#define SOCFPGA_SECREG_DMI_SDRAM_2G_LR_REG		0x464
+#define SOCFPGA_SECREG_DMI_SDRAM_2G_HR_REG		0x468
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_BAR_REG	0x470
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_LR_REG	0x474
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_16G_HR_REG	0x478
+#define SOCFPGA_SECREG_DMI_SDRAM_30G_BAR_REG		0x480
+#define SOCFPGA_SECREG_DMI_SDRAM_30G_LR_REG		0x484
+#define SOCFPGA_SECREG_DMI_SDRAM_30G_HR_REG		0x488
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_BAR_REG	0x490
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_LR_REG	0x494
+#define SOCFPGA_SECREG_NCAIU0_SOC2FPGA_256G_HR_REG	0x498
+#define SOCFPGA_SECREG_DMI_SDRAM_480G_BAR_REG		0x4a0
+#define SOCFPGA_SECREG_DMI_SDRAM_480G_LR_REG		0x4a4
+#define SOCFPGA_SECREG_DMI_SDRAM_480G_HR_REG		0x4a8
+
+#define SOCFPGA_DMI0_ADDRESS			0x1c007000
+#define SOCFPGA_DMI0_DMIUSMCTCR_REG		0x300
+
+#define SOCFPGA_DMI1_ADDRESS			0x1c008000
+#define SOCFPGA_DMI1_DMIUSMCTCR_REG		0x300
+
+#define SOCFPGA_F2SDRAM_MGR_ADDRESS		0x18001000
+#define SOCFPGA_SMMU_ADDRESS			0x16000000
+#define SOCFPGA_OCRAM_FIREWALL_ADDRESS		0x108cc400
+#define SOCFPGA_MAILBOX_ADDRESS			0x10a30000
+#define SOCFPGA_UART0_ADDRESS			0x10c02000
+#define SOCFPGA_UART1_ADDRESS			0x10c02100
+#define SOCFPGA_SPTIMER0_ADDRESS		0x10c03000
+#define SOCFPGA_SPTIMER1_ADDRESS		0x10c03100
+#define SOCFPGA_SYSTIMER0_ADDRESS		0x10d00000
+#define SOCFPGA_SYSTIMER1_ADDRESS		0x10d00100
+#define SOCFPGA_L4WD0_ADDRESS			0x10d00200
+#define SOCFPGA_L4WD1_ADDRESS			0x10d00300
+#define SOCFPGA_L4WD2_ADDRESS			0x10d00400
+#define SOCFPGA_L4WD3_ADDRESS			0x10d00500
+#define SOCFPGA_L4WD4_ADDRESS			0x10d00600
+#define SOCFPGA_GTIMER_SEC_ADDRESS		0x10d01000
+#define SOCFPGA_GTIMER_NSEC_ADDRESS		0x10d02000
+#define SOCFPGA_CLKMGR_ADDRESS			0x10d10000
+#define SOCFPGA_RSTMGR_ADDRESS			0x10d11000
+#define SOCFPGA_SYSMGR_ADDRESS			0x10d12000
+#define SOCFPGA_PINMUX_ADDRESS			0x10d13000
+#define SOCFPGA_OCRAM_ADDRESS			0x00000000
+#define SOCFPGA_MPFE_CSR_ADDRESS		0x18000000
+#define SOCFPGA_FW_DDR_CCU_DMI0_ADDRESS		0x18000800
+#define SOCFPGA_FW_DDR_CCU_DMI1_ADDRESS		0x18000A00
+#define SOCFPGA_FW_TBU2NOC_ADDRESS		0x18000C00
+#define SOCFPGA_FIREWALL_L4_PER_ADDRESS		0x10d21000
+#define SOCFPGA_FIREWALL_L4_PER_NAND_REG	0x0
+#define SOCFPGA_FIREWALL_L4_PER_USB0_REG	0xc
+#define SOCFPGA_FIREWALL_L4_PER_USB1_REG	0x10
+#define SOCFPGA_FIREWALL_L4_PER_SPI_MAIN0_REG	0x1c
+#define SOCFPGA_FIREWALL_L4_PER_SPI_MAIN1_REG	0x20
+#define SOCFPGA_FIREWALL_L4_PER_SPI_SEC0_REG	0x24
+#define SOCFPGA_FIREWALL_L4_PER_SPI_SEC1_REG	0x28
+#define SOCFPGA_FIREWALL_L4_PER_EMAC0_REG	0x2c
+#define SOCFPGA_FIREWALL_L4_PER_EMAC1_REG	0x30
+#define SOCFPGA_FIREWALL_L4_PER_EMAC2_REG	0x34
+#define SOCFPGA_FIREWALL_L4_PER_SDMMC_REG	0x40
+#define SOCFPGA_FIREWALL_L4_PER_GPIO0_REG	0x44
+#define SOCFPGA_FIREWALL_L4_PER_GPIO1_REG	0x48
+#define SOCFPGA_FIREWALL_L4_PER_I2C0_REG	0x50
+#define SOCFPGA_FIREWALL_L4_PER_I2C1_REG	0x54
+#define SOCFPGA_FIREWALL_L4_PER_I2C2_REG	0x58
+#define SOCFPGA_FIREWALL_L4_PER_I2C3_REG	0x5c
+#define SOCFPGA_FIREWALL_L4_PER_I2C4_REG	0x60
+#define SOCFPGA_FIREWALL_L4_PER_SP_TIMER0_REG	0x64
+#define SOCFPGA_FIREWALL_L4_PER_SP_TIMER1_REG	0x68
+#define SOCFPGA_FIREWALL_L4_PER_UART0_REG	0x6c
+#define SOCFPGA_FIREWALL_L4_PER_UART1_REG	0x70
+#define SOCFPGA_FIREWALL_L4_PER_I3C0_REG	0x74
+#define SOCFPGA_FIREWALL_L4_PER_I3C1_REG	0x78
+#define SOCFPGA_FIREWALL_L4_PER_DMA0_REG	0x7c
+#define SOCFPGA_FIREWALL_L4_PER_DMA1_REG	0x80
+#define SOCFPGA_FIREWALL_L4_PER_COMBO_PHY_REG	0x84
+#define SOCFPGA_FIREWALL_L4_PER_NAND_SDMA_REG	0x88
+
+#define SOCFPGA_FIREWALL_L4_SYS_ADDRESS			0x10d21100
+#define SOCFPGA_FIREWALL_L4_SYS_DMA_ECC_REG		0x08
+#define SOCFPGA_FIREWALL_L4_SYS_EMAC0RX_ECC_REG		0x0c
+#define SOCFPGA_FIREWALL_L4_SYS_EMAC0TX_ECC_REG		0x10
+#define SOCFPGA_FIREWALL_L4_SYS_EMAC1RX_ECC_REG		0x14
+#define SOCFPGA_FIREWALL_L4_SYS_EMAC1TX_ECC_REG		0x18
+#define SOCFPGA_FIREWALL_L4_SYS_EMAC2RX_ECC_REG		0x1c
+#define SOCFPGA_FIREWALL_L4_SYS_EMAC2TX_ECC_REG		0x20
+#define SOCFPGA_FIREWALL_L4_SYS_NAND_ECC_REG		0x2c
+#define SOCFPGA_FIREWALL_L4_SYS_NAND_READ_ECC_REG	0x30
+#define SOCFPGA_FIREWALL_L4_SYS_NAND_WRITE_ECC_REG	0x34
+#define SOCFPGA_FIREWALL_L4_SYS_OCRAM_ECC_REG		0x38
+#define SOCFPGA_FIREWALL_L4_SYS_SDMMC_ECC_REG		0x40
+#define SOCFPGA_FIREWALL_L4_SYS_USB0_ECC_REG		0x44
+#define SOCFPGA_FIREWALL_L4_SYS_USB1_CACHEECC_REG	0x48
+#define SOCFPGA_FIREWALL_L4_SYS_CLOCK_MANAGER_REG	0x4c
+#define SOCFPGA_FIREWALL_L4_SYS_IO_MANAGER_REG		0x54
+#define SOCFPGA_FIREWALL_L4_SYS_RESET_MANAGER_REG	0x58
+#define SOCFPGA_FIREWALL_L4_SYS_SYSTEM_MANAGER_REG	0x5c
+#define SOCFPGA_FIREWALL_L4_SYS_OSC0_TIMER_REG		0x60
+#define SOCFPGA_FIREWALL_L4_SYS_OSC1_TIMER0_REG		0x64
+#define SOCFPGA_FIREWALL_L4_SYS_WATCHDOG0_REG		0x68
+#define SOCFPGA_FIREWALL_L4_SYS_WATCHDOG1_REG		0x6c
+#define SOCFPGA_FIREWALL_L4_SYS_WATCHDOG2_REG		0x70
+#define SOCFPGA_FIREWALL_L4_SYS_WATCHDOG3_REG		0x74
+#define SOCFPGA_FIREWALL_L4_SYS_DAP_REG			0x78
+#define SOCFPGA_FIREWALL_L4_SYS_WATCHDOG4_REG		0x7c
+#define SOCFPGA_FIREWALL_L4_SYS_POWER_MANAGER_REG	0x80
+#define SOCFPGA_FIREWALL_L4_SYS_USB1_RXECC_REG		0x84
+#define SOCFPGA_FIREWALL_L4_SYS_USB1_TXECC_REG		0x88
+#define SOCFPGA_FIREWALL_L4_SYS_L4_NOC_PROBES_REG	0x90
+#define SOCFPGA_FIREWALL_L4_SYS_L4_NOC_QOS_REG		0x94
+
+#define SOCFPGA_FIREWALL_SOC2FPGA_ADDRESS	0x10d21200
+#define SOCFPGA_FIREWALL_LWSOC2FPGA_ADDRESS	0x10d21300
+#define SOCFPGA_FIREWALL_TCU_ADDRESS		0x10d21400
+#define GICD_BASE				0x1d000000
+#define GICR_BASE				0x1d060000
+
+#define SOCFPGA_AGILEX5_DDR_BASE		0x80000000
+
+#else
+#define SOCFPGA_CCU_ADDRESS			0xf7000000
+#define SOCFPGA_SDR_SCHEDULER_ADDRESS		0xf8000400
+#define SOCFPGA_HMC_MMR_IO48_ADDRESS		0xf8010000
+#define SOCFPGA_SDR_ADDRESS			0xf8011000
+#define SOCFPGA_FW_MPFE_SCR_ADDRESS		0xf8020000
+#define SOCFPGA_FW_MPU_DDR_SCR_ADDRESS		0xf8020100
+#define SOCFPGA_F2SDRAM_MGR_ADDRESS		0xf8024000
+#define SOCFPGA_SMMU_ADDRESS			0xfa000000
+#define SOCFPGA_MAILBOX_ADDRESS			0xffa30000
+#define SOCFPGA_UART0_ADDRESS			0xffc02000
+#define SOCFPGA_UART1_ADDRESS			0xffc02100
+#define SOCFPGA_SPTIMER0_ADDRESS		0xffc03000
+#define SOCFPGA_SPTIMER1_ADDRESS		0xffc03100
+#define SOCFPGA_SYSTIMER0_ADDRESS		0xffd00000
+#define SOCFPGA_SYSTIMER1_ADDRESS		0xffd00100
+#define SOCFPGA_L4WD0_ADDRESS			0xffd00200
+#define SOCFPGA_L4WD1_ADDRESS			0xffd00300
+#define SOCFPGA_L4WD2_ADDRESS			0xffd00400
+#define SOCFPGA_L4WD3_ADDRESS			0xffd00500
+#define SOCFPGA_GTIMER_SEC_ADDRESS		0xffd01000
+#define SOCFPGA_GTIMER_NSEC_ADDRESS		0xffd02000
+#define SOCFPGA_CLKMGR_ADDRESS			0xffd10000
+#define SOCFPGA_RSTMGR_ADDRESS			0xffd11000
+#define SOCFPGA_SYSMGR_ADDRESS			0xffd12000
+#define SOCFPGA_PINMUX_DEDICATED_IO_ADDRESS	0xffd13000
+#define SOCFPGA_FIREWALL_L4_PER			0xffd21000
+#define SOCFPGA_FIREWALL_L4_SYS			0xffd21100
+#define SOCFPGA_FIREWALL_SOC2FPGA		0xffd21200
+#define SOCFPGA_FIREWALL_LWSOC2FPGA		0xffd21300
+#define SOCFPGA_FIREWALL_TCU			0xffd21400
+#define SOCFPGA_FIREWALL_PRIV_MEMORYMAP_PRIV	0xffd24800
+#define SOCFPGA_DMANONSECURE_ADDRESS		0xffda0000
+#define SOCFPGA_DMASECURE_ADDRESS		0xffda1000
+#define SOCFPGA_OCRAM_ADDRESS			0xffe00000
+#define GICD_BASE				0xfffc1000
+#define GICC_BASE				0xfffc2000
+#endif
+
+#endif /* _SOCFPGA_SOC64_BASE_HARDWARE_H_ */
diff --git a/include/mach/socfpga/soc64-reset-manager.h b/include/mach/socfpga/soc64-reset-manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9822ae9bfd9d02581432dc2aeb2051334c149bb
--- /dev/null
+++ b/include/mach/socfpga/soc64-reset-manager.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *  Copyright (C) 2016-2022 Intel Corporation <www.intel.com>
+ */
+
+#ifndef _RESET_MANAGER_SOC64_H_
+#define _RESET_MANAGER_SOC64_H_
+
+#define RSTMGR_SOC64_STATUS	0x00
+#define RSTMGR_SOC64_HDSKEN	0x10
+#define RSTMGR_SOC64_HDSKREQ	0x14
+#define RSTMGR_SOC64_HDSKACK	0x18
+#define RSTMGR_SOC64_MPUMODRST	0x20
+#define RSTMGR_SOC64_PER0MODRST	0x24
+#define RSTMGR_SOC64_PER1MODRST	0x28
+#define RSTMGR_SOC64_BRGMODRST	0x2c
+
+#define RSTMGR_MPUMODRST_CORE0		0
+#define RSTMGR_PER0MODRST_OCP_MASK	0x0020bf00
+
+#define RSTMGR_BRGMODRST_SOC2FPGA_MASK		BIT(0)
+#define RSTMGR_BRGMODRST_LWSOC2FPGA_MASK	BIT(1)
+#define RSTMGR_BRGMODRST_FPGA2SOC_MASK		BIT(2)
+#define RSTMGR_BRGMODRST_F2SDRAM0_MASK		BIT(3)
+#define RSTMGR_BRGMODRST_F2SDRAM1_MASK		BIT(4)
+#define RSTMGR_BRGMODRST_F2SDRAM2_MASK		BIT(5)
+#define RSTMGR_BRGMODRST_DDRSCH_MASK		BIT(6)
+
+#define RSTMGR_HDSKEN_FPGAHSEN		BIT(2)
+#define RSTMGR_HDSKREQ_FPGAHSREQ	BIT(2)
+
+/* SDM, Watchdogs and MPU warm reset mask */
+#define RSTMGR_STAT_SDMWARMRST		0x2
+#define RSTMGR_STAT_MPU0RST_BITPOS	8
+#define RSTMGR_STAT_L4WD0RST_BITPOS	16
+#define RSTMGR_STAT_L4WD0RST_BIT	0x1F0000
+#define RSTMGR_L4WD_MPU_WARMRESET_MASK	RSTMGR_STAT_SDMWARMRST | \
+		RSTMGR_STAT_L4WD0RST_BIT
+
+#endif /* _RESET_MANAGER_SOC64_H_ */
diff --git a/include/mach/socfpga/soc64-sdram.h b/include/mach/socfpga/soc64-sdram.h
new file mode 100644
index 0000000000000000000000000000000000000000..c84cd7f8253734dfb7066077c3b8401884efb0ed
--- /dev/null
+++ b/include/mach/socfpga/soc64-sdram.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017-2023 Intel Corporation <www.intel.com>
+ */
+
+#ifndef	_SDRAM_SOC64_H_
+#define	_SDRAM_SOC64_H_
+
+#include <linux/sizes.h>
+
+struct altera_sdram_plat {
+	void __iomem *mpfe_base_addr;
+	bool dualport;
+	bool dualemif;
+};
+
+/* ECC HMC registers */
+#define DDRIOCTRL			0x8
+#define DDRCALSTAT			0xc
+#define DRAMADDRWIDTH			0xe0
+#define ECCCTRL1			0x100
+#define ECCCTRL2			0x104
+#define ERRINTEN			0x110
+#define ERRINTENS			0x114
+#define INTMODE				0x11c
+#define INTSTAT				0x120
+#define AUTOWB_CORRADDR			0x138
+#define ECC_REG2WRECCDATABUS		0x144
+#define ECC_DIAGON			0x150
+#define ECC_DECSTAT			0x154
+#define HPSINTFCSEL			0x210
+#define RSTHANDSHAKECTRL		0x214
+#define RSTHANDSHAKESTAT		0x218
+
+#define DDR_HMC_DDRIOCTRL_IOSIZE_MSK		0x00000003
+#define DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_MSK BIT(2)
+#define DDR_HMC_DDRIOCTRL_MPFE_HMCA_DATA_RATE_SHIFT 2
+#define DDR_HMC_DDRCALSTAT_CAL_MSK		BIT(0)
+#define DDR_HMC_ECCCTL_AWB_CNT_RST_SET_MSK	BIT(16)
+#define DDR_HMC_ECCCTL_CNT_RST_SET_MSK		BIT(8)
+#define DDR_HMC_ECCCTL_ECC_EN_SET_MSK		BIT(0)
+#define DDR_HMC_ECCCTL2_RMW_EN_SET_MSK		BIT(8)
+#define DDR_HMC_ECCCTL2_AWB_EN_SET_MSK		BIT(0)
+#define DDR_HMC_ECC_DIAGON_ECCDIAGON_EN_SET_MSK	BIT(16)
+#define DDR_HMC_ECC_DIAGON_WRDIAGON_EN_SET_MSK	BIT(0)
+#define DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK	BIT(0)
+#define DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK	BIT(1)
+#define DDR_HMC_INTSTAT_SERRPENA_SET_MSK	BIT(0)
+#define DDR_HMC_INTSTAT_DERRPENA_SET_MSK	BIT(1)
+#define DDR_HMC_INTSTAT_ADDRMTCFLG_SET_MSK	BIT(16)
+#define DDR_HMC_INTMODE_INTMODE_SET_MSK		BIT(0)
+#define DDR_HMC_RSTHANDSHAKE_MASK		0x0000000f
+#define DDR_HMC_CORE2SEQ_INT_REQ		0xF
+#define DDR_HMC_SEQ2CORE_INT_RESP_MASK		BIT(3)
+#define DDR_HMC_HPSINTFCSEL_ENABLE_MASK		0x001f1f1f
+
+#define	DDR_HMC_ERRINTEN_INTMASK				\
+		(DDR_HMC_ERRINTEN_SERRINTEN_EN_SET_MSK |	\
+		 DDR_HMC_ERRINTEN_DERRINTEN_EN_SET_MSK)
+
+/* HMC MMR IO48 registers */
+#define CTRLCFG0			0x28
+#define CTRLCFG1			0x2c
+#define CTRLCFG3                        0x34
+#define CTRLCFG5                        0x3c
+#define CTRLCFG6                        0x40
+#define DRAMTIMING0			0x50
+#define CALTIMING0			0x7c
+#define CALTIMING1			0x80
+#define CALTIMING2			0x84
+#define CALTIMING3			0x88
+#define CALTIMING4			0x8c
+#define CALTIMING9			0xa0
+#define DRAMADDRW			0xa8
+#define DRAMSTS				0xec
+#define NIOSRESERVED0			0x110
+#define NIOSRESERVED1			0x114
+#define NIOSRESERVED2			0x118
+
+#define CTRLCFG3_CFG_CTRL_CMD_RATE_QUARTER	BIT(2)
+#define CTRLCFG5_CFG_CTRL_RC_EN_MASK		BIT(8)
+
+#define DRAMADDRW_CFG_COL_ADDR_WIDTH(x)			\
+	((x) & 0x1F)
+#define DRAMADDRW_CFG_ROW_ADDR_WIDTH(x)			\
+	(((x) >> 5) & 0x1F)
+#define DRAMADDRW_CFG_BANK_ADDR_WIDTH(x)		\
+	(((x) >> 10) & 0xF)
+#define DRAMADDRW_CFG_BANK_GRP_ADDR_WIDTH(x)		\
+	(((x) >> 14) & 0x3)
+#define DRAMADDRW_CFG_CS_ADDR_WIDTH(x)			\
+	(((x) >> 16) & 0x7)
+
+#define CTRLCFG0_CFG_MEMTYPE(x)				\
+	((x) & 0xF)
+#define CTRLCFG0_CFG_DIMM_TYPE(x)			\
+	(((x) >> 4) & 0x7)
+#define CTRLCFG0_CFG_AC_POS(x)				\
+	(((x) >> 7) & 0x3)
+#define CTRLCFG0_CFG_CTRL_BURST_LEN(x)			\
+	(((x) >> 9) & 0x1F)
+
+#define CTRLCFG1_CFG_DBC3_BURST_LEN(x)			\
+	((x) & 0x1F)
+#define CTRLCFG1_CFG_ADDR_ORDER(x)			\
+	(((x) >> 5) & 0x3)
+#define CTRLCFG1_CFG_CTRL_EN_ECC(x)			\
+	(((x) >> 7) & 0x1)
+
+#define CTRLCFG6_CFG_CS_CHIP(x)				\
+	((x) & 0xFFFF)
+
+#define DRAMTIMING0_CFG_TCL(x)				\
+	((x) & 0x7F)
+
+#define CALTIMING0_CFG_ACT_TO_RDWR(x)			\
+	((x) & 0x3F)
+#define CALTIMING0_CFG_ACT_TO_PCH(x)			\
+	(((x) >> 6) & 0x3F)
+#define CALTIMING0_CFG_ACT_TO_ACT(x)			\
+	(((x) >> 12) & 0x3F)
+#define CALTIMING0_CFG_ACT_TO_ACT_DB(x)			\
+	(((x) >> 18) & 0x3F)
+
+#define CALTIMING1_CFG_RD_TO_RD(x)			\
+	((x) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_RD_DC(x)			\
+	(((x) >> 6) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_RD_DB(x)			\
+	(((x) >> 12) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_WR(x)			\
+	(((x) >> 18) & 0x3F)
+#define CALTIMING1_CFG_RD_TO_WR_DC(x)			\
+	(((x) >> 24) & 0x3F)
+
+#define CALTIMING2_CFG_RD_TO_WR_DB(x)			\
+	((x) & 0x3F)
+#define CALTIMING2_CFG_RD_TO_WR_PCH(x)			\
+	(((x) >> 6) & 0x3F)
+#define CALTIMING2_CFG_RD_AP_TO_VALID(x)		\
+	(((x) >> 12) & 0x3F)
+#define CALTIMING2_CFG_WR_TO_WR(x)			\
+	(((x) >> 18) & 0x3F)
+#define CALTIMING2_CFG_WR_TO_WR_DC(x)			\
+	(((x) >> 24) & 0x3F)
+
+#define CALTIMING3_CFG_WR_TO_WR_DB(x)			\
+	((x) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_RD(x)			\
+	(((x) >> 6) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_RD_DC(x)			\
+	(((x) >> 12) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_RD_DB(x)			\
+	(((x) >> 18) & 0x3F)
+#define CALTIMING3_CFG_WR_TO_PCH(x)			\
+	(((x) >> 24) & 0x3F)
+
+#define CALTIMING4_CFG_WR_AP_TO_VALID(x)		\
+	((x) & 0x3F)
+#define CALTIMING4_CFG_PCH_TO_VALID(x)			\
+	(((x) >> 6) & 0x3F)
+#define CALTIMING4_CFG_PCH_ALL_TO_VALID(x)		\
+	(((x) >> 12) & 0x3F)
+#define CALTIMING4_CFG_ARF_TO_VALID(x)			\
+	(((x) >> 18) & 0xFF)
+#define CALTIMING4_CFG_PDN_TO_VALID(x)			\
+	(((x) >> 26) & 0x3F)
+
+#define CALTIMING9_CFG_4_ACT_TO_ACT(x)			\
+	((x) & 0xFF)
+
+/* Firewall DDR scheduler MPFE */
+#define FW_HMC_ADAPTOR_REG_ADDR			0xf8020004
+#define FW_HMC_ADAPTOR_MPU_MASK			BIT(0)
+
+u32 hmc_readl(struct altera_sdram_plat *plat, u32 reg);
+u32 hmc_ecc_readl(struct altera_sdram_plat *plat, u32 reg);
+u32 hmc_ecc_writel(struct altera_sdram_plat *plat,
+		   u32 data, u32 reg);
+u32 ddr_sch_writel(struct altera_sdram_plat *plat, u32 data,
+		   u32 reg);
+int emif_clear(struct altera_sdram_plat *plat);
+int emif_reset(struct altera_sdram_plat *plat);
+int poll_hmc_clock_status(void);
+void sdram_clear_mem(phys_addr_t addr, phys_size_t size);
+//void sdram_set_firewall(struct bd_info *bd);
+phys_size_t sdram_calculate_size(struct altera_sdram_plat *plat);
+int agilex5_ddr_init_full(void);
+
+static inline resource_size_t agilex5_mpfe_sdram_size(void)
+{
+	u32 lower;
+	resource_size_t mem = 0;
+
+	lower = FW_MPU_DDR_DMI0_SCR_READL(SOCFPGA_FW_DDR_CCU_DMI0_ADDRESS +
+					  FW_MPU_DDR_SCR_MPUREGION0ADDR_LIMIT);
+
+	mem = lower;
+
+	return mem;
+}
+
+#endif /* _SDRAM_SOC64_H_ */
diff --git a/include/mach/socfpga/soc64-system-manager.h b/include/mach/socfpga/soc64-system-manager.h
new file mode 100644
index 0000000000000000000000000000000000000000..862e974b190245862dc7975cbeb281ba6b263dc7
--- /dev/null
+++ b/include/mach/socfpga/soc64-system-manager.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+* Copyright (C) 2019-2023 Intel Corporation <www.intel.com>
+ */
+
+#ifndef _SOC64_SYSTEM_MANAGER_H_
+#define _SOC64_SYSTEM_MANAGER_H_
+
+#include <linux/bitops.h>
+
+#define SYSMGR_SOC64_SILICONID_1		0x00
+#define SYSMGR_SOC64_SILICONID_2		0x04
+#define SYSMGR_SOC64_WDDBG			0x08
+#define SYSMGR_SOC64_MPU_STATUS			0x10
+#define SYSMGR_SOC64_SDMMC			0x28
+#define SYSMGR_SOC64_SDMMC_L3MASTER		0x2c
+#define SYSMGR_SOC64_COMBOPHY_DFISEL		0xfc
+#define SYSMGR_SOC64_COMBOPHY_DFISEL_SDMMC	0x1
+#define SYSMGR_SOC64_NANDGRP_L3MASTER		0x34
+#define SYSMGR_SOC64_USB0_L3MASTER		0x38
+#define SYSMGR_SOC64_USB1_L3MASTER		0x3c
+#define SYSMGR_SOC64_TSN_GLOBAL			0x40
+#define SYSMGR_SOC64_TSN_0			0x44
+#define SYSMGR_SOC64_TSN_1			0x48
+#define SYSMGR_SOC64_TSN_2			0x4C
+#define SYSMGR_SOC64_TSN_0_ACE			0x50
+#define SYSMGR_SOC64_TSN_1_ACE			0x54
+#define SYSMGR_SOC64_TSN_2_ACE			0x58
+#define SYSMGR_SOC64_FPGAINTF_EN1		0x68
+#define SYSMGR_SOC64_FPGAINTF_EN2		0x6C
+#define SYSMGR_SOC64_FPGAINTF_EN3		0x70
+#define SYSMGR_SOC64_DMAC0_L3_MASTER		0x74
+#define SYSMGR_SOC64_ETR_L3_MASTER		0x78
+#define SYSMGR_SOC64_DMAC1_L3_MASTER		0x7C
+#define SYSMGR_SOC64_SEC_CTRL_SLT		0x80
+#define SYSMGR_SOC64_OSC_TRIM			0x84
+#define SYSMGR_SOC64_DMAC0_CTRL_STATUS_REG	0x88
+#define SYSMGR_SOC64_DMAC1_CTRL_STATUS_REG	0x8C
+#define SYSMGR_SOC64_ECC_INTMASK_VALUE		0x90
+#define SYSMGR_SOC64_ECC_INTMASK_SET		0x94
+#define SYSMGR_SOC64_ECC_INTMASK_CLR		0x98
+#define SYSMGR_SOC64_ECC_INTMASK_SERR		0x9C
+#define SYSMGR_SOC64_ECC_INTMASK_DERR		0xA0
+#define SYSMGR_SOC64_NOC_TIMEOUT		0xC0
+#define SYSMGR_SOC64_NOC_IDLEREQ_SET		0xc4
+#define SYSMGR_SOC64_NOC_IDLEREQ_CLR		0xc8
+#define SYSMGR_SOC64_NOC_IDLEREQ_VAL		0xcc
+#define SYSMGR_SOC64_NOC_IDLEACK		0xd0
+#define SYSMGR_SOC64_NOC_IDLESTATUS		0xD4
+#define SYSMGR_SOC64_FPGA2SOC_CTRL		0xD8
+#define SYSMGR_SOC64_FPGA_CONFIG		0xDC
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD0		0x200
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD1		0x204
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD2		0x208
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD3		0x20C
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD4		0x210
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD5		0x214
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD6		0x218
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD7		0x21C
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD8		0x220
+#define SYSMGR_SOC64_BOOT_SCRATCH_COLD9		0x224
+#define SYSMGR_SOC64_MPFE_CONFIG		0x228
+#define SYSMGR_SOC64_BOOT_SCRATCH_POR0		0x258
+#define SYSMGR_SOC64_BOOT_SCRATCH_POR1		0x25C
+
+#define SYSMGR_SCRATCH_REG_0_QSPI_REFCLK_MASK		GENMASK(31, 0)
+#define ALT_SYSMGR_SCRATCH_REG_3_DDR_RESET_TYPE_MASK	GENMASK(31, 29)
+#define ALT_SYSMGR_SCRATCH_REG_3_DDR_RESET_TYPE_SHIFT	29
+#define ALT_SYSMGR_SCRATCH_REG_3_DDR_DBE_MASK		BIT(1)
+#define ALT_SYSMGR_SCRATCH_REG_3_OCRAM_DBE_MASK		BIT(0)
+#define ALT_SYSMGR_SCRATCH_REG_POR_0_DDR_PROGRESS_MASK	BIT(0)
+#define ALT_SYSMGR_SCRATCH_REG_POR_1_REVA_WORKAROUND_USER_MODE_MASK	BIT(0)
+#define ALT_SYSMGR_SCRATCH_REG_POR_1_REVA_WORKAROUND_MASK	BIT(1)
+
+#define SYSMGR_SOC64_EMAC_GLOBAL	SYSMGR_SOC64_TSN_GLOBAL
+#define SYSMGR_SOC64_EMAC0		SYSMGR_SOC64_TSN_0
+#define SYSMGR_SOC64_EMAC1		SYSMGR_SOC64_TSN_1
+#define SYSMGR_SOC64_EMAC2		SYSMGR_SOC64_TSN_2
+#define SYSMGR_SOC64_EMAC0_ACE		SYSMGR_SOC64_TSN_0_ACE
+#define SYSMGR_SOC64_EMAC1_ACE		SYSMGR_SOC64_TSN_1_ACE
+#define SYSMGR_SOC64_EMAC2_ACE		SYSMGR_SOC64_TSN_2_ACE
+
+#define SYSMGR_SOC64_PINSEL0			0x1000
+#define SYSMGR_SOC64_IOCTRL0			0x1130
+#define SYSMGR_SOC64_EMAC0_USEFPGA		0x1300
+#define SYSMGR_SOC64_EMAC1_USEFPGA		0x1304
+#define SYSMGR_SOC64_EMAC2_USEFPGA		0x1308
+#define SYSMGR_SOC64_I2C0_USEFPGA		0x130c
+#define SYSMGR_SOC64_I2C1_USEFPGA		0x1310
+#define SYSMGR_SOC64_I2C_EMAC0_USEFPGA		0x1314
+#define SYSMGR_SOC64_I2C_EMAC1_USEFPGA		0x1318
+#define SYSMGR_SOC64_I2C_EMAC2_USEFPGA		0x131c
+#define SYSMGR_SOC64_NAND_USEFPGA		0x1320
+#define SYSMGR_SOC64_SPIM0_USEFPGA		0x1328
+#define SYSMGR_SOC64_SPIM1_USEFPGA		0x132c
+#define SYSMGR_SOC64_SPIS0_USEFPGA		0x1330
+#define SYSMGR_SOC64_SPIS1_USEFPGA		0x1334
+#define SYSMGR_SOC64_UART0_USEFPGA		0x1338
+#define SYSMGR_SOC64_UART1_USEFPGA		0x133c
+#define SYSMGR_SOC64_MDIO0_USEFPGA		0x1340
+#define SYSMGR_SOC64_MDIO1_USEFPGA		0x1344
+#define SYSMGR_SOC64_MDIO2_USEFPGA		0x1348
+#define SYSMGR_SOC64_JTAG_USEFPGA		0x1350
+#define SYSMGR_SOC64_SDMMC_USEFPGA		0x1354
+#define SYSMGR_SOC64_HPS_OSC_CLK		0x1358
+#define SYSMGR_SOC64_IODELAY0			0x1400
+#define SYSMGR_SOC64_PERI			0x15D0
+
+/*
+ * Bits for SYSMGR_SOC64_BOOT_SCRATCH_COLD8
+ * Bit[31] reserved for FSBL to check DBE is triggered (set by SDM to "1") ?
+ *
+ * Bit[30] reserved for FSBL to update the DDR init progress
+ * 1 - means in progress, 0 - haven't started / DDR is up running.
+ *
+* Bit[19] store ATF CPU0 ON OFF value.
+*
+ * Bit[18] reserved for SDM to configure ACF
+ * Bit[17:1] - Setting by Linux EDAC.
+ * Bit[1](ECC_OCRAM), Bit[16](ECC_DDR0), Bit[17](ECC_DDR1)
+ */
+#define ALT_SYSMGR_SCRATCH_REG_8_DDR_DBE_MASK		BIT(31)
+#define ALT_SYSMGR_SCRATCH_REG_8_DDR_PROGRESS_MASK	BIT(30)
+#define SYSMGR_SCRATCH_REG_8_ACF_DDR_RATE_MASK		BIT(18)
+#define SYSMGR_SCRATCH_REG_8_ACF_DDR_RATE_SHIFT		18
+
+#define SYSMGR_SDMMC				SYSMGR_SOC64_SDMMC
+
+#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGPINMUX	BIT(0)
+#define SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO	BIT(1)
+#define SYSMGR_ECC_OCRAM_EN			BIT(0)
+#define SYSMGR_ECC_OCRAM_SERR			BIT(3)
+#define SYSMGR_ECC_OCRAM_DERR			BIT(4)
+#define SYSMGR_FPGACONFIG_FPGA_COMPLETE		BIT(0)
+#define SYSMGR_FPGACONFIG_EARLY_USERMODE	BIT(1)
+#define SYSMGR_FPGACONFIG_READY_MASK	(SYSMGR_FPGACONFIG_FPGA_COMPLETE | \
+					 SYSMGR_FPGACONFIG_EARLY_USERMODE)
+
+#define SYSMGR_FPGAINTF_USEFPGA	0x1
+#define SYSMGR_FPGAINTF_NAND	BIT(4)
+#define SYSMGR_FPGAINTF_SDMMC	BIT(8)
+#define SYSMGR_FPGAINTF_SPIM0	BIT(16)
+#define SYSMGR_FPGAINTF_SPIM1	BIT(24)
+#define SYSMGR_FPGAINTF_EMAC0	BIT(0)
+#define SYSMGR_FPGAINTF_EMAC1	BIT(8)
+#define SYSMGR_FPGAINTF_EMAC2	BIT(16)
+
+#define SYSMGR_SDMMC_SMPLSEL_SHIFT	4
+#define SYSMGR_SDMMC_DRVSEL_SHIFT	0
+
+/* EMAC Group Bit definitions */
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII	0x0
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII		0x1
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII		0x2
+
+#define SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB			0
+#define SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB			2
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK			0x3
+
+#define SYSMGR_NOC_H2F_MSK		0x00000001
+#define SYSMGR_NOC_LWH2F_MSK		0x00000010
+#define SYSMGR_HMC_CLK_STATUS_MSK	0x00000001
+
+#define SYSMGR_DMA_IRQ_NS		0xFF000000
+#define SYSMGR_DMA_MGR_NS		0x00010000
+
+#define SYSMGR_DMAPERIPH_ALL_NS		0xFFFFFFFF
+
+#define SYSMGR_WDDBG_PAUSE_ALL_CPU	0x0F0F0F0F
+
+void agilex5_security_interleaving_on(void);
+void agilex5_security_interleaving_off(void);
+void agilex5_initialize_security_policies(void);
+void agilex5_sysmgr_pinmux_init(void);
+
+#endif /* _SOC64_SYSTEM_MANAGER_H_ */

-- 
2.46.0



From a.fatoum at pengutronix.de  Tue Feb 18 04:43:00 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Tue, 18 Feb 2025 13:43:00 +0100
Subject: [PATCH] dmesg: add support for dumping log into file
Message-ID: <20250218124300.3862498-1-a.fatoum@pengutronix.de>

We already have a log_writefile() helper for dumping the log into a
file. Make it easily accessible via the shell by having a new
dmesg -o option call it.

There is nothing keeping us from extending the function to support flags
and levels like log_print does, but this can follow later if needed.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 commands/dmesg.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/commands/dmesg.c b/commands/dmesg.c
index 8a60f075076e..7982188cda6d 100644
--- a/commands/dmesg.c
+++ b/commands/dmesg.c
@@ -76,13 +76,17 @@ static unsigned dmesg_get_levels(const char *__args)
 
 static int do_dmesg(int argc, char *argv[])
 {
+	const char *outputfile = NULL;
 	int opt, ret, i;
 	int delete_buf = 0, emit = 0;
 	unsigned flags = 0, levels = 0;
 	char *set = NULL;
 
-	while ((opt = getopt(argc, argv, "ctderl:n:")) > 0) {
+	while ((opt = getopt(argc, argv, "o:ctderl:n:")) > 0) {
 		switch (opt) {
+		case 'o':
+			outputfile = optarg;
+			break;
 		case 'c':
 			delete_buf = 1;
 			break;
@@ -111,6 +115,12 @@ static int do_dmesg(int argc, char *argv[])
 		}
 	}
 
+	if (outputfile) {
+		if (flags || levels)
+			return COMMAND_ERROR_USAGE;
+		return log_writefile(outputfile);
+	}
+
 	if (set) {
 		int level = str_to_loglevel(set);
 
@@ -166,6 +176,7 @@ BAREBOX_CMD_HELP_TEXT("Known debug loglevels are: emerg, alert, crit, err, warn,
 BAREBOX_CMD_HELP_TEXT("vdebug")
 BAREBOX_CMD_HELP_TEXT("")
 BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-o <file>",	"Output all log to given file (conflicts with -tdlr)")
 BAREBOX_CMD_HELP_OPT ("-c",		"Delete messages after printing them")
 BAREBOX_CMD_HELP_OPT ("-d",		"Show a time delta to the last message")
 BAREBOX_CMD_HELP_OPT ("-e <msg>",	"Emit a log message")
-- 
2.39.5



From s.hauer at pengutronix.de  Tue Feb 18 06:04:07 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Feb 2025 15:04:07 +0100
Subject: [PATCH 2/2] ARM: i.MX9: Enable PBL_VERIFY_PIGGY with non INSECURE
In-Reply-To: <20250218140407.1224499-1-s.hauer@pengutronix.de>
References: <20250218140407.1224499-1-s.hauer@pengutronix.de>
Message-ID: <20250218140407.1224499-2-s.hauer@pengutronix.de>

i.MX93 boards load barebox proper in the PBL. In a verified boot
scenario this binary must be verified before executing it, so
enable PBL_VERIFY_PIGGY when INSECURE is disabled.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-imx/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 424c7d71a6..239ad674b5 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -190,6 +190,7 @@ config ARCH_IMX93
 	select PINCTRL_IMX_IOMUX_V3
 	select COMMON_CLK_OF_PROVIDER
 	select ARCH_HAS_FEC_IMX
+	select PBL_VERIFY_PIGGY if !INSECURE
 
 config ARCH_VF610
 	bool
-- 
2.39.5



From s.hauer at pengutronix.de  Tue Feb 18 06:04:06 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Feb 2025 15:04:06 +0100
Subject: [PATCH 1/2] ARM: i.MX6: Enable PBL_VERIFY_PIGGY with HABV4 support
Message-ID: <20250218140407.1224499-1-s.hauer@pengutronix.de>

Some i.MX6 configurations use the xload mechanism. With this the ROM
only loads and verifies the PBL. The PBL will then load barebox proper.
Without verification the barebox proper binary is untrusted and could be
modified. Select PBL_VERIFY_PIGGY when HABV4 is enabled to ensure the
barebox proper binary has not been tempered with.

boards not using the xload mechanism don't need this option, but there
is no good way to detect currently if the xload mechanism is used, so
these boards will have to live with a slightly increased binary size
for now.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-imx/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 58b32b8e91..424c7d71a6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -127,6 +127,7 @@ config ARCH_IMX6
 	select PINCTRL_IMX_IOMUX_V3
 	select COMMON_CLK_OF_PROVIDER
 	select HW_HAS_PCI
+	select PBL_VERIFY_PIGGY if HABV4
 
 config ARCH_IMX6SL
 	bool
-- 
2.39.5



From s.hauer at pengutronix.de  Tue Feb 18 06:04:53 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Feb 2025 15:04:53 +0100
Subject: [PATCH] net: Fix DRIVER_NET_TI_DAVINCI_MDIO dependency
In-Reply-To: <20250217110548.1695938-1-s.hauer@pengutronix.de>
References: <20250217110548.1695938-1-s.hauer@pengutronix.de>
Message-ID: <173988749344.1236839.10077501423754980798.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 12:05:48 +0100, Sascha Hauer wrote:
> The davinci-mdio driver was factored out from DRIVER_NET_CPSW which
> depends on ARCH_OMAP, so DRIVER_NET_TI_DAVINCI_MDIO should depend
> on the same symbol, not ARCH_OMAP3.
> 
> 

Applied, thanks!

[1/1] net: Fix DRIVER_NET_TI_DAVINCI_MDIO dependency
      https://git.pengutronix.de/cgit/barebox/commit/?id=38332a5b15f7 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Tue Feb 18 06:05:46 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Tue, 18 Feb 2025 15:05:46 +0100
Subject: [PATCH 1/2] usb: dwc3: am62: Use HZ_PER_KHZ
In-Reply-To: <20250217144543.1777605-1-s.hauer@pengutronix.de>
References: <20250217144543.1777605-1-s.hauer@pengutronix.de>
Message-ID: <173988754624.1251614.15029751625924782411.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 15:45:42 +0100, Sascha Hauer wrote:
> Use HZ_PER_KHZ to make intention clear and drop now unnecessary comment.
> 
> 

Applied, thanks!

[1/2] usb: dwc3: am62: Use HZ_PER_KHZ
      https://git.pengutronix.de/cgit/barebox/commit/?id=5dd32e5531b5 (link may not be stable)
[2/2] usb: dwc3: am62: set mode valid bit before probing children
      https://git.pengutronix.de/cgit/barebox/commit/?id=a2e46da015a4 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From m.felsch at pengutronix.de  Wed Feb 19 02:43:29 2025
From: m.felsch at pengutronix.de (Marco Felsch)
Date: Wed, 19 Feb 2025 11:43:29 +0100
Subject: [PATCH 1/2] ARM: i.MX6: Enable PBL_VERIFY_PIGGY with HABV4
 support
In-Reply-To: <20250218140407.1224499-1-s.hauer@pengutronix.de>
References: <20250218140407.1224499-1-s.hauer@pengutronix.de>
Message-ID: <20250219104329.toyskdpkbtwftatc@pengutronix.de>

Hi Sascha,

On 25-02-18, Sascha Hauer wrote:
> Some i.MX6 configurations use the xload mechanism. With this the ROM
> only loads and verifies the PBL. The PBL will then load barebox proper.
> Without verification the barebox proper binary is untrusted and could be
> modified. Select PBL_VERIFY_PIGGY when HABV4 is enabled to ensure the
> barebox proper binary has not been tempered with.
> 
> boards not using the xload mechanism don't need this option, but there
> is no good way to detect currently if the xload mechanism is used, so
> these boards will have to live with a slightly increased binary size
> for now.

I hav no objections but do you have numbers? There are many i.MX6 based
systems which do use a spi-nor with limited amount of space already
facing size issues since barebox is becoming bigger and bigger.

Regards,
  Marco


From s.hauer at pengutronix.de  Wed Feb 19 04:13:45 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 13:13:45 +0100
Subject: [PATCH 1/2] ARM: i.MX6: Enable PBL_VERIFY_PIGGY with HABV4
 support
In-Reply-To: <20250219104329.toyskdpkbtwftatc@pengutronix.de>
References: <20250218140407.1224499-1-s.hauer@pengutronix.de>
 <20250219104329.toyskdpkbtwftatc@pengutronix.de>
Message-ID: <Z7XK-T1R6HHU99p_@pengutronix.de>

On Wed, Feb 19, 2025 at 11:43:29AM +0100, Marco Felsch wrote:
> Hi Sascha,
> 
> On 25-02-18, Sascha Hauer wrote:
> > Some i.MX6 configurations use the xload mechanism. With this the ROM
> > only loads and verifies the PBL. The PBL will then load barebox proper.
> > Without verification the barebox proper binary is untrusted and could be
> > modified. Select PBL_VERIFY_PIGGY when HABV4 is enabled to ensure the
> > barebox proper binary has not been tempered with.
> > 
> > boards not using the xload mechanism don't need this option, but there
> > is no good way to detect currently if the xload mechanism is used, so
> > these boards will have to live with a slightly increased binary size
> > for now.
> 
> I hav no objections but do you have numbers? There are many i.MX6 based
> systems which do use a spi-nor with limited amount of space already
> facing size issues since barebox is becoming bigger and bigger.

Enabling PBL_VERIFY_PIGGY increases the PBL by about ~6k on ARM/ARM64.

We could add the select to MCI_IMX_ESDHC_PBL instead. The SPI xload
code doesn't have a corresponding Kconfig symbol though, so we would
have to add that first.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Feb 19 04:20:12 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 13:20:12 +0100
Subject: [PATCH v2 08/10] net: phy: add Analog Devices ADIN1300
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-8-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
 <20250218-v2024-10-0-topic-socfpga-agilex5-v2-8-30b6f507810b@pengutronix.de>
Message-ID: <Z7XMfIV1bnTVFpuZ@pengutronix.de>

On Tue, Feb 18, 2025 at 10:21:33AM +0100, Steffen Trumtrar wrote:
> The Analog Devices ADIN1300 is a low power 10Mbps,100Mbps, and 1Gbps
> ethernet phy.
> (https://www.analog.com/media/en/technical-documentation/data-sheets/adin1300.pdf)

Where is this driver from? Can you add a reference to the commit
message?

> 
> Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
> ---
>  drivers/net/phy/Kconfig  |   7 +
>  drivers/net/phy/Makefile |   1 +
>  drivers/net/phy/adin.c   | 360 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 368 insertions(+)
> 

...

> +static u16 adin_ext_read(struct phy_device *phydev, const u32 regnum)
> +{
> +	u16 val;
> +
> +	phy_write(phydev, ADIN1300_MII_EXT_REG_PTR, regnum);
> +	val = phy_read(phydev, ADIN1300_MII_EXT_REG_DATA);
> +
> +	debug("%s: adin at 0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);

phydev_dbg() please.

> +
> +	return val;
> +}
> +
> +static int adin_ext_write(struct phy_device *phydev, const u32 regnum, const u16 val)
> +{
> +	debug("%s: adin at 0x%x 0x%x=0x%x\n", __func__, phydev->addr, regnum, val);

ditto

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Feb 19 04:21:04 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 13:21:04 +0100
Subject: [PATCH v2 07/10] clk: socfpga: add agilex5 clock support
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-7-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
 <20250218-v2024-10-0-topic-socfpga-agilex5-v2-7-30b6f507810b@pengutronix.de>
Message-ID: <Z7XMsHmKuUrCL3o2@pengutronix.de>

On Tue, Feb 18, 2025 at 10:21:32AM +0100, Steffen Trumtrar wrote:
> Add support for the Stratix10 and Agilex5 pll,gate and periph clocks.
> 
> Only tested on Agilex5.
> 
> Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
> ---
>  drivers/clk/socfpga/Makefile         |   4 +-
>  drivers/clk/socfpga/clk-agilex5.c    | 833 +++++++++++++++++++++++++++++++++++
>  drivers/clk/socfpga/clk-gate-s10.c   | 184 ++++++++
>  drivers/clk/socfpga/clk-periph-s10.c | 163 +++++++
>  drivers/clk/socfpga/clk-pll-s10.c    | 140 ++++++
>  drivers/clk/socfpga/clk.h            |   9 +
>  drivers/clk/socfpga/stratix10-clk.h  |  73 +++
>  7 files changed, 1405 insertions(+), 1 deletion(-)
> 
> +
> +static int socfpga_gate_get_parent(struct clk_hw *hwclk)
> +{
> +	struct socfpga_gate_clk *socfpgaclk = to_socfpga_gate_clk(hwclk);
> +	u32 mask, second_bypass;
> +	u8 parent = 0;
> +	const char *name = clk_hw_get_name(hwclk);
> +
> +printk("%s: %s\n", __func__, name);
> +
> +	if (socfpgaclk->bypass_reg) {
> +		mask = (0x1 << socfpgaclk->bypass_shift);
> +		parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
> +			  socfpgaclk->bypass_shift);
> +printk("%s: parent %d\n", __func__, parent);

Debugging leftovers.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Feb 19 05:47:12 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 14:47:12 +0100
Subject: [PATCH v2 09/10] net: add support for Designware XGMAC (10gb)
 ethernet
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-9-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
 <20250218-v2024-10-0-topic-socfpga-agilex5-v2-9-30b6f507810b@pengutronix.de>
Message-ID: <Z7Xg4AHYW1sUFlls@pengutronix.de>

On Tue, Feb 18, 2025 at 10:21:34AM +0100, Steffen Trumtrar wrote:
> The Designware XGMAC is designed for 1/2.5/5/10G ethernet applications.
> It is mostly identical to the eqos driver but has a different register
> layout.
> 
> Signed-off-by: Steffen Trumtrar <s.trumtrar at pengutronix.de>
> ---
>  drivers/net/Kconfig                    |  18 +
>  drivers/net/Makefile                   |   2 +
>  drivers/net/designware_xgmac.c         | 856 +++++++++++++++++++++++++++++++++
>  drivers/net/designware_xgmac.h         | 298 ++++++++++++
>  drivers/net/designware_xgmac_socfpga.c | 156 ++++++
>  5 files changed, 1330 insertions(+)
> 
> diff --git a/drivers/net/designware_xgmac.c b/drivers/net/designware_xgmac.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..ca79ab4cb4a39c053fff0df13f587cbde9c2e6e7
> --- /dev/null
> +static int xgmac_set_full_duplex(struct device *dev)
> +{
> +	struct xgmac_priv *xgmac = dev_get_priv(dev);

The edev to priv conversion is inconsistent in the driver.

Sometimes it's done like:

	struct xgmac_priv *xgmac = dev_get_priv(edev->parent);

Other places have:

	struct xgmac_priv *xgmac = edev->priv;

Please add a

static inline to_xgmac(struct eth_device *edev)
{
	return container_of(edev, struct xgmac_priv, netdev);
}

and use it everywhere.

Also, the functions purely internal to the driver should take a
struct xgmac_priv * directly instead of doing the edev to priv
conversion multiple times.


> +static void xgmac_adjust_link(struct eth_device *edev)
> +{
> +	struct device *dev = edev->parent;
> +	bool en_calibration;

en_calibration is set but not used.

> +	int ret;
> +
> +	if (edev->phydev->duplex)
> +		ret = xgmac_set_full_duplex(dev);
> +	else
> +		ret = xgmac_set_half_duplex(dev);

just return void from these functions. They do not fail.

> +	if (ret < 0) {
> +		dev_err(dev, "xgmac_set_*_duplex() failed: %d\n", ret);
> +	}
> +
> +	switch (edev->phydev->speed) {
> +	case SPEED_1000:
> +		en_calibration = true;
> +		ret = xgmac_set_gmii_speed(dev);
> +		break;
> +	case SPEED_100:
> +		en_calibration = true;
> +		ret = xgmac_set_mii_speed_100(dev);
> +		break;
> +	case SPEED_10:
> +		en_calibration = false;
> +		ret = xgmac_set_mii_speed_10(dev);
> +		break;
> +	default:
> +		dev_err(dev, "invalid speed %d\n", edev->phydev->speed);
> +	}
> +	if (ret < 0)
> +		dev_err(dev, "xgmac_set_*mii_speed*() failed: %d\n", ret);
> +}
> +
> +static int xgmac_start(struct eth_device *edev)
> +{
> +	struct xgmac_priv *xgmac = edev->priv;
> +	int ret, i;
> +	u32 val, tx_fifo_sz, rx_fifo_sz, tqs, rqs, pbl;
> +	ulong last_rx_desc;
> +	ulong desc_pad;
> +	u32 idle;
> +
> +	ret = phy_device_connect(edev, &xgmac->miibus, xgmac->phy_addr,
> +				 xgmac_adjust_link, 0, xgmac->interface);

xgmac->phy_addr is set to 0 during init and used only here. Replace with
-1 to default to scan the bus. Usually the address argument is unused
in phy_device_connect() when the phy is specified in the device tree.
When it's not, then -1 is better than hardcoding phy0.

> +static void xgmac_stop(struct eth_device *edev)
> +{
> +	struct xgmac_priv *xgmac = edev->priv;
> +	u64 start_time;
> +	u32 val;
> +	u32 trcsts;
> +	u32 txqsts;
> +	u32 prxq;
> +	u32 rxqsts;
> +
> +	debug("%s(dev=%p):\n", __func__, edev);

dev_dbg()

> +static int xgmac_send(struct eth_device *edev, void *packet, int length)
> +{
> +	struct xgmac_priv *xgmac = edev->priv;
> +	struct xgmac_desc *tx_desc;
> +	dma_addr_t dma;
> +	u32 des3_prev, des3;
> +	int ret;
> +
> +	tx_desc = &xgmac->tx_descs[xgmac->tx_desc_idx];
> +	xgmac->tx_desc_idx++;
> +	xgmac->tx_desc_idx %= XGMAC_DESCRIPTORS_NUM;
> +
> +	dma = dma_map_single(edev->parent, packet, length, DMA_TO_DEVICE);
> +	if (dma_mapping_error(edev->parent, dma))
> +		return -EFAULT;
> +
> +	tx_desc->des0 = lower_32_bits(dma);
> +	tx_desc->des1 = upper_32_bits(dma);
> +	tx_desc->des2 = length;
> +	/*
> +	 * Make sure that if HW sees the _OWN write below, it will see all the
> +	 * writes to the rest of the descriptor too.
> +	 */
> +	barrier();
> +
> +	des3_prev = XGMAC_DESC3_OWN | XGMAC_DESC3_FD | XGMAC_DESC3_LD | length;
> +	writel(des3_prev, &tx_desc->des3);
> +	writel((ulong)(tx_desc + 1), &xgmac->dma_regs->ch0_txdesc_tail_pointer); // <-- TODO
> +
> +	ret = readl_poll_timeout(&tx_desc->des3, des3,
> +				 !(des3 & XGMAC_DESC3_OWN),
> +				 100 * USEC_PER_MSEC);
> +
> +	dma_unmap_single(edev->parent, dma, length, DMA_TO_DEVICE);
> +
> +	if (ret == -ETIMEDOUT)
> +		debug("%s: TX timeout 0x%08x\n", __func__, des3);

dev_dbg()

> +
> +	return ret;
> +}
> +
> +static void xgmac_recv(struct eth_device *edev)
> +{
> +	struct xgmac_priv *xgmac = edev->priv;
> +	struct xgmac_desc *rx_desc;
> +	dma_addr_t dma;
> +	void *pkt;
> +	int length;
> +
> +	rx_desc = &xgmac->rx_descs[xgmac->rx_desc_idx];
> +
> +	if (rx_desc->des3 & XGMAC_DESC3_OWN)
> +		return;
> +
> +	dma = xgmac->dma_rx_buf_phys[xgmac->rx_desc_idx];
> +	pkt = xgmac->dma_rx_buf_virt[xgmac->rx_desc_idx];
> +	length = rx_desc->des3 & XGMAC_RDES3_PKT_LENGTH_MASK;
> +
> +	dma_sync_single_for_cpu(edev->parent, dma, length, DMA_FROM_DEVICE);
> +	net_receive(edev, pkt, length);
> +	dma_sync_single_for_device(edev->parent, dma, length, DMA_FROM_DEVICE);
> +
> +	/* Read Format RX descriptor */
> +	rx_desc = &xgmac->rx_descs[xgmac->rx_desc_idx];
> +	rx_desc->des0 = dma;

This is a 32bit variable whereas the dma address potentially has 64bit.
Does des1 take the upper 32bit? If yes you should add that, otherwise
a warning would be good.

> +	rx_desc->des1 = 0;
> +	rx_desc->des2 = 0;
> +	/*
> +	 * Make sure that if HW sees the _OWN write below, it will see all the
> +	 * writes to the rest of the descriptor too.
> +	 */
> +	rx_desc->des3 = XGMAC_DESC3_OWN;
> +	barrier();
> +
> +	writel(xgmac->rx_descs_phys + (xgmac->rx_desc_idx * XGMAC_DESCRIPTOR_SIZE),
> +	       &xgmac->dma_regs->ch0_rxdesc_tail_pointer);
> +
> +	xgmac->rx_desc_idx++;
> +	xgmac->rx_desc_idx %= XGMAC_DESCRIPTORS_NUM;
> +}
> +
> +static void xgmac_probe_dt(struct device *dev, struct xgmac_priv *xgmac)
> +{
> +	struct device_node *child;
> +	int phy_reset;
> +	int ret;
> +
> +	xgmac->interface = of_get_phy_mode(dev->of_node);
> +	xgmac->phy_addr = 0;
> +
> +	/* Set MDIO bus device node, if present. */
> +	for_each_child_of_node(dev->of_node, child) {
> +		if (of_device_is_compatible(child, "snps,dwmac-mdio") ||
> +		    (child->name && !of_node_cmp(child->name, "mdio"))) {
> +			xgmac->miibus.dev.of_node = child;
> +			break;
> +		}
> +	}
> +
> +	phy_reset = of_get_named_gpio(dev->of_node, "phy-reset-gpios", 0);
> +	if (gpio_is_valid(phy_reset)) {
> +		ret = gpio_request(phy_reset, "phy-reset");
> +		if (ret)
> +			return;
> +
> +		xgmac->phy_reset_gpio = phy_reset;
> +	}

The phy reset GPIO is optional, but used unconditionally. You'll end up
toggling GPIO 0 when no reset GPIO is given.

Also you could switch to the gpiod API.

> +
> +}
> +
> +int xgmac_probe(struct device *dev)
> +{
> +	struct device_node *np = dev->of_node;
> +	struct mii_bus *miibus;
> +	struct xgmac_priv *xgmac;
> +	struct resource *iores;
> +	struct eth_device *edev;
> +	int ret = 0;
> +
> +	xgmac = xzalloc(sizeof(*xgmac));
> +
> +	xgmac->dev = dev;
> +	xgmac->config = device_get_match_data(dev);
> +	if (ret < 0) {

if (!xgmac->config)

> +		dev_err(dev, "xgmac_probe() failed to get driver data: %d\n", ret);
> +		return ret;
> +	}
> +
> +	iores = dev_request_mem_resource(dev, 0);
> +	if (IS_ERR(iores))
> +		return PTR_ERR(iores);
> +	xgmac->regs = IOMEM(iores->start);
> +
> +	xgmac->mac_regs = xgmac->regs + XGMAC_MAC_REGS_BASE;
> +	xgmac->mtl_regs = xgmac->regs + XGMAC_MTL_REGS_BASE;
> +	xgmac->dma_regs = xgmac->regs + XGMAC_DMA_REGS_BASE;
> +
> +	xgmac_probe_dt(dev, xgmac);
> +
> +	edev = &xgmac->netdev;
> +	dev->priv = edev->priv = xgmac;
> +
> +	edev->parent = dev;
> +	edev->open = xgmac_start;
> +	edev->send = xgmac_send;
> +	edev->halt = xgmac_stop;
> +	edev->recv = xgmac_recv;
> +	edev->get_ethaddr = xgmac_read_rom_hwaddr;
> +	edev->set_ethaddr = xgmac_write_hwaddr;
> +
> +	of_property_read_u32(np, "max-speed", &xgmac->max_speed);

This is unused in the driver.

> diff --git a/drivers/net/designware_xgmac_socfpga.c b/drivers/net/designware_xgmac_socfpga.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..7d8dba3c17cdb3fe7c82a6fa9315fecfdbfcc32a
> --- /dev/null
> +++ b/drivers/net/designware_xgmac_socfpga.c
> @@ -0,0 +1,156 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2023, Intel Corporation
> + */
> +#define DEBUG

Drop please

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Feb 19 05:54:46 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 14:54:46 +0100
Subject: [PATCH v2 10/10] ARM: socfpga: add Arrow AXE5 Agilex5 board
In-Reply-To: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-10-30b6f507810b@pengutronix.de>
References: <20250218-v2024-10-0-topic-socfpga-agilex5-v2-0-30b6f507810b@pengutronix.de>
 <20250218-v2024-10-0-topic-socfpga-agilex5-v2-10-30b6f507810b@pengutronix.de>
Message-ID: <Z7XipiIsN9Vk1Lpu@pengutronix.de>

On Tue, Feb 18, 2025 at 10:21:35AM +0100, Steffen Trumtrar wrote:
> diff --git a/arch/arm/boards/arrow-axe5-eagle/lowlevel.c b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..b736ca643f86b031dc070baf62f15a4a09e5aaba
> --- /dev/null
> +++ b/arch/arm/boards/arrow-axe5-eagle/lowlevel.c
> @@ -0,0 +1,74 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <common.h>
> +#include <io.h>
> +#include <linux/sizes.h>
> +#include <asm/barebox-arm.h>
> +#include <asm/system.h>
> +#include <pbl.h>
> +#include <mach/socfpga/debug_ll.h>
> +#include <mach/socfpga/init.h>
> +#include <mach/socfpga/generic.h>
> +#include <mach/socfpga/mailbox_s10.h>
> +#include <mach/socfpga/soc64-firewall.h>
> +#include <mach/socfpga/soc64-regs.h>
> +#include <mach/socfpga/soc64-sdram.h>
> +#include <mach/socfpga/soc64-system-manager.h>
> +
> +extern char __dtb_z_socfpga_agilex5_axe5_eagle_start[];
> +
> +#define AXE5_STACKTOP	(SZ_512K)
> +
> +static noinline void axe5_eagle_continue(void)
> +{
> +	void *fdt;
> +
> +	agilex5_clk_init();
> +
> +	socfpga_uart_setup_ll();
> +	pbl_set_putc(socfpga_uart_putc, (void *) SOCFPGA_UART0_ADDRESS);
> +
> +	pr_debug("Lowlevel init done\n");
> +
> +	printk("Change the pullup values on EMAC2 HPS mii signals\n");

debugging leftover?

> +	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x224);
> +	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x228);
> +	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x23c);
> +	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x234);
> +	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x248);
> +	writel(0x14, SOCFPGA_PINMUX_ADDRESS + 0x24c);
> +
> +	writel(0x410, 0x10c03304);
> +	writel(0x410, 0x10c03300);
> +	/* reset the phy via GPIO10. We currently haven't got enough space
> +	 * to enable the gpio driver in barebox. */
> +	writel(0x000, 0x10c03300);
> +	mdelay(1000);

Quite a long time. Is this necessary?

> +	writel(0x410, 0x10c03300);
> +
> +	if (current_el() == 3) {
> +		agilex5_initialize_security_policies();
> +		pr_debug("Security policies initialized\n");
> +
> +		agilex5_ddr_init_full();
> +
> +		socfpga_mailbox_s10_init();
> +		socfpga_mailbox_s10_qspi_open();
> +
> +		agilex5_load_and_start_image_via_tfa(SZ_1G);
> +	}
> +
> +	fdt = __dtb_z_socfpga_agilex5_axe5_eagle_start;
> +
> +	barebox_arm_entry(SOCFPGA_AGILEX5_DDR_BASE + SZ_1M, SZ_1G - SZ_1M, fdt);
> +}
> +
> +ENTRY_FUNCTION_WITHSTACK(start_socfpga_agilex5_axe5_eagle, AXE5_STACKTOP, r0, r1, r2)
> +{
> +	if (current_el() == 3)
> +		socfpga_agilex5_cpu_lowlevel_init();
> +
> +	relocate_to_current_adr();
> +	setup_c();
> +
> +	axe5_eagle_continue();
> +}
> diff --git a/arch/arm/configs/socfpga-agilex5_defconfig b/arch/arm/configs/socfpga-agilex5_defconfig
> new file mode 100644
> index 0000000000000000000000000000000000000000..b443a1281e6ad621d7270cade3ea0d60ccdc9af5
> --- /dev/null
> +++ b/arch/arm/configs/socfpga-agilex5_defconfig

Do we need another defconfig? Can we add it to multi_v8_defconfig
instead?

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Wed Feb 19 06:18:39 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 15:18:39 +0100
Subject: [PATCH 0/5] Filesystem memory corruption fixes
Message-ID: <20250219141844.1912413-1-s.hauer@pengutronix.de>

These are some fixes for memory corruptions that can occur on corrupted
or manipulated filesystems.

In case you use one of the affected filesystems in a secure boot chain
you should apply these patches.

Normally you shouldn't use a barebox filesystem in a secure boot chain,
but instead use FIT images on a raw partition. We never made this explicit
though. Ahmad has done this recently:

https://lore.kernel.org/barebox/20250217180949.3961860-3-a.fatoum at pengutronix.de/T/#u

I digged through the U-Boot code and there are a few CVE fixes in the
ext4 code that we'll likely need as well. But even with these applied
we don't consider the barebox filesystems as suitable for secure boot.

For those curious we consider adding support for dm-verity at some
point. This would allow us to remove the attack surface from the
filesystem implementations and we could also use bootspec rather than
signed FIT images.

Sascha

Sascha Hauer (5):
  CVE-2025-26722: fs: squashfs: Ensure positive inode length
  CVE-2025-26724: fs: cramfs: fix malloc(size + constant) buffer
    overflow issues
  CVE-2025-26723: fs: ext4: fix malloc(size + constant) buffer overflow
    issues
  CVE-2025-26725: fs: jffs2: fix malloc(size + constant) buffer overflow
    issues
  CVE-2025-26721: fs: pstore: fix malloc(size + constant) buffer
    overflow issues

 fs/cramfs/cramfs.c    | 2 +-
 fs/ext4/ext_barebox.c | 2 +-
 fs/jffs2/malloc.c     | 4 ++--
 fs/jffs2/nodelist.h   | 2 +-
 fs/jffs2/readinode.c  | 2 +-
 fs/pstore/fs.c        | 2 +-
 fs/squashfs/symlink.c | 8 ++++++--
 7 files changed, 13 insertions(+), 9 deletions(-)

-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 19 06:18:43 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 15:18:43 +0100
Subject: [PATCH 4/5] CVE-2025-26725: fs: jffs2: fix malloc(size + constant) buffer overflow issues
In-Reply-To: <20250219141844.1912413-1-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
Message-ID: <20250219141844.1912413-5-s.hauer@pengutronix.de>

The pattern malloc(size + constant) is dangerous when size can be
manipulated by an attacker. In that case 'size' can be manipulated
in a way that 'size + constant' is 0 due to integer overflow. The
result is a zero sized buffer to which is then data written to.

Avoid this by using size_add() and struct_size() instead.

Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 fs/jffs2/malloc.c    | 4 ++--
 fs/jffs2/nodelist.h  | 2 +-
 fs/jffs2/readinode.c | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index e0e29fa648..61c2430c18 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -15,10 +15,10 @@
 #include <linux/jffs2.h>
 #include "nodelist.h"
 
-struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
+struct jffs2_full_dirent *jffs2_alloc_full_dirent(size_t namesize)
 {
 	struct jffs2_full_dirent *ret;
-	ret = kmalloc(sizeof(*ret) + namesize, GFP_KERNEL);
+	ret = kmalloc(struct_size(ret, name, namesize), GFP_KERNEL);
 	dbg_memalloc("%p\n", ret);
 	return ret;
 }
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index d8687319c7..28b35d6d58 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -440,7 +440,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
 
 /* malloc.c */
 
-struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize);
+struct jffs2_full_dirent *jffs2_alloc_full_dirent(size_t namesize);
 void jffs2_free_full_dirent(struct jffs2_full_dirent *);
 struct jffs2_full_dnode *jffs2_alloc_full_dnode(void);
 void jffs2_free_full_dnode(struct jffs2_full_dnode *dnode);
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 605130d60c..4634ee5818 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -601,7 +601,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r
 		spin_unlock(&c->erase_completion_lock);
 	}
 
-	fd = jffs2_alloc_full_dirent(rd->nsize + 1);
+	fd = jffs2_alloc_full_dirent(size_add(rd->nsize, 1));
 	if (unlikely(!fd))
 		return -ENOMEM;
 
-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 19 06:18:42 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 15:18:42 +0100
Subject: [PATCH 3/5] CVE-2025-26723: fs: ext4: fix malloc(size + constant) buffer overflow issues
In-Reply-To: <20250219141844.1912413-1-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
Message-ID: <20250219141844.1912413-4-s.hauer@pengutronix.de>

The pattern malloc(size + constant) is dangerous when size can be
manipulated by an attacker. In that case 'size' can be manipulated
in a way that 'size + constant' is 0 due to integer overflow. The
result is a zero sized buffer to which is then data written to.

Avoid this by using size_add() instead.

Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 fs/ext4/ext_barebox.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c
index 163c4d2fe1..7480c045d7 100644
--- a/fs/ext4/ext_barebox.c
+++ b/fs/ext4/ext_barebox.c
@@ -189,7 +189,7 @@ static const char *ext_get_link(struct dentry *dentry, struct inode *inode)
 
 	BUG_ON(inode->i_link);
 
-	inode->i_link = zalloc(inode->i_size + 1);
+	inode->i_link = zalloc(size_add(inode->i_size, 1));
 
 	ret = ext4fs_read_file(node, 0, inode->i_size, inode->i_link);
 	if (ret == 0) {
-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 19 06:18:44 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 15:18:44 +0100
Subject: [PATCH 5/5] CVE-2025-26721: fs: pstore: fix malloc(size + constant) buffer overflow issues
In-Reply-To: <20250219141844.1912413-1-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
Message-ID: <20250219141844.1912413-6-s.hauer@pengutronix.de>

The pattern malloc(size + constant) is dangerous when size can be
manipulated by an attacker. In that case 'size' can be manipulated
in a way that 'size + constant' is 0 due to integer overflow. The
result is a zero sized buffer to which is then data written to.

Avoid this by using struct_size() instead.

Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 fs/pstore/fs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c
index 24b0fa5c9d..706c2d4684 100644
--- a/fs/pstore/fs.c
+++ b/fs/pstore/fs.c
@@ -62,7 +62,7 @@ int pstore_mkfile(struct pstore_record *record)
 			return -EEXIST;
 	}
 
-	private = xzalloc(sizeof(*private) + size);
+	private = xzalloc(struct_size(private, data, size));
 	private->type = record->type;
 	private->id = record->id;
 	private->count = record->count;
-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 19 06:18:40 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 15:18:40 +0100
Subject: [PATCH 1/5] CVE-2025-26722: fs: squashfs: Ensure positive inode length
In-Reply-To: <20250219141844.1912413-1-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
Message-ID: <20250219141844.1912413-2-s.hauer@pengutronix.de>

In squashfs_get_link() we have:

	int length = min_t(int, i_size_read(inode), PAGE_SIZE);

The inode size is a 64bit number directly read from the device which
is interpreted as a 32bit signed number above. An inode size with the
lower 32bits set to 0xffffffff results in length being -1. Later we
do a:

	symlink = malloc(length + 1);

With length being -1 this results in allocating a zero size buffer which
is then overwritten by following code.

Fix this by first making sure that the inode length is positive.
Afterwards limit the length to the desired range, explicitly using
loff_t as the type to compare to make sure we do not truncate the
original data type during comparison.

Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 fs/squashfs/symlink.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
index 40b9bdcc8b..cb14eb20a5 100644
--- a/fs/squashfs/symlink.c
+++ b/fs/squashfs/symlink.c
@@ -43,16 +43,20 @@
 static const char *squashfs_get_link(struct dentry *dentry, struct inode *inode)
 {
 	struct super_block *sb = inode->i_sb;
-	int index = 0;
 	u64 block = squashfs_i(inode)->start;
 	int offset = squashfs_i(inode)->offset;
-	int length = min_t(int, i_size_read(inode) - index, PAGE_SIZE);
+	size_t length;
 	int bytes;
 	unsigned char *symlink;
 
 	TRACE("Entered squashfs_symlink_readpage, start block "
 			"%llx, offset %x\n", block, offset);
 
+	if (i_size_read(inode) < 0)
+		return NULL;
+
+	length = min_t(loff_t, i_size_read(inode), PAGE_SIZE);
+
 	symlink = malloc(length + 1);
 	if (!symlink)
 		return NULL;
-- 
2.39.5



From s.hauer at pengutronix.de  Wed Feb 19 06:18:41 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Wed, 19 Feb 2025 15:18:41 +0100
Subject: [PATCH 2/5] CVE-2025-26724: fs: cramfs: fix malloc(size + constant) buffer overflow issues
In-Reply-To: <20250219141844.1912413-1-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
Message-ID: <20250219141844.1912413-3-s.hauer@pengutronix.de>

The pattern malloc(size + constant) is dangerous when size can be
manipulated by an attacker. In that case 'size' can be manipulated
in a way that 'size + constant' is 0 due to integer overflow. The
result is a zero sized buffer to which is then data written to.

Avoid this by using size_add() instead.

Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 fs/cramfs/cramfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index e554ebef6f..641a6d2b05 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -423,7 +423,7 @@ static const char *cramfs_get_link(struct dentry *dentry, struct inode *inode)
 {
 	int ret;
 
-	inode->i_link = xzalloc(inode->i_size + 1);
+	inode->i_link = xzalloc(size_add(inode->i_size, 1));
 
 	ret = cramfs_read_file(inode, 0, inode->i_link, inode->i_size);
 	if (ret < 0)
-- 
2.39.5



From a.fatoum at pengutronix.de  Wed Feb 19 08:47:39 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Feb 2025 17:47:39 +0100
Subject: [PATCH 0/5] Filesystem memory corruption fixes
In-Reply-To: <20250219141844.1912413-1-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
Message-ID: <5aad1a19-e9d7-47b8-a096-1122ae3a1256@pengutronix.de>

On 19.02.25 15:18, Sascha Hauer wrote:
> These are some fixes for memory corruptions that can occur on corrupted
> or manipulated filesystems.
> 
> In case you use one of the affected filesystems in a secure boot chain
> you should apply these patches.
> 
> Normally you shouldn't use a barebox filesystem in a secure boot chain,
> but instead use FIT images on a raw partition. We never made this explicit
> though. Ahmad has done this recently:
> 
> https://lore.kernel.org/barebox/20250217180949.3961860-3-a.fatoum at pengutronix.de/T/#u
> 
> I digged through the U-Boot code and there are a few CVE fixes in the
> ext4 code that we'll likely need as well. But even with these applied
> we don't consider the barebox filesystems as suitable for secure boot.
> 
> For those curious we consider adding support for dm-verity at some
> point. This would allow us to remove the attack surface from the
> filesystem implementations and we could also use bootspec rather than
> signed FIT images.
> 
> Sascha
> 
> Sascha Hauer (5):
>   CVE-2025-26722: fs: squashfs: Ensure positive inode length
>   CVE-2025-26724: fs: cramfs: fix malloc(size + constant) buffer
>     overflow issues
>   CVE-2025-26723: fs: ext4: fix malloc(size + constant) buffer overflow
>     issues
>   CVE-2025-26725: fs: jffs2: fix malloc(size + constant) buffer overflow
>     issues
>   CVE-2025-26721: fs: pstore: fix malloc(size + constant) buffer
>     overflow issues

I think the CVE id should better go into the commit message body, (maybe
with a Fixes: before it) and not into the title.


Thanks,
Ahmad

> 
>  fs/cramfs/cramfs.c    | 2 +-
>  fs/ext4/ext_barebox.c | 2 +-
>  fs/jffs2/malloc.c     | 4 ++--
>  fs/jffs2/nodelist.h   | 2 +-
>  fs/jffs2/readinode.c  | 2 +-
>  fs/pstore/fs.c        | 2 +-
>  fs/squashfs/symlink.c | 8 ++++++--
>  7 files changed, 13 insertions(+), 9 deletions(-)
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Feb 19 08:49:05 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Feb 2025 17:49:05 +0100
Subject: [PATCH 1/5] CVE-2025-26722: fs: squashfs: Ensure positive inode
 length
In-Reply-To: <20250219141844.1912413-2-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
 <20250219141844.1912413-2-s.hauer@pengutronix.de>
Message-ID: <61270515-e726-4447-b924-b9c1f919cf74@pengutronix.de>

On 19.02.25 15:18, Sascha Hauer wrote:
> In squashfs_get_link() we have:
> 
> 	int length = min_t(int, i_size_read(inode), PAGE_SIZE);
> 
> The inode size is a 64bit number directly read from the device which
> is interpreted as a 32bit signed number above. An inode size with the
> lower 32bits set to 0xffffffff results in length being -1. Later we
> do a:
> 
> 	symlink = malloc(length + 1);
> 
> With length being -1 this results in allocating a zero size buffer which
> is then overwritten by following code.
> 
> Fix this by first making sure that the inode length is positive.
> Afterwards limit the length to the desired range, explicitly using
> loff_t as the type to compare to make sure we do not truncate the
> original data type during comparison.
> 
> Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>

Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

> ---
>  fs/squashfs/symlink.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
> index 40b9bdcc8b..cb14eb20a5 100644
> --- a/fs/squashfs/symlink.c
> +++ b/fs/squashfs/symlink.c
> @@ -43,16 +43,20 @@
>  static const char *squashfs_get_link(struct dentry *dentry, struct inode *inode)
>  {
>  	struct super_block *sb = inode->i_sb;
> -	int index = 0;
>  	u64 block = squashfs_i(inode)->start;
>  	int offset = squashfs_i(inode)->offset;
> -	int length = min_t(int, i_size_read(inode) - index, PAGE_SIZE);
> +	size_t length;
>  	int bytes;
>  	unsigned char *symlink;
>  
>  	TRACE("Entered squashfs_symlink_readpage, start block "
>  			"%llx, offset %x\n", block, offset);
>  
> +	if (i_size_read(inode) < 0)
> +		return NULL;
> +
> +	length = min_t(loff_t, i_size_read(inode), PAGE_SIZE);
> +
>  	symlink = malloc(length + 1);
>  	if (!symlink)
>  		return NULL;


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Feb 19 08:50:53 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Feb 2025 17:50:53 +0100
Subject: [PATCH 2/5] CVE-2025-26724: fs: cramfs: fix malloc(size +
 constant) buffer overflow issues
In-Reply-To: <20250219141844.1912413-3-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
 <20250219141844.1912413-3-s.hauer@pengutronix.de>
Message-ID: <0b07c033-131d-4403-8709-0e31bce0617f@pengutronix.de>

On 19.02.25 15:18, Sascha Hauer wrote:
> The pattern malloc(size + constant) is dangerous when size can be
> manipulated by an attacker. In that case 'size' can be manipulated
> in a way that 'size + constant' is 0 due to integer overflow. The
> result is a zero sized buffer to which is then data written to.
> 
> Avoid this by using size_add() instead.

For those unfamiliar with size_add(), it does a saturation addition
and thus xzalloc() will fail as it's impossible to allocate
SIZE_MAX bytes.

> 
> Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>

Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

Thanks,
Ahmad

> ---
>  fs/cramfs/cramfs.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
> index e554ebef6f..641a6d2b05 100644
> --- a/fs/cramfs/cramfs.c
> +++ b/fs/cramfs/cramfs.c
> @@ -423,7 +423,7 @@ static const char *cramfs_get_link(struct dentry *dentry, struct inode *inode)
>  {
>  	int ret;
>  
> -	inode->i_link = xzalloc(inode->i_size + 1);
> +	inode->i_link = xzalloc(size_add(inode->i_size, 1));
>  
>  	ret = cramfs_read_file(inode, 0, inode->i_link, inode->i_size);
>  	if (ret < 0)


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Feb 19 08:51:14 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Feb 2025 17:51:14 +0100
Subject: [PATCH 3/5] CVE-2025-26723: fs: ext4: fix malloc(size + constant)
 buffer overflow issues
In-Reply-To: <20250219141844.1912413-4-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
 <20250219141844.1912413-4-s.hauer@pengutronix.de>
Message-ID: <4d1d9746-0f83-4c4b-b239-8001939b6d46@pengutronix.de>

On 19.02.25 15:18, Sascha Hauer wrote:
> The pattern malloc(size + constant) is dangerous when size can be
> manipulated by an attacker. In that case 'size' can be manipulated
> in a way that 'size + constant' is 0 due to integer overflow. The
> result is a zero sized buffer to which is then data written to.
> 
> Avoid this by using size_add() instead.
> 
> Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>

Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

> ---
>  fs/ext4/ext_barebox.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/ext4/ext_barebox.c b/fs/ext4/ext_barebox.c
> index 163c4d2fe1..7480c045d7 100644
> --- a/fs/ext4/ext_barebox.c
> +++ b/fs/ext4/ext_barebox.c
> @@ -189,7 +189,7 @@ static const char *ext_get_link(struct dentry *dentry, struct inode *inode)
>  
>  	BUG_ON(inode->i_link);
>  
> -	inode->i_link = zalloc(inode->i_size + 1);
> +	inode->i_link = zalloc(size_add(inode->i_size, 1));
>  
>  	ret = ext4fs_read_file(node, 0, inode->i_size, inode->i_link);
>  	if (ret == 0) {


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Feb 19 08:54:09 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Feb 2025 17:54:09 +0100
Subject: [PATCH 4/5] CVE-2025-26725: fs: jffs2: fix malloc(size +
 constant) buffer overflow issues
In-Reply-To: <20250219141844.1912413-5-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
 <20250219141844.1912413-5-s.hauer@pengutronix.de>
Message-ID: <26e93d34-4278-4f72-a5bf-2bd8170d7418@pengutronix.de>

Hi Sascha,

On 19.02.25 15:18, Sascha Hauer wrote:
> The pattern malloc(size + constant) is dangerous when size can be
> manipulated by an attacker. In that case 'size' can be manipulated
> in a way that 'size + constant' is 0 due to integer overflow. The
> result is a zero sized buffer to which is then data written to.
> 
> Avoid this by using size_add() and struct_size() instead.
> 
> Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>

With below comment addressed:
Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

> ---
>  fs/jffs2/malloc.c    | 4 ++--
>  fs/jffs2/nodelist.h  | 2 +-
>  fs/jffs2/readinode.c | 2 +-
>  3 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
> index e0e29fa648..61c2430c18 100644
> --- a/fs/jffs2/malloc.c
> +++ b/fs/jffs2/malloc.c
> @@ -15,10 +15,10 @@
>  #include <linux/jffs2.h>
>  #include "nodelist.h"
>  
> -struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
> +struct jffs2_full_dirent *jffs2_alloc_full_dirent(size_t namesize)
>  {
>  	struct jffs2_full_dirent *ret;
> -	ret = kmalloc(sizeof(*ret) + namesize, GFP_KERNEL);
> +	ret = kmalloc(struct_size(ret, name, namesize), GFP_KERNEL);

I was under the impression that struct_size requires the last argument to be
the name of a C99 flexible array member[] and not that of a zero-sized array.

Could you squash a change from struct jffs2_full_dirent::name[0] to ::name[] in 
fs/jffs2/nodelist.h into this commit?

Thanks,
Ahmad

>  	dbg_memalloc("%p\n", ret);
>  	return ret;
>  }
> diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
> index d8687319c7..28b35d6d58 100644
> --- a/fs/jffs2/nodelist.h
> +++ b/fs/jffs2/nodelist.h
> @@ -440,7 +440,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
>  
>  /* malloc.c */
>  
> -struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize);
> +struct jffs2_full_dirent *jffs2_alloc_full_dirent(size_t namesize);
>  void jffs2_free_full_dirent(struct jffs2_full_dirent *);
>  struct jffs2_full_dnode *jffs2_alloc_full_dnode(void);
>  void jffs2_free_full_dnode(struct jffs2_full_dnode *dnode);
> diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
> index 605130d60c..4634ee5818 100644
> --- a/fs/jffs2/readinode.c
> +++ b/fs/jffs2/readinode.c
> @@ -601,7 +601,7 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r
>  		spin_unlock(&c->erase_completion_lock);
>  	}
>  
> -	fd = jffs2_alloc_full_dirent(rd->nsize + 1);
> +	fd = jffs2_alloc_full_dirent(size_add(rd->nsize, 1));
>  	if (unlikely(!fd))
>  		return -ENOMEM;
>  


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Feb 19 08:54:48 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Wed, 19 Feb 2025 17:54:48 +0100
Subject: [PATCH 5/5] CVE-2025-26721: fs: pstore: fix malloc(size +
 constant) buffer overflow issues
In-Reply-To: <20250219141844.1912413-6-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
 <20250219141844.1912413-6-s.hauer@pengutronix.de>
Message-ID: <53d279f3-7cca-48e0-b688-b1ceb7d013fc@pengutronix.de>

On 19.02.25 15:18, Sascha Hauer wrote:
> The pattern malloc(size + constant) is dangerous when size can be
> manipulated by an attacker. In that case 'size' can be manipulated
> in a way that 'size + constant' is 0 due to integer overflow. The
> result is a zero sized buffer to which is then data written to.
> 
> Avoid this by using struct_size() instead.
> 
> Reported-by: Jonathan Bar Or <jonathanbaror at gmail.com>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>

Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

> ---
>  fs/pstore/fs.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/pstore/fs.c b/fs/pstore/fs.c
> index 24b0fa5c9d..706c2d4684 100644
> --- a/fs/pstore/fs.c
> +++ b/fs/pstore/fs.c
> @@ -62,7 +62,7 @@ int pstore_mkfile(struct pstore_record *record)
>  			return -EEXIST;
>  	}
>  
> -	private = xzalloc(sizeof(*private) + size);
> +	private = xzalloc(struct_size(private, data, size));
>  	private->type = record->type;
>  	private->id = record->id;
>  	private->count = record->count;


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Feb 19 22:38:47 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 07:38:47 +0100
Subject: [PATCH] scripts: include: rename printk.h to printf.h
In-Reply-To: <173891686844.239361.18192152268825416500.b4-ty@pengutronix.de>
References: <20250205102549.27015-1-jmaselbas@zdiv.net>
 <173891686844.239361.18192152268825416500.b4-ty@pengutronix.de>
Message-ID: <ddc2507d-47e4-4cc0-98fe-ef85f34cbd98@pengutronix.de>

Hello Sascha,

On 07.02.25 09:27, Sascha Hauer wrote:
> 
> On Wed, 05 Feb 2025 11:25:49 +0100, Jules Maselbas wrote:
>> The include scripts/include/asm-generic/bug.h relied on a printk.h
>> compatible header which is located in the scripts/include/ and was
>> not updated when printk.h was renamed to printf.h.
>>
>>
> 
> Applied, thanks!

Please apply this patch to master as the musl build is otherwise broken
(glibc provides a <printf.h> header).

Thanks,
Ahmad

> 
> [1/1] scripts: include: rename printk.h to printf.h
>       https://git.pengutronix.de/cgit/barebox/commit/?id=f7a4435177aa (link may not be stable)
> 
> Best regards,


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Wed Feb 19 22:46:11 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 07:46:11 +0100
Subject: [PATCH master 1/2] scripts: define _GNU_SOURCE for every user tool build
Message-ID: <20250220064612.865757-1-a.fatoum@pengutronix.de>

Defining _GNU_SOURCE via userccflags (for target tools) and KBUILD_HOSTCFLAGS
(for host tools) works, but needs to be repeated in subdirectories like i.MX
as well. As we make ample use of the asprintf GNU extension anyway, let's just
define it in the top-level makefile for build of all user code.

Fixes: 02a61edc1842 ("scripts: define _GNU_SOURCE for all source files")
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 Makefile         | 3 ++-
 scripts/Makefile | 4 ----
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/Makefile b/Makefile
index 5488f9d97251..4e6ac5a10a97 100644
--- a/Makefile
+++ b/Makefile
@@ -399,7 +399,8 @@ HOSTCXX	= g++
 endif
 
 KBUILD_USERHOSTCFLAGS := -Wall -Wmissing-prototypes -Wstrict-prototypes \
-			      -O2 -fomit-frame-pointer -std=gnu11
+			      -O2 -fomit-frame-pointer -std=gnu11 \
+			      -D_GNU_SOURCE=""
 KBUILD_USERCFLAGS  := $(KBUILD_USERHOSTCFLAGS) $(USERCFLAGS)
 KBUILD_USERLDFLAGS := $(USERLDFLAGS)
 
diff --git a/scripts/Makefile b/scripts/Makefile
index bb4e85b0a639..6d89af7d4f35 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -60,10 +60,6 @@ rk-usb-loader-target-userldlibs += `$(CROSS_PKG_CONFIG) --libs libusb-1.0`
 
 userccflags += -I $(srctree)/$(src)/include -isystem $(srctree)/scripts/include
 
-# We need to explicitly set the macro to empty, otherwise it's defined to =1
-userccflags += -D_GNU_SOURCE=""
-KBUILD_HOSTCFLAGS += -D_GNU_SOURCE=""
-
 subdir-y			+= mod
 subdir-y			+= imx
 subdir-$(CONFIG_ARCH_TEGRA)	+= tegra
-- 
2.39.5



From a.fatoum at pengutronix.de  Wed Feb 19 22:46:12 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 07:46:12 +0100
Subject: [PATCH master 2/2] scripts: common.h: define loff_t on musl
In-Reply-To: <20250220064612.865757-1-a.fatoum@pengutronix.de>
References: <20250220064612.865757-1-a.fatoum@pengutronix.de>
Message-ID: <20250220064612.865757-2-a.fatoum@pengutronix.de>

Target tool build against musl fails, because loff_t is undefined,
despite _GNU_SOURCE being defined.

This is because glibc defines loff_t via <sys/types.h>, but musl defines
loff_t only in fcntl.h and the latter file isn't included beforehand in
imx-usb-loader-target.c.

Add the missing include to <linux/types.h> and include that header in
scripts/common.h to resolve the musl breakage.

This issue was noticedd during a Yocto build against musl, but can be
easily reproduced in Debian as well using the musl-tools package:

  export ARCH=sandbox
  make HOSTCC=musl-gcc CC=musl-gcc targettools_defconfig
  make HOSTCC=musl-gcc CC=musl-gcc

Changes to CI to build sandbox against musl will follow later.

Fixes: 5171f4d0696f ("scripts: implement read_fd and pread_full for tools")
Reported-by: Enrico J?rns <ejo at pengutronix.de>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 scripts/common.h              | 2 ++
 scripts/include/linux/types.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/scripts/common.h b/scripts/common.h
index a0d16606b5d9..21ec576a5be9 100644
--- a/scripts/common.h
+++ b/scripts/common.h
@@ -1,6 +1,8 @@
 #ifndef __COMMON_H
 #define __COMMON_H
 
+#include <linux/types.h>
+
 int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_size);
 void *read_file(const char *filename, size_t *size);
 void *read_fd(int fd, size_t *out_size);
diff --git a/scripts/include/linux/types.h b/scripts/include/linux/types.h
index e81d7e810126..5b0133345bb9 100644
--- a/scripts/include/linux/types.h
+++ b/scripts/include/linux/types.h
@@ -4,6 +4,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <fcntl.h>
 
 typedef uint64_t __u64;
 typedef int64_t __s64;
-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 20 00:26:22 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Feb 2025 09:26:22 +0100
Subject: [PATCH 0/6] of: partition: add Linux
 CONFIG_OF_PARTITION-compatible adaptive fixup mode
In-Reply-To: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
References: <20250217180833.3955657-1-a.fatoum@pengutronix.de>
Message-ID: <174003998208.2425412.5151355715286141072.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 19:08:27 +0100, Ahmad Fatoum wrote:
> barebox has for many years supported a superset of the upstream OF
> partitions binding by parsing partitions out of SD/eMMC and EEPROM
> in addition to MTD.
> 
> Unfortunately, we didn't upstream our binding and a different binding
> went upstream into Linux v6.13-rc1 along with Linux commit
> 2e3a191e89f9 ("block: add support for partition table defined in OF").
> 
> [...]

Applied, thanks!

[1/6] of: factor out of_node_is_fixed_partitions check
      https://git.pengutronix.de/cgit/barebox/commit/?id=45c5c9c807e4 (link may not be stable)
[2/6] of: of_path: support barebox,fixed-partitions
      https://git.pengutronix.de/cgit/barebox/commit/?id=deb18a4be9cd (link may not be stable)
[3/6] ARM: IMX8MP: var-dart-dt8mcustomboard.dts: use new-style partition binding
      https://git.pengutronix.de/cgit/barebox/commit/?id=c19cbce92960 (link may not be stable)
[4/6] ARM: dts: prefix all non-MTD fixed-partitions with barebox,
      https://git.pengutronix.de/cgit/barebox/commit/?id=cf4cf9997a3b (link may not be stable)
[5/6] of: partition: refactor of_partition_binding checks into switch
      https://git.pengutronix.de/cgit/barebox/commit/?id=162884adec56 (link may not be stable)
[6/6] of: partition: add Linux CONFIG_OF_PARTITION-compatible adaptive fixup mode
      https://git.pengutronix.de/cgit/barebox/commit/?id=f0d91d7ba6cb (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Thu Feb 20 01:17:43 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Thu, 20 Feb 2025 10:17:43 +0100
Subject: [PATCH] boot: fix systemd watchdog command line argument
Message-ID: <20250220091743.3489127-1-s.hauer@pengutronix.de>

The kernel command line option to specify the watchdog to use is
"systemd.watchdog_device" as specified in [1], not
"systemd.watchdog-device"

[1] https://www.freedesktop.org/software/systemd/man/latest/kernel-command-line.html#systemd.watchdog_sec=

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 common/oftree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/common/oftree.c b/common/oftree.c
index 4afe955719..2ebde791c7 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -172,7 +172,7 @@ static void watchdog_build_bootargs(struct watchdog *watchdog, struct device_nod
 	if (alias_id < 0)
 		return;
 
-	buf = basprintf("systemd.watchdog-device=/dev/watchdog%d", alias_id);
+	buf = basprintf("systemd.watchdog_device=/dev/watchdog%d", alias_id);
 	if (!buf)
 		return;
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Thu Feb 20 04:06:53 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 13:06:53 +0100
Subject: [PATCH] boot: fix systemd watchdog command line argument
In-Reply-To: <20250220091743.3489127-1-s.hauer@pengutronix.de>
References: <20250220091743.3489127-1-s.hauer@pengutronix.de>
Message-ID: <1058511f-b54e-44be-b267-dce2b1fd048a@pengutronix.de>

On 20.02.25 10:17, Sascha Hauer wrote:
> The kernel command line option to specify the watchdog to use is
> "systemd.watchdog_device" as specified in [1], not
> "systemd.watchdog-device"
> 
> [1] https://www.freedesktop.org/software/systemd/man/latest/kernel-command-line.html#systemd.watchdog_sec=
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>

Please also include the typo fix in the common/Kconfig help text for
CONFIG_SYSTEMD_OF_WATCHDOG.

With that squashed:

Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>

I could swear I have tested this with two watchdogs back then...

Anyways, I have submitted a fix to the systemd documentation here:
https://github.com/systemd/systemd/pull/36453

Thanks,
Ahmad


> ---
>  common/oftree.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/common/oftree.c b/common/oftree.c
> index 4afe955719..2ebde791c7 100644
> --- a/common/oftree.c
> +++ b/common/oftree.c
> @@ -172,7 +172,7 @@ static void watchdog_build_bootargs(struct watchdog *watchdog, struct device_nod
>  	if (alias_id < 0)
>  		return;
>  
> -	buf = basprintf("systemd.watchdog-device=/dev/watchdog%d", alias_id);
> +	buf = basprintf("systemd.watchdog_device=/dev/watchdog%d", alias_id);
>  	if (!buf)
>  		return;
>  


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From stefano.manni at gmail.com  Thu Feb 20 09:39:55 2025
From: stefano.manni at gmail.com (Stefano Manni)
Date: Thu, 20 Feb 2025 18:39:55 +0100
Subject: [PATCH 1/2] imx-bbu-nand-fcb: do not use hardcoded devicefile
Message-ID: <J2TZRS.AUAITN7RW0RJ1@gmail.com>

Device file was hardcoded to "nand0.barebox".
This patch harmonize the signature of

imx6_bbu_nand_register_handler()
imx7_bbu_nand_register_handler()
imx28_bbu_nand_register_handler()

with the other bbu register functions in order to take
the devicefile as parameter.

Signed-off-by: Stefano Manni <stefano.manni at gmail.com>
---
 common/imx-bbu-nand-fcb.c | 23 ++++++++++++++++-------
 include/bbu.h | 18 ++++++++++++------
 2 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index d0261140cf..0d17a7bf6a 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -1219,6 +1219,7 @@ static int imx_bbu_nand_update(struct bbu_handler 
*handler, struct bbu_data *dat
  int used = 0;
  int fw_orig_len = 0;
  int used_refresh = 0, unused_refresh = 0;
+ const char *devname = handler->devicefile;

  if (data->image) {
   filetype = file_detect_type(data->image, data->len);
@@ -1230,7 +1231,12 @@ static int imx_bbu_nand_update(struct 
bbu_handler *handler, struct bbu_data *dat
    return -EINVAL;
  }

- bcb_cdev = cdev_by_name(handler->devicefile);
+ /* Support both boot /dev/nand0.barebox and boot nand0.barebox */
+ devname += str_has_prefix(devname, "/dev/");
+
+ device_detect_by_name(devname);
+
+ bcb_cdev = cdev_by_name(devname);
  if (!bcb_cdev) {
   pr_err("%s: No FCB device!\n", __func__);
   return -ENODEV;
@@ -1432,7 +1438,8 @@ static void imx6_fcb_create(struct 
imx_nand_fcb_bbu_handler *imx_handler,
  fcb->MetadataBytes = 10;
 }

-int imx6_bbu_nand_register_handler(const char *name, unsigned long 
flags)
+int imx6_bbu_nand_register_handler(const char *name,
+ const char *devicefile, unsigned long flags)
 {
  struct imx_nand_fcb_bbu_handler *imx_handler;
  struct bbu_handler *handler;
@@ -1451,7 +1458,7 @@ int imx6_bbu_nand_register_handler(const char 
*name, unsigned long flags)
  }

  handler = &imx_handler->handler;
- handler->devicefile = "nand0.barebox";
+ handler->devicefile = devicefile;
  handler->name = name;
  handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
  handler->handler = imx_bbu_nand_update;
@@ -1526,7 +1533,8 @@ static void imx28_fcb_create(struct 
imx_nand_fcb_bbu_handler *imx_handler,
  fcb->EraseThreshold = readl(bch_regs + BCH_MODE);
 }

-int imx28_bbu_nand_register_handler(const char *name, unsigned long 
flags)
+int imx28_bbu_nand_register_handler(const char *name,
+ const char *devicefile, unsigned long flags)
 {
  struct imx_nand_fcb_bbu_handler *imx_handler;
  struct bbu_handler *handler;
@@ -1540,7 +1548,7 @@ int imx28_bbu_nand_register_handler(const char 
*name, unsigned long flags)
  imx_handler->filetype = filetype_mxs_bootstream;

  handler = &imx_handler->handler;
- handler->devicefile = "nand0.barebox";
+ handler->devicefile = devicefile;
  handler->name = name;
  handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
  handler->handler = imx_bbu_nand_update;
@@ -1599,7 +1607,8 @@ static int imx7_fcb_write(struct mtd_info *mtd, 
int block, struct fcb_block *fcb
  return mxs_nand_write_fcb_bch62(block, fcb, sizeof(*fcb));
 }

-int imx7_bbu_nand_register_handler(const char *name, unsigned long 
flags)
+int imx7_bbu_nand_register_handler(const char *name
+ const char *devicefile, unsigned long flags)
 {
  struct imx_nand_fcb_bbu_handler *imx_handler;
  struct bbu_handler *handler;
@@ -1612,7 +1621,7 @@ int imx7_bbu_nand_register_handler(const char 
*name, unsigned long flags)
  imx_handler->filetype = filetype_arm_barebox;

  handler = &imx_handler->handler;
- handler->devicefile = "nand0.barebox";
+ handler->devicefile = devicefile;
  handler->name = name;
  handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
  handler->handler = imx_bbu_nand_update;
diff --git a/include/bbu.h b/include/bbu.h
index 5105d2ac70..087d3ee827 100644
--- a/include/bbu.h
+++ b/include/bbu.h
@@ -98,19 +98,25 @@ static inline int 
bbu_mmcboot_register_handler(const char *name,
 #endif

 #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB)
-int imx6_bbu_nand_register_handler(const char *name, unsigned long 
flags);
-int imx7_bbu_nand_register_handler(const char *name, unsigned long 
flags);
-int imx28_bbu_nand_register_handler(const char *name, unsigned long 
flags);
+int imx6_bbu_nand_register_handler(const char *name, const char 
*devicefile, unsigned long flags);
+int imx7_bbu_nand_register_handler(const char *name, const char 
*devicefile, unsigned long flags);
+int imx28_bbu_nand_register_handler(const char *name, const char 
*devicefile, unsigned long flags);
 #else
-static inline int imx6_bbu_nand_register_handler(const char *name, 
unsigned long flags)
+static inline int imx6_bbu_nand_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
 {
  return -ENOSYS;
 }
-static inline int imx7_bbu_nand_register_handler(const char *name, 
unsigned long flags)
+static inline int imx7_bbu_nand_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
 {
  return -ENOSYS;
 }
-static inline int imx28_bbu_nand_register_handler(const char *name, 
unsigned long flags)
+static inline int imx28_bbu_nand_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
 {
  return -ENOSYS;
 }
-- 
2.25.1





From stefano.manni at gmail.com  Thu Feb 20 09:39:56 2025
From: stefano.manni at gmail.com (Stefano Manni)
Date: Thu, 20 Feb 2025 18:39:56 +0100
Subject: [PATCH 2/2] ARM: boards: fix nand bbu_handler device paths
Message-ID: <K2TZRS.I55GET28HSJS3@gmail.com>

The bbu handler for nand now takes the device
path as parameter and no longer use the hardcoded
value.
Make the change accordingly to all the boards
using it.

Signed-off-by: Stefano Manni <stefano.manni at gmail.com>
---
 arch/arm/boards/digi-ccimx6ulsom/board.c | 3 ++-
 arch/arm/boards/gateworks-ventana/board.c | 4 +++-
 arch/arm/boards/karo-tx6x/board.c | 3 ++-
 arch/arm/boards/phytec-som-imx6/board.c | 4 +++-
 4 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boards/digi-ccimx6ulsom/board.c 
b/arch/arm/boards/digi-ccimx6ulsom/board.c
index ef6828c02c..9765c65839 100644
--- a/arch/arm/boards/digi-ccimx6ulsom/board.c
+++ b/arch/arm/boards/digi-ccimx6ulsom/board.c
@@ -11,7 +11,8 @@ static int digi_ccimx6ulsbcpro_device_init(void)
  if (!of_machine_is_compatible("digi,ccimx6ulsbcpro"))
   return 0;

- imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+ imx6_bbu_nand_register_handler("nand", "/dev/nand0.barebox",
+ BBU_HANDLER_FLAG_DEFAULT);

  barebox_set_hostname("ccimx6ulsbcpro");

diff --git a/arch/arm/boards/gateworks-ventana/board.c 
b/arch/arm/boards/gateworks-ventana/board.c
index aa2137a971..9c0012b359 100644
--- a/arch/arm/boards/gateworks-ventana/board.c
+++ b/arch/arm/boards/gateworks-ventana/board.c
@@ -72,7 +72,9 @@ static int gw54xx_devices_init(void)
  if (gsc_get_rev(&client) < 'E')
   of_register_fixup(gw54xx_wdog_of_fixup, NULL);

- imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+ imx6_bbu_nand_register_handler("nand",
+ "/dev/nand0.barebox",
+ BBU_HANDLER_FLAG_DEFAULT);

  barebox_set_hostname("gw54xx");

diff --git a/arch/arm/boards/karo-tx6x/board.c 
b/arch/arm/boards/karo-tx6x/board.c
index f964ddefd1..1e14a75272 100644
--- a/arch/arm/boards/karo-tx6x/board.c
+++ b/arch/arm/boards/karo-tx6x/board.c
@@ -110,7 +110,8 @@ static int tx6x_devices_init(void)
   * this board has eMMC or NAND.
   */
  if (sbmr1 & (1 << 7)) {
- imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+ imx6_bbu_nand_register_handler("nand", "/dev/nand0.barebox",
+ BBU_HANDLER_FLAG_DEFAULT);
   of_device_enable_and_register_by_name("environment-nand");
   of_device_enable_and_register_by_alias("nand");
  } else {
diff --git a/arch/arm/boards/phytec-som-imx6/board.c 
b/arch/arm/boards/phytec-som-imx6/board.c
index 2db3fa1db8..7e6f61bc36 100644
--- a/arch/arm/boards/phytec-som-imx6/board.c
+++ b/arch/arm/boards/phytec-som-imx6/board.c
@@ -259,7 +259,9 @@ static int physom_imx6_probe(struct device *dev)
   imx6_bbu_internal_mmcboot_register_handler("mmc1-boot",
       "mmc1", 0);
  } else {
- imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+ imx6_bbu_nand_register_handler("nand",
+ "/dev/nand0.barebox",
+ BBU_HANDLER_FLAG_DEFAULT);
  }

  defaultenv_append_directory(defaultenv_physom_imx6);
-- 
2.25.1





From a.fatoum at pengutronix.de  Thu Feb 20 09:45:18 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 18:45:18 +0100
Subject: [PATCH] boot: fix systemd watchdog command line argument
In-Reply-To: <1058511f-b54e-44be-b267-dce2b1fd048a@pengutronix.de>
References: <20250220091743.3489127-1-s.hauer@pengutronix.de>
 <1058511f-b54e-44be-b267-dce2b1fd048a@pengutronix.de>
Message-ID: <98c9c867-0985-4c83-8e76-b16fff5cafd6@pengutronix.de>

On 20.02.25 13:06, Ahmad Fatoum wrote:
> On 20.02.25 10:17, Sascha Hauer wrote:
>> The kernel command line option to specify the watchdog to use is
>> "systemd.watchdog_device" as specified in [1], not
>> "systemd.watchdog-device"
>>
>> [1] https://www.freedesktop.org/software/systemd/man/latest/kernel-command-line.html#systemd.watchdog_sec=
>>
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> 
> Please also include the typo fix in the common/Kconfig help text for
> CONFIG_SYSTEMD_OF_WATCHDOG.
> 
> With that squashed:
> 
> Reviewed-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> 
> I could swear I have tested this with two watchdogs back then...

Turns out, you can replace an underscore with a dash in all systemd
kernel options and they will behave identically:
https://github.com/systemd/systemd/pull/36453#discussion_r1963693274

> Anyways, I have submitted a fix to the systemd documentation here:
> https://github.com/systemd/systemd/pull/36453

And it's merged. It's a good idea for barebox to be aligned with the
current systemd documentation, but it's reassuring to learn that
this was not buggy to begin with. :)

Cheers,
Ahmad

> 
> Thanks,
> Ahmad
> 
> 
>> ---
>>  common/oftree.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/common/oftree.c b/common/oftree.c
>> index 4afe955719..2ebde791c7 100644
>> --- a/common/oftree.c
>> +++ b/common/oftree.c
>> @@ -172,7 +172,7 @@ static void watchdog_build_bootargs(struct watchdog *watchdog, struct device_nod
>>  	if (alias_id < 0)
>>  		return;
>>  
>> -	buf = basprintf("systemd.watchdog-device=/dev/watchdog%d", alias_id);
>> +	buf = basprintf("systemd.watchdog_device=/dev/watchdog%d", alias_id);
>>  	if (!buf)
>>  		return;
>>  
> 
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From a.fatoum at pengutronix.de  Thu Feb 20 12:27:23 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 21:27:23 +0100
Subject: [PATCH] sandbox: configs: disable CONFIG_NET_NETCONSOLE in sandbox_defconfig
Message-ID: <20250220202723.3349623-1-a.fatoum@pengutronix.de>

Sandbox users can register extra consoles via command-line arguments, so
it makes sense to have CONFIG_CONSOLE_ACTIVATE_ALL enabled.

This also means that users get an ugly error message by default:

  ERROR: netconsole: port not set

Avoid this by disabling the netconsole support in the defconfig.
Users willing to configure it can always enable it again.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/sandbox/configs/sandbox_defconfig | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/sandbox/configs/sandbox_defconfig b/arch/sandbox/configs/sandbox_defconfig
index a5e0f72c6340..251af8d0ef31 100644
--- a/arch/sandbox/configs/sandbox_defconfig
+++ b/arch/sandbox/configs/sandbox_defconfig
@@ -94,7 +94,6 @@ CONFIG_CMD_SPD_DECODE=y
 CONFIG_CMD_SEED=y
 CONFIG_NET=y
 CONFIG_NET_NFS=y
-CONFIG_NET_NETCONSOLE=y
 CONFIG_NET_SNTP=y
 CONFIG_NET_FASTBOOT=y
 CONFIG_FEATURE_CONTROLLER=y
-- 
2.39.5



From a.fatoum at pengutronix.de  Thu Feb 20 12:30:30 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 21:30:30 +0100
Subject: [PATCH 4/6] sandbox: libc_malloc: fail allocations exceeding MALLOC_MAX_SIZE
In-Reply-To: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
References: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
Message-ID: <20250220203032.3350247-4-a.fatoum@pengutronix.de>

The libc allocator is a bit unpredictable, because overcommit can
mean that big allocations succeed initially, only to OOM later.

Let's thus enforce a maximum allocation limit on the barebox side in
alignment with the bare metal allocators.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 arch/sandbox/os/libc_malloc.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/arch/sandbox/os/libc_malloc.c b/arch/sandbox/os/libc_malloc.c
index e34156cd49e7..ac97fc37eee5 100644
--- a/arch/sandbox/os/libc_malloc.c
+++ b/arch/sandbox/os/libc_malloc.c
@@ -7,6 +7,8 @@
 #include <malloc.h>
 
 #define BAREBOX_ENOMEM 12
+#define BAREBOX_MALLOC_MAX_SIZE 0x40000000
+
 extern int barebox_errno;
 
 void barebox_malloc_stats(void)
@@ -15,7 +17,10 @@ void barebox_malloc_stats(void)
 
 void *barebox_memalign(size_t alignment, size_t bytes)
 {
-	void *mem = memalign(alignment, bytes);
+	void *mem = NULL;
+
+	if (alignment <= BAREBOX_MALLOC_MAX_SIZE && bytes <= BAREBOX_MALLOC_MAX_SIZE)
+		mem = memalign(alignment, bytes);
 	if (!mem)
 		barebox_errno = BAREBOX_ENOMEM;
 
@@ -25,7 +30,10 @@ void *barebox_memalign(size_t alignment, size_t bytes)
 void *barebox_malloc(size_t size)
 {
 
-	void *mem = malloc(size);
+	void *mem = NULL;
+
+	if (size <= BAREBOX_MALLOC_MAX_SIZE)
+		mem = malloc(size);
 	if (!mem)
 		barebox_errno = BAREBOX_ENOMEM;
 
@@ -44,7 +52,10 @@ void barebox_free(void *ptr)
 
 void *barebox_realloc(void *ptr, size_t size)
 {
-	void *mem = realloc(ptr, size);
+	void *mem = NULL;
+
+	if (size <= BAREBOX_MALLOC_MAX_SIZE)
+		mem = realloc(ptr, size);
 	if (!mem)
 		barebox_errno = BAREBOX_ENOMEM;
 
@@ -53,7 +64,12 @@ void *barebox_realloc(void *ptr, size_t size)
 
 void *barebox_calloc(size_t n, size_t elem_size)
 {
-	void *mem = calloc(n, elem_size);
+	size_t product;
+	void *mem = NULL;
+
+	if (!__builtin_add_overflow(n, elem_size, &product) &&
+	    product <= BAREBOX_MALLOC_MAX_SIZE)
+		mem = calloc(n, elem_size);
 	if (!mem)
 		barebox_errno = BAREBOX_ENOMEM;
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Thu Feb 20 12:30:31 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 21:30:31 +0100
Subject: [PATCH 5/6] dummy_malloc: fail allocations exceeding MALLOC_MAX_SIZE
In-Reply-To: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
References: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
Message-ID: <20250220203032.3350247-5-a.fatoum@pengutronix.de>

For uniformity with the proper allocators, let's observe the same
maximum allocation size they do.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/dummy_malloc.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/common/dummy_malloc.c b/common/dummy_malloc.c
index 140ba314272a..4973f35650ab 100644
--- a/common/dummy_malloc.c
+++ b/common/dummy_malloc.c
@@ -11,8 +11,10 @@ void malloc_stats(void)
 
 void *memalign(size_t alignment, size_t bytes)
 {
-	void *mem = sbrk(bytes + alignment);
+	void *mem = NULL;
 
+	if (alignment <= MALLOC_MAX_SIZE && bytes <= MALLOC_MAX_SIZE)
+		mem = sbrk(bytes + alignment);
 	if (!mem) {
 		errno = ENOMEM;
 		return NULL;
-- 
2.39.5



From a.fatoum at pengutronix.de  Thu Feb 20 12:30:27 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 21:30:27 +0100
Subject: [PATCH 1/6] malloc: define a maximum malloc size
Message-ID: <20250220203032.3350247-1-a.fatoum@pengutronix.de>

TLSF and dlmalloc each already enforce a maximum allocation size.

Let's define SZ_1G as common maximum allocation size in preparation
for aligning all allocators to observe it.

The intention is to make code easier to reason about and as extra
hardening against possible, yet undiscovered, allocator bugs.

Suggested-by: Richard Weinberger <richard at nod.at>
Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 include/malloc.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/malloc.h b/include/malloc.h
index 7bee03dab236..c38726342c08 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -5,6 +5,9 @@
 #include <linux/compiler.h>
 #include <types.h>
 
+#define MALLOC_SHIFT_MAX	30
+#define MALLOC_MAX_SIZE		(1UL << MALLOC_SHIFT_MAX)
+
 #if IN_PROPER
 void *malloc(size_t) __alloc_size(1);
 size_t malloc_usable_size(void *);
-- 
2.39.5



From a.fatoum at pengutronix.de  Thu Feb 20 12:30:32 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 21:30:32 +0100
Subject: [PATCH 6/6] test: self: malloc: adapt to addition of MALLOC_MAX_SIZE
In-Reply-To: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
References: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
Message-ID: <20250220203032.3350247-6-a.fatoum@pengutronix.de>

Now that we enforce a maximum allocation size, adapt the tests to
account for this.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 test/self/malloc.c | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/test/self/malloc.c b/test/self/malloc.c
index 0feec810185f..79a32b5d97c7 100644
--- a/test/self/malloc.c
+++ b/test/self/malloc.c
@@ -84,16 +84,17 @@ static void test_malloc(void)
 	p = expect_alloc_ok(malloc(1));
 	free(p);
 
-	if (mem_malloc_size) {
-		tmp = expect_alloc_fail(malloc(RELOC_HIDE(SIZE_MAX, 0)));
-		free(tmp);
+	p = expect_alloc_fail(malloc(RELOC_HIDE(SIZE_MAX, 0)));
+	free(p);
 
-		if (0xf0000000 > mem_malloc_size) {
-			tmp = expect_alloc_fail(malloc(RELOC_HIDE(0xf0000000, 0)));
-			free(tmp);
-		}
+	p = expect_alloc_fail(malloc(RELOC_HIDE(MALLOC_MAX_SIZE, 1)));
+	free(p);
+
+	if (mem_malloc_size) {
+		tmp = expect_alloc_fail(malloc(RELOC_HIDE(MALLOC_MAX_SIZE, -1)));
+		free(tmp);
 	} else {
-		skipped_tests += 2;
+		skipped_tests++;
 	}
 
 	free(realloc(NULL, 1));
@@ -110,16 +111,10 @@ static void test_malloc(void)
 		tmp = expect_alloc_fail(realloc(p, mem_malloc_size));
 		free(tmp);
 
-		if (0xf0000000 > mem_malloc_size) {
-			tmp = expect_alloc_fail(realloc(p, RELOC_HIDE(0xf0000000, 0)));
-			free(tmp);
-		}
-
-		tmp = expect_alloc_fail(realloc(p, RELOC_HIDE(SIZE_MAX, 0)));
+		tmp = expect_alloc_fail(realloc(p, RELOC_HIDE(MALLOC_MAX_SIZE, -1)));
 		free(tmp);
-
 	} else {
-		skipped_tests += 3;
+		skipped_tests += 2;
 	}
 
 	free(p);
-- 
2.39.5



From a.fatoum at pengutronix.de  Thu Feb 20 12:30:28 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 21:30:28 +0100
Subject: [PATCH 2/6] tlsf: fail allocations exceeding MALLOC_MAX_SIZE
In-Reply-To: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
References: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
Message-ID: <20250220203032.3350247-2-a.fatoum@pengutronix.de>

TLSF already enforces a maximum allocation size of SZ_1G on 32-bit systems
and a size of SZ_4G on 64-bit systems. There's no need to differentiate
between the two, let's settle on SZ_1G for both by unconditionally using
the newly introduced MALLOC_SHIFT_MAX macro.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/tlsf.c | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/common/tlsf.c b/common/tlsf.c
index 4cd90e150de2..146f1b7ebe81 100644
--- a/common/tlsf.c
+++ b/common/tlsf.c
@@ -46,15 +46,7 @@ enum tlsf_private
 	** blocks below that size into the 0th first-level list.
 	*/
 
-#if defined (TLSF_64BIT)
-	/*
-	** TODO: We can increase this to support larger sizes, at the expense
-	** of more overhead in the TLSF structure.
-	*/
-	FL_INDEX_MAX = 32,
-#else
-	FL_INDEX_MAX = 30,
-#endif
+	FL_INDEX_MAX = MALLOC_SHIFT_MAX,
 	SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2),
 	FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2),
 	FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1),
@@ -824,15 +816,9 @@ pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes)
 
 	if (pool_bytes < block_size_min || pool_bytes > block_size_max)
 	{
-#if defined (TLSF_64BIT)
-		printf("tlsf_add_pool: Memory size must be between 0x%x and 0x%x00 bytes.\n",
-			(unsigned int)(pool_overhead + block_size_min),
-			(unsigned int)((pool_overhead + block_size_max) / 256));
-#else
 		printf("tlsf_add_pool: Memory size must be between %u and %u bytes.\n",
 			(unsigned int)(pool_overhead + block_size_min),
 			(unsigned int)(pool_overhead + block_size_max));
-#endif
 		return 0;
 	}
 
-- 
2.39.5



From a.fatoum at pengutronix.de  Thu Feb 20 12:30:29 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Thu, 20 Feb 2025 21:30:29 +0100
Subject: [PATCH 3/6] dlmalloc: fail allocations exceeding MALLOC_MAX_SIZE
In-Reply-To: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
References: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
Message-ID: <20250220203032.3350247-3-a.fatoum@pengutronix.de>

We already enforce a maximum allocation size of LONG_MAX in dlmalloc,
but this is larger than any reasonable allocation size we would have.

Let's reduce it to the new common maximum of SZ_1G.

While at it, enforce this limit for all size and alignment
parameters.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/dlmalloc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index 731c46b584b0..2b5723e127c4 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -1162,7 +1162,7 @@ void *dlmalloc(size_t bytes)
 
 	INTERNAL_SIZE_T nb;
 
-	if ((long) bytes < 0) {
+	if (bytes > MALLOC_MAX_SIZE) {
 		errno = ENOMEM;
 		return NULL;
 	}
@@ -1499,7 +1499,7 @@ void *dlrealloc(void *oldmem, size_t bytes)
 	}
 #endif
 
-	if ((long)bytes < 0) {
+	if (bytes > MALLOC_MAX_SIZE) {
 		errno = ENOMEM;
 		return NULL;
 	}
@@ -1668,7 +1668,7 @@ void *dlmemalign(size_t alignment, size_t bytes)
 	mchunkptr remainder;	/* spare room at end to split off */
 	long remainder_size;	/* its size */
 
-	if ((long) bytes < 0) {
+	if (bytes > MALLOC_MAX_SIZE || alignment > MALLOC_MAX_SIZE) {
 		errno = ENOMEM;
 		return NULL;
 	}
@@ -1753,7 +1753,7 @@ void *dlcalloc(size_t n, size_t elem_size)
 	mchunkptr oldtop = top;
 	INTERNAL_SIZE_T oldtopsize = chunksize(top);
 
-	if ((long)n < 0) {
+	if (sz > MALLOC_MAX_SIZE) {
 		errno = ENOMEM;
 		return NULL;
 	}
-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 20 23:33:53 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 08:33:53 +0100
Subject: [PATCH 0/5] Filesystem memory corruption fixes
In-Reply-To: <20250219141844.1912413-1-s.hauer@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
Message-ID: <174012323334.2354255.16758545638294107895.b4-ty@pengutronix.de>


On Wed, 19 Feb 2025 15:18:39 +0100, Sascha Hauer wrote:
> These are some fixes for memory corruptions that can occur on corrupted
> or manipulated filesystems.
> 
> In case you use one of the affected filesystems in a secure boot chain
> you should apply these patches.
> 
> Normally you shouldn't use a barebox filesystem in a secure boot chain,
> but instead use FIT images on a raw partition. We never made this explicit
> though. Ahmad has done this recently:
> 
> [...]

Applied, thanks!

[1/5] CVE-2025-26722: fs: squashfs: Ensure positive inode length
      https://git.pengutronix.de/cgit/barebox/commit/?id=6281a871e2c6 (link may not be stable)
[2/5] CVE-2025-26724: fs: cramfs: fix malloc(size + constant) buffer overflow issues
      https://git.pengutronix.de/cgit/barebox/commit/?id=f86e528c8fba (link may not be stable)
[3/5] CVE-2025-26723: fs: ext4: fix malloc(size + constant) buffer overflow issues
      https://git.pengutronix.de/cgit/barebox/commit/?id=51eea5c16fd2 (link may not be stable)
[4/5] CVE-2025-26725: fs: jffs2: fix malloc(size + constant) buffer overflow issues
      https://git.pengutronix.de/cgit/barebox/commit/?id=e7397340359d (link may not be stable)
[5/5] CVE-2025-26721: fs: pstore: fix malloc(size + constant) buffer overflow issues
      https://git.pengutronix.de/cgit/barebox/commit/?id=7563f5722dfd (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 21 02:22:19 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 11:22:19 +0100
Subject: [PATCH master 1/2] scripts: define _GNU_SOURCE for every user
 tool build
In-Reply-To: <20250220064612.865757-1-a.fatoum@pengutronix.de>
References: <20250220064612.865757-1-a.fatoum@pengutronix.de>
Message-ID: <174013333913.1372990.11745460185790676726.b4-ty@pengutronix.de>


On Thu, 20 Feb 2025 07:46:11 +0100, Ahmad Fatoum wrote:
> Defining _GNU_SOURCE via userccflags (for target tools) and KBUILD_HOSTCFLAGS
> (for host tools) works, but needs to be repeated in subdirectories like i.MX
> as well. As we make ample use of the asprintf GNU extension anyway, let's just
> define it in the top-level makefile for build of all user code.
> 
> 

Applied, thanks!

[1/2] scripts: define _GNU_SOURCE for every user tool build
      https://git.pengutronix.de/cgit/barebox/commit/?id=6b0121ddc44b (link may not be stable)
[2/2] scripts: common.h: define loff_t on musl
      https://git.pengutronix.de/cgit/barebox/commit/?id=f0c67c9477c9 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 21 02:38:26 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 11:38:26 +0100
Subject: [PATCH 1/2] imx-bbu-nand-fcb: do not use hardcoded devicefile
In-Reply-To: <J2TZRS.AUAITN7RW0RJ1@gmail.com>
References: <J2TZRS.AUAITN7RW0RJ1@gmail.com>
Message-ID: <Z7hXohthRBbG9XIf@pengutronix.de>

Hi Stefano,

The patch is mangled. Could you send it using git send-email? Using a
web endpoint for b4 would be another possibility if git send-email
doesn't work for you.

The two patches should be sent as one to avoid intermediate breakage
between the patches.

Regards
  Sascha

On Thu, Feb 20, 2025 at 06:39:55PM +0100, Stefano Manni wrote:
> Device file was hardcoded to "nand0.barebox".
> This patch harmonize the signature of
> 
> imx6_bbu_nand_register_handler()
> imx7_bbu_nand_register_handler()
> imx28_bbu_nand_register_handler()
> 
> with the other bbu register functions in order to take
> the devicefile as parameter.
> 
> Signed-off-by: Stefano Manni <stefano.manni at gmail.com>
> ---
> common/imx-bbu-nand-fcb.c | 23 ++++++++++++++++-------
> include/bbu.h | 18 ++++++++++++------
> 2 files changed, 28 insertions(+), 13 deletions(-)
> 
> diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
> index d0261140cf..0d17a7bf6a 100644
> --- a/common/imx-bbu-nand-fcb.c
> +++ b/common/imx-bbu-nand-fcb.c
> @@ -1219,6 +1219,7 @@ static int imx_bbu_nand_update(struct bbu_handler
> *handler, struct bbu_data *dat
>  int used = 0;
>  int fw_orig_len = 0;
>  int used_refresh = 0, unused_refresh = 0;
> + const char *devname = handler->devicefile;
> 
>  if (data->image) {
>   filetype = file_detect_type(data->image, data->len);
> @@ -1230,7 +1231,12 @@ static int imx_bbu_nand_update(struct bbu_handler
> *handler, struct bbu_data *dat
>    return -EINVAL;
>  }
> 
> - bcb_cdev = cdev_by_name(handler->devicefile);
> + /* Support both boot /dev/nand0.barebox and boot nand0.barebox */
> + devname += str_has_prefix(devname, "/dev/");
> +
> + device_detect_by_name(devname);
> +
> + bcb_cdev = cdev_by_name(devname);
>  if (!bcb_cdev) {
>   pr_err("%s: No FCB device!\n", __func__);
>   return -ENODEV;
> @@ -1432,7 +1438,8 @@ static void imx6_fcb_create(struct
> imx_nand_fcb_bbu_handler *imx_handler,
>  fcb->MetadataBytes = 10;
> }
> 
> -int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
> +int imx6_bbu_nand_register_handler(const char *name,
> + const char *devicefile, unsigned long flags)
> {
>  struct imx_nand_fcb_bbu_handler *imx_handler;
>  struct bbu_handler *handler;
> @@ -1451,7 +1458,7 @@ int imx6_bbu_nand_register_handler(const char *name,
> unsigned long flags)
>  }
> 
>  handler = &imx_handler->handler;
> - handler->devicefile = "nand0.barebox";
> + handler->devicefile = devicefile;
>  handler->name = name;
>  handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>  handler->handler = imx_bbu_nand_update;
> @@ -1526,7 +1533,8 @@ static void imx28_fcb_create(struct
> imx_nand_fcb_bbu_handler *imx_handler,
>  fcb->EraseThreshold = readl(bch_regs + BCH_MODE);
> }
> 
> -int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
> +int imx28_bbu_nand_register_handler(const char *name,
> + const char *devicefile, unsigned long flags)
> {
>  struct imx_nand_fcb_bbu_handler *imx_handler;
>  struct bbu_handler *handler;
> @@ -1540,7 +1548,7 @@ int imx28_bbu_nand_register_handler(const char *name,
> unsigned long flags)
>  imx_handler->filetype = filetype_mxs_bootstream;
> 
>  handler = &imx_handler->handler;
> - handler->devicefile = "nand0.barebox";
> + handler->devicefile = devicefile;
>  handler->name = name;
>  handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>  handler->handler = imx_bbu_nand_update;
> @@ -1599,7 +1607,8 @@ static int imx7_fcb_write(struct mtd_info *mtd, int
> block, struct fcb_block *fcb
>  return mxs_nand_write_fcb_bch62(block, fcb, sizeof(*fcb));
> }
> 
> -int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
> +int imx7_bbu_nand_register_handler(const char *name
> + const char *devicefile, unsigned long flags)
> {
>  struct imx_nand_fcb_bbu_handler *imx_handler;
>  struct bbu_handler *handler;
> @@ -1612,7 +1621,7 @@ int imx7_bbu_nand_register_handler(const char *name,
> unsigned long flags)
>  imx_handler->filetype = filetype_arm_barebox;
> 
>  handler = &imx_handler->handler;
> - handler->devicefile = "nand0.barebox";
> + handler->devicefile = devicefile;
>  handler->name = name;
>  handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>  handler->handler = imx_bbu_nand_update;
> diff --git a/include/bbu.h b/include/bbu.h
> index 5105d2ac70..087d3ee827 100644
> --- a/include/bbu.h
> +++ b/include/bbu.h
> @@ -98,19 +98,25 @@ static inline int bbu_mmcboot_register_handler(const
> char *name,
> #endif
> 
> #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB)
> -int imx6_bbu_nand_register_handler(const char *name, unsigned long flags);
> -int imx7_bbu_nand_register_handler(const char *name, unsigned long flags);
> -int imx28_bbu_nand_register_handler(const char *name, unsigned long flags);
> +int imx6_bbu_nand_register_handler(const char *name, const char
> *devicefile, unsigned long flags);
> +int imx7_bbu_nand_register_handler(const char *name, const char
> *devicefile, unsigned long flags);
> +int imx28_bbu_nand_register_handler(const char *name, const char
> *devicefile, unsigned long flags);
> #else
> -static inline int imx6_bbu_nand_register_handler(const char *name, unsigned
> long flags)
> +static inline int imx6_bbu_nand_register_handler(const char *name,
> + const char *devicefile,
> + unsigned long flags)
> {
>  return -ENOSYS;
> }
> -static inline int imx7_bbu_nand_register_handler(const char *name, unsigned
> long flags)
> +static inline int imx7_bbu_nand_register_handler(const char *name,
> + const char *devicefile,
> + unsigned long flags)
> {
>  return -ENOSYS;
> }
> -static inline int imx28_bbu_nand_register_handler(const char *name,
> unsigned long flags)
> +static inline int imx28_bbu_nand_register_handler(const char *name,
> + const char *devicefile,
> + unsigned long flags)
> {
>  return -ENOSYS;
> }
> -- 
> 2.25.1
> 
> 
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From martin.l.wege at gmail.com  Fri Feb 21 03:54:00 2025
From: martin.l.wege at gmail.com (Martin Wege)
Date: Fri, 21 Feb 2025 12:54:00 +0100
Subject: Mount NFSv4.2 filesystem in barebox?
In-Reply-To: <Z6yxUVTp0vGWqs7Q@pengutronix.de>
References: <CANH4o6Njc3uHE=NbasRJrRr0W5B89R8MTM_BwGwab7t5fNWuaA@mail.gmail.com>
 <Z6yxUVTp0vGWqs7Q@pengutronix.de>
Message-ID: <CANH4o6NRK2+ekNe_LrUaoAi8PVbi-MC3hWerv4g6F-WmXmyK5w@mail.gmail.com>

On Wed, Feb 12, 2025 at 3:33?PM Sascha Hauer <s.hauer at pengutronix.de> wrote:
>
> Hi Martin,
>
> On Tue, Feb 11, 2025 at 01:56:58PM +0100, Martin Wege wrote:
> > Hello!
> >
> > Does barebox have support to mount a NFSv.2 filesystem?
>
> No, not yet. For NFSv4 we would first need TCP support. While we started
> to integrate a TCP stack we are not there yet unfortunately.

How long is this going to take?

https://github.com/sahlberg/libnfs has NFSv4.1 support, just remove
the NFSv3,v2 bits, both are considered obsolete by the IETF.

Thanks,
Martin


From s.hauer at pengutronix.de  Fri Feb 21 04:17:18 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 13:17:18 +0100
Subject: [PATCH] sandbox: configs: disable CONFIG_NET_NETCONSOLE in
 sandbox_defconfig
In-Reply-To: <20250220202723.3349623-1-a.fatoum@pengutronix.de>
References: <20250220202723.3349623-1-a.fatoum@pengutronix.de>
Message-ID: <174014023842.1419851.1391645662739523261.b4-ty@pengutronix.de>


On Thu, 20 Feb 2025 21:27:23 +0100, Ahmad Fatoum wrote:
> Sandbox users can register extra consoles via command-line arguments, so
> it makes sense to have CONFIG_CONSOLE_ACTIVATE_ALL enabled.
> 
> This also means that users get an ugly error message by default:
> 
>   ERROR: netconsole: port not set
> 
> [...]

Applied, thanks!

[1/1] sandbox: configs: disable CONFIG_NET_NETCONSOLE in sandbox_defconfig
      https://git.pengutronix.de/cgit/barebox/commit/?id=20876a9ad601 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 21 04:20:33 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 13:20:33 +0100
Subject: [PATCH 1/6] malloc: define a maximum malloc size
In-Reply-To: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
References: <20250220203032.3350247-1-a.fatoum@pengutronix.de>
Message-ID: <174014043388.1478951.219003102869539280.b4-ty@pengutronix.de>


On Thu, 20 Feb 2025 21:30:27 +0100, Ahmad Fatoum wrote:
> TLSF and dlmalloc each already enforce a maximum allocation size.
> 
> Let's define SZ_1G as common maximum allocation size in preparation
> for aligning all allocators to observe it.
> 
> The intention is to make code easier to reason about and as extra
> hardening against possible, yet undiscovered, allocator bugs.
> 
> [...]

Applied, thanks!

[1/6] malloc: define a maximum malloc size
      https://git.pengutronix.de/cgit/barebox/commit/?id=6279bd2d3a33 (link may not be stable)
[2/6] tlsf: fail allocations exceeding MALLOC_MAX_SIZE
      https://git.pengutronix.de/cgit/barebox/commit/?id=b5c4d87dfb62 (link may not be stable)
[3/6] dlmalloc: fail allocations exceeding MALLOC_MAX_SIZE
      https://git.pengutronix.de/cgit/barebox/commit/?id=122a8979fefb (link may not be stable)
[4/6] sandbox: libc_malloc: fail allocations exceeding MALLOC_MAX_SIZE
      https://git.pengutronix.de/cgit/barebox/commit/?id=8839004152f7 (link may not be stable)
[5/6] dummy_malloc: fail allocations exceeding MALLOC_MAX_SIZE
      https://git.pengutronix.de/cgit/barebox/commit/?id=8dcd7add5943 (link may not be stable)
[6/6] test: self: malloc: adapt to addition of MALLOC_MAX_SIZE
      https://git.pengutronix.de/cgit/barebox/commit/?id=cb77a6989e59 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 21 05:20:39 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 14:20:39 +0100
Subject: [PATCH] boot: fix systemd watchdog command line argument
In-Reply-To: <20250220091743.3489127-1-s.hauer@pengutronix.de>
References: <20250220091743.3489127-1-s.hauer@pengutronix.de>
Message-ID: <174014403930.2558999.4757744156276813508.b4-ty@pengutronix.de>


On Thu, 20 Feb 2025 10:17:43 +0100, Sascha Hauer wrote:
> The kernel command line option to specify the watchdog to use is
> "systemd.watchdog_device" as specified in [1], not
> "systemd.watchdog-device"
> 
> [1] https://www.freedesktop.org/software/systemd/man/latest/kernel-command-line.html#systemd.watchdog_sec=
> 
> 
> [...]

Applied, thanks!

[1/1] boot: fix systemd watchdog command line argument
      https://git.pengutronix.de/cgit/barebox/commit/?id=e11b5d8e5216 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 21 05:22:28 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 14:22:28 +0100
Subject: [PATCH] scripts: include: rename printk.h to printf.h
In-Reply-To: <ddc2507d-47e4-4cc0-98fe-ef85f34cbd98@pengutronix.de>
References: <20250205102549.27015-1-jmaselbas@zdiv.net>
 <173891686844.239361.18192152268825416500.b4-ty@pengutronix.de>
 <ddc2507d-47e4-4cc0-98fe-ef85f34cbd98@pengutronix.de>
Message-ID: <Z7h-FCovLsUCFvBE@pengutronix.de>

On Thu, Feb 20, 2025 at 07:38:47AM +0100, Ahmad Fatoum wrote:
> Hello Sascha,
> 
> On 07.02.25 09:27, Sascha Hauer wrote:
> > 
> > On Wed, 05 Feb 2025 11:25:49 +0100, Jules Maselbas wrote:
> >> The include scripts/include/asm-generic/bug.h relied on a printk.h
> >> compatible header which is located in the scripts/include/ and was
> >> not updated when printk.h was renamed to printf.h.
> >>
> >>
> > 
> > Applied, thanks!
> 
> Please apply this patch to master as the musl build is otherwise broken
> (glibc provides a <printf.h> header).

Did that

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Fri Feb 21 06:09:37 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 21 Feb 2025 15:09:37 +0100
Subject: barebox-2025.02.0
Message-ID: <Z7iJIYuoxZAja_F7@pengutronix.de>

Hi All,

barebox-2025.02.0 is out.

Topic of the month is security. This release has several memory overflow
fixes for different filesystems.  barebox has a history of being a great
bring-up and development tool for embedded hardware. While barebox can
be used in a secure boot environment, doing so requires many of the
features being disabled. So far we've never written that up explicitly,
but this changed recently. Have a look at [1], thanks Ahmad.

A common way to start barebox development on a new hardware often is to
start barebox from U-Boot. We now have a FIT image target for this
purpose.  the FIT image build target that can be activated with
CONFIG_BOARD_GENERIC_FIT. The resulting FIT image contains a 2nd stage
barebox binary along with all device trees that the barebox binary has
support for and can be started from U-Boot with the regular bootm
command.

The AM625 support continues to evolve. This release brings us 1st stage
support including DDR, clock and power domain drivers. Also with the
AM625-SK we have a new board supported.

For Rockchip we have a new board as well, the Pine64 PineTab 2.

As usual, for a detailed list of patches that went into this release see
below.

Have Fun!
 Sascha

[1] https://www.barebox.org/doc/latest/user/security.html


----------------------------------------------------------------
Ahmad Fatoum (71):
      bbremote: fix 'NoneType' object has no attribute 'encode'
      bbremote: decode bytes output of getenv and md on command line
      images: don't compare filesizes if file didn't change
      images: don't check for missing FW if file didn't change
      images: fix missing FORCE prerequisite
      images: don't prelink if input file didn't change
      images: don't compute size if input file didn't change
      bbu: fix bbu_register_std_file_update regression for file systems
      ARM: beaglebone: register bbu handlers for FAT partition
      of: fdt: reserve properties and nodes starting with $ for barebox use
      of: fdt: rename /memreserve special node to /$memreserve
      FIT: cache uncompressed data
      Documentation: devel: project-ideas: add SDL input support
      sandbox: add support for --loglevel option
      sandbox: add support for architecture-specific debug options
      sandbox: move CONFIG_ASAN to architecture Kconfig
      startup: set barebox_main in data section
      cdev: allow overriding partition overlap check
      commands: addpart: allow force creation of overlapping partition
      ARM: ep93xx: delete unused drivers
      compiler: drop intel compiler support
      fs: ramfs: drop unneeded indirection during unlink
      fs: squashfs: delete unreferenced source file
      fs: collect legacy file system operation in new struct fs_legacy_ops
      fs: return error pointer not NULL from cdev_mount_default
      commands: stat: fix size display for FILE_SIZE_STREAM
      commands: stat: print mode in octal if type unknown
      include: rename printk.h to printf.h
      vsprintf: document %JP format specifier as being barebox-specific
      driver: replace single info callbacks with stack
      virtio: allow inlining of trivial virtio_find_vqs function
      test: pytest: add support for --dump-dtb
      images: rename k3-am625-beagleplay extension from fit to itb
      sandbox: os: define referenced config symbols
      fs: derive file descriptor number by pointer arithmetic
      fs: drop ifdefs in linux/fs.h
      fs: retire FILE.in_use member
      fs: align FILE struct member names with upstream struct file
      fs: fat: rename f_size to f_len
      fs: replace FILE.size by f_inode.i_size
      fs: merge struct file and struct filep
      fs: retire FILE typdef
      fs: introduce hidden CONFIG_FS_WRITABLE option
      ARM: ep93xx: delete unused drivers
      ARM: dts: add device trees for the QEMU Virt machine
      treewide: collect the name of all board device trees
      kbuild: collect available device trees in dtbs-list
      scripts: add new scripts_dtc target
      kbuild: restrict dtbs target to enabled DTs by default
      kbuild: improve make help description
      kbuild: allow dependency on any file in images/
      arch: maintain Linux kernel and mkimage ARCH mapping in Kconfig
      arch: make BOARD_GENERIC_DT a user-selectable option across archs
      Import ARM Trusted Firmware fiptool utility
      MAKEALL: rename target in symbols to more appropiate defconfig
      MAKEALL: add support for building arbitrary targets
      ci: container: add python3-libfdt dependency for barebox.fit
      images: add barebox FIT image target
      dma: fix fixup warning for SoCs without /soc node
      kbuild: remove stale references to README
      scripts: define _GNU_SOURCE for all source files
      ARM: boards: colibri-imx6: make BBU setting independent of DT alias
      partitions: efi: update warning message after addition of parted command
      environment: autoprobe environment only when CONFIG_INSECURE=y
      SECURITY.md: add security policy
      ARM: zii-imx8mq-dev: fix warnings about missing #address-/#size-cells
      common: introduce CONFIG_HAS_INSECURE_DEFAULTS
      Documentation: user: optee: bring up-to-date
      Documentation: user: add security consideration for using barebox
      scripts: define _GNU_SOURCE for every user tool build
      scripts: common.h: define loff_t on musl

Alexander Shiyan (12):
      ARM: dts: rk356x: Use RNG node from upstream DTSI
      clk: rk3588: Add reset line for HDMI Receiver
      ARM: rockchip: dmc fix LPDDR5 bank info for sys_reg version 3
      clk: rk3588: sync with kernel
      ARM: at91: Compile at91sam9g45_reset handler only for affected SOCs
      ARM: at91: Remove AT91SAM9_SMC dependency for SAMA5D2
      mfd: atmel-flexcom: Driver refresh
      spi: Fix hang on spi_sync() when driver does not support transfer() call
      spi: at91: Use the SPI alias from devicetre
      usb: host: ehci-atmel: Add HSIC mode support
      mtd: Remove orphan symbol MTD_SST25L
      i2c: at91: Fix driver for SAMA5D2 SoC

Bastian Krause (4):
      keytoc: check for memory allocation failures in print_bignum()
      keytoc: move __ENV__ resolving to dedicated function
      keytoc: allow __ENV__ lookup for keyname hint
      crypto: document __ENV__ lookup in CRYPTO_PUBLIC_KEYS

Dang Huynh (1):
      ARM: rockchip: Add support for Pine64 PineTab 2

David Dgien (1):
      macb: Fix tx completion check

Jonas Rebmann (3):
      ARM: i.MX6: correct UART IOMUX_PADs
      ARM: dts: i.MX6: drop OCOTP MAC address provider
      ARM: boards: Add support for todarex colibri imx6 on iris

Jules Maselbas (1):
      scripts: include: rename printk.h to printf.h

Lucas Stach (10):
      ARM: zynq: add MMC aliases
      ARM: zynq: zed: define SDHCI bus-width
      ARM: zynq: zed: guard board initcall
      ARM: zynq: zed: add environment
      ARM: zynq: zed: add Barebox update handler
      ARM: zynq: enable some useful things in defconfig
      ARM: zynq: zed: switch to entry function with stack
      ARM: zynq: call common arm lowlevel init from zynq lowlevel init
      ARM: zynq: zed: always relocate in PBL
      environment: don't return raw device when file-path is specified

Marco Felsch (12):
      spi: cosmetic style fixes
      spi: fix spi_message init during __spi_validate
      spi: add spi_{set,get}_ctldata accessors
      gpiolib: add support for gpiod_get_index and gpiod_get_index_optional
      gpiolib: add support for gpiod_set_consumer_name
      spi: add support to handle cs-gpios
      spi: add support to setup spi-cs-{setup,hold,inactive}-delay-ns
      spi: allow reporting the effectivly used speed_hz for a transfer
      spi: import spi_controller::flags
      spi: add support for spi_controller::set_cs_timing
      spi: Provide common spi_message processing loop
      spi: add support for BCM2835 SPI controller

Oleksij Rempel (3):
      ARM: stm32mp151-mecio1: use kernel dts
      ARM: stm32mp151-mect1s: use kernel dts
      ARM: stm32: move stm32-bsec-optee-ta.h to include/soc/stm32

Roan van Dijk (1):
      ARM: protonic-stm32mp1: Add Add Priva E-Measuringbox board support

Sascha Hauer (66):
      ARM: dts: i.MX51 babbage: use upstream FEC pinctrl group
      dts: update to v6.13-rc1
      dts: update to v6.13-rc2
      fdt: Add function to check if a pointer contains a fdt
      store external device tree as file
      ARM: beagleplay: put external device tree into handoff data
      ARM: psci-client: better search for existing psci node
      dts: update to v6.13-rc3
      dts: update to v6.13-rc4
      dts: update to v6.13-rc5
      dts: update to v6.13-rc6
      gpio: fix static inline stub selection
      commands: add config option for dfu command
      common: always compile usbgadget.c when USB_GADGET is enabled
      usb: dwc3: add am62 support
      i2c: omap: add ti,am64-i2c compatible
      mfd: add tps65219 support
      ARM: enable CONFIG_USE_COMPRESSED_DTB by default
      usb: add static inline wrapper for of_usb_get_phy_mode()
      regulator: add tps65219 regulator support
      ARM: add ARMv7R MPU support
      lib/rationale: compile for pbl
      DDR: Add k3 DDR driver
      ARM: move ARM_CPU_PART_* defines to header
      nommu_v7_vectors_init: disable for r5
      clocksource: timer-ti-dm: add support for K3 SoCs
      ARM: K3: mount /boot even with env handling disabled
      clk: add K3 clk driver
      pmdomain: add K3 driver
      rproc: add K3 arm64 rproc driver
      ARM: k3: add k3_debug_ll_init()
      ARM: K3: use debug_ll code for regular PBL console
      elf: use iomem regions as fallback when loading to non-sdram memory
      rproc: add K3 system_controller
      firmware: ti_sci: add function to get global handle
      ARM: k3: Add initial r5 support
      dts: update to v6.13-rc7
      scripts: k3: add script to generate cfg files from yaml
      ARM: k3: Add k3img tool
      ARM: beagleplay: add Cortex-R5 boot support
      Documentation: add build documentation for TI K3 SoCs
      ARM: am625: disable secondary watchdogs
      ARM: k3: Add DRAM size detection
      ARM: k3: am625-sk board support
      ARM: k3: fix bootsource detection
      Merge branch 'for-next/arm'
      Merge branch 'for-next/dts'
      Merge branch 'for-next/fit'
      Merge branch 'for-next/fs'
      Merge branch 'for-next/images'
      Merge branch 'for-next/k3'
      Merge branch 'for-next/misc'
      Merge branch 'for-next/spi'
      ARM: k3: beagleplay: Use correct file for GP device
      ARM: beagleplay: Add missing DRAM frequencies
      file-list: fix file_list_detect_all()
      console: print countdown aborted message only once
      partitions: efi: Fix position of alternate gpt when writing
      environment: fix free() of unitialized variable
      net: Fix DRIVER_NET_TI_DAVINCI_MDIO dependency
      fs: squashfs: Ensure positive inode length
      fs: cramfs: fix malloc(size + constant) buffer overflow issues
      fs: ext4: fix malloc(size + constant) buffer overflow issues
      fs: jffs2: fix malloc(size + constant) buffer overflow issues
      CVE-2025-26721: fs: pstore: fix malloc(size + constant) buffer overflow issues
      Release v2025.02.0

Stefan Kerkmann (1):
      ARM: i.MX8MM: Phytec i.MX8MM SoC: change ddr_fsp0_cfg to static struct

Ulrich ?lmann (1):
      partitions: efi: fix error message in mkpart



-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From stefano.manni at gmail.com  Fri Feb 21 09:47:23 2025
From: stefano.manni at gmail.com (Stefano Manni)
Date: Fri, 21 Feb 2025 18:47:23 +0100
Subject: [PATCH 1/2] imx-bbu-nand-fcb: do not use hardcoded devicefile
In-Reply-To: <Z7hXohthRBbG9XIf@pengutronix.de>
References: <J2TZRS.AUAITN7RW0RJ1@gmail.com>
	<Z7hXohthRBbG9XIf@pengutronix.de>
Message-ID: <Z2O1SS.LY1P1MZAEMZ02@gmail.com>

Hi Sasha,

sorry but I changed my workstation recently and did not restore 
send-email as on the old one. I thought the mail client geary would be 
enough but it is not.
I will send a new patch series in these days.

Best,
Stefano

On ven, feb 21 2025 at 11:38:26 +01:00:00, Sascha Hauer 
<s.hauer at pengutronix.de> wrote:
> Hi Stefano,
> 
> The patch is mangled. Could you send it using git send-email? Using a
> web endpoint for b4 would be another possibility if git send-email
> doesn't work for you.
> 
> The two patches should be sent as one to avoid intermediate breakage
> between the patches.
> 
> Regards
>   Sascha
> 
> On Thu, Feb 20, 2025 at 06:39:55PM +0100, Stefano Manni wrote:
>>  Device file was hardcoded to "nand0.barebox".
>>  This patch harmonize the signature of
>> 
>>  imx6_bbu_nand_register_handler()
>>  imx7_bbu_nand_register_handler()
>>  imx28_bbu_nand_register_handler()
>> 
>>  with the other bbu register functions in order to take
>>  the devicefile as parameter.
>> 
>>  Signed-off-by: Stefano Manni <stefano.manni at gmail.com>
>>  ---
>>  common/imx-bbu-nand-fcb.c | 23 ++++++++++++++++-------
>>  include/bbu.h | 18 ++++++++++++------
>>  2 files changed, 28 insertions(+), 13 deletions(-)
>> 
>>  diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
>>  index d0261140cf..0d17a7bf6a 100644
>>  --- a/common/imx-bbu-nand-fcb.c
>>  +++ b/common/imx-bbu-nand-fcb.c
>>  @@ -1219,6 +1219,7 @@ static int imx_bbu_nand_update(struct 
>> bbu_handler
>>  *handler, struct bbu_data *dat
>>   int used = 0;
>>   int fw_orig_len = 0;
>>   int used_refresh = 0, unused_refresh = 0;
>>  + const char *devname = handler->devicefile;
>> 
>>   if (data->image) {
>>    filetype = file_detect_type(data->image, data->len);
>>  @@ -1230,7 +1231,12 @@ static int imx_bbu_nand_update(struct 
>> bbu_handler
>>  *handler, struct bbu_data *dat
>>     return -EINVAL;
>>   }
>> 
>>  - bcb_cdev = cdev_by_name(handler->devicefile);
>>  + /* Support both boot /dev/nand0.barebox and boot nand0.barebox */
>>  + devname += str_has_prefix(devname, "/dev/");
>>  +
>>  + device_detect_by_name(devname);
>>  +
>>  + bcb_cdev = cdev_by_name(devname);
>>   if (!bcb_cdev) {
>>    pr_err("%s: No FCB device!\n", __func__);
>>    return -ENODEV;
>>  @@ -1432,7 +1438,8 @@ static void imx6_fcb_create(struct
>>  imx_nand_fcb_bbu_handler *imx_handler,
>>   fcb->MetadataBytes = 10;
>>  }
>> 
>>  -int imx6_bbu_nand_register_handler(const char *name, unsigned long 
>> flags)
>>  +int imx6_bbu_nand_register_handler(const char *name,
>>  + const char *devicefile, unsigned long flags)
>>  {
>>   struct imx_nand_fcb_bbu_handler *imx_handler;
>>   struct bbu_handler *handler;
>>  @@ -1451,7 +1458,7 @@ int imx6_bbu_nand_register_handler(const char 
>> *name,
>>  unsigned long flags)
>>   }
>> 
>>   handler = &imx_handler->handler;
>>  - handler->devicefile = "nand0.barebox";
>>  + handler->devicefile = devicefile;
>>   handler->name = name;
>>   handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>>   handler->handler = imx_bbu_nand_update;
>>  @@ -1526,7 +1533,8 @@ static void imx28_fcb_create(struct
>>  imx_nand_fcb_bbu_handler *imx_handler,
>>   fcb->EraseThreshold = readl(bch_regs + BCH_MODE);
>>  }
>> 
>>  -int imx28_bbu_nand_register_handler(const char *name, unsigned 
>> long flags)
>>  +int imx28_bbu_nand_register_handler(const char *name,
>>  + const char *devicefile, unsigned long flags)
>>  {
>>   struct imx_nand_fcb_bbu_handler *imx_handler;
>>   struct bbu_handler *handler;
>>  @@ -1540,7 +1548,7 @@ int imx28_bbu_nand_register_handler(const 
>> char *name,
>>  unsigned long flags)
>>   imx_handler->filetype = filetype_mxs_bootstream;
>> 
>>   handler = &imx_handler->handler;
>>  - handler->devicefile = "nand0.barebox";
>>  + handler->devicefile = devicefile;
>>   handler->name = name;
>>   handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>>   handler->handler = imx_bbu_nand_update;
>>  @@ -1599,7 +1607,8 @@ static int imx7_fcb_write(struct mtd_info 
>> *mtd, int
>>  block, struct fcb_block *fcb
>>   return mxs_nand_write_fcb_bch62(block, fcb, sizeof(*fcb));
>>  }
>> 
>>  -int imx7_bbu_nand_register_handler(const char *name, unsigned long 
>> flags)
>>  +int imx7_bbu_nand_register_handler(const char *name
>>  + const char *devicefile, unsigned long flags)
>>  {
>>   struct imx_nand_fcb_bbu_handler *imx_handler;
>>   struct bbu_handler *handler;
>>  @@ -1612,7 +1621,7 @@ int imx7_bbu_nand_register_handler(const char 
>> *name,
>>  unsigned long flags)
>>   imx_handler->filetype = filetype_arm_barebox;
>> 
>>   handler = &imx_handler->handler;
>>  - handler->devicefile = "nand0.barebox";
>>  + handler->devicefile = devicefile;
>>   handler->name = name;
>>   handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>>   handler->handler = imx_bbu_nand_update;
>>  diff --git a/include/bbu.h b/include/bbu.h
>>  index 5105d2ac70..087d3ee827 100644
>>  --- a/include/bbu.h
>>  +++ b/include/bbu.h
>>  @@ -98,19 +98,25 @@ static inline int 
>> bbu_mmcboot_register_handler(const
>>  char *name,
>>  #endif
>> 
>>  #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB)
>>  -int imx6_bbu_nand_register_handler(const char *name, unsigned long 
>> flags);
>>  -int imx7_bbu_nand_register_handler(const char *name, unsigned long 
>> flags);
>>  -int imx28_bbu_nand_register_handler(const char *name, unsigned 
>> long flags);
>>  +int imx6_bbu_nand_register_handler(const char *name, const char
>>  *devicefile, unsigned long flags);
>>  +int imx7_bbu_nand_register_handler(const char *name, const char
>>  *devicefile, unsigned long flags);
>>  +int imx28_bbu_nand_register_handler(const char *name, const char
>>  *devicefile, unsigned long flags);
>>  #else
>>  -static inline int imx6_bbu_nand_register_handler(const char *name, 
>> unsigned
>>  long flags)
>>  +static inline int imx6_bbu_nand_register_handler(const char *name,
>>  + const char *devicefile,
>>  + unsigned long flags)
>>  {
>>   return -ENOSYS;
>>  }
>>  -static inline int imx7_bbu_nand_register_handler(const char *name, 
>> unsigned
>>  long flags)
>>  +static inline int imx7_bbu_nand_register_handler(const char *name,
>>  + const char *devicefile,
>>  + unsigned long flags)
>>  {
>>   return -ENOSYS;
>>  }
>>  -static inline int imx28_bbu_nand_register_handler(const char *name,
>>  unsigned long flags)
>>  +static inline int imx28_bbu_nand_register_handler(const char *name,
>>  + const char *devicefile,
>>  + unsigned long flags)
>>  {
>>   return -ENOSYS;
>>  }
>>  --
>>  2.25.1
>> 
>> 
>> 
>> 
>> 
> 
> --
> Pengutronix e.K.                           |                          
>    |
> Steuerwalder Str. 21                       | 
> http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0 
>    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   
> +49-5121-206917-5555 |




From stefano.manni at gmail.com  Fri Feb 21 10:01:08 2025
From: stefano.manni at gmail.com (Stefano Manni)
Date: Fri, 21 Feb 2025 19:01:08 +0100
Subject: [PATCH 1/2] imx-bbu-nand-fcb: do not use hardcoded devicefile
Message-ID: <20250221180109.14129-1-stefano.manni@gmail.com>

Device file was hardcoded to "nand0.barebox".
This patch harmonize the signature of

imx6_bbu_nand_register_handler()
imx7_bbu_nand_register_handler()
imx28_bbu_nand_register_handler()

with the other bbu register functions in order to take
the devicefile as parameter.

Signed-off-by: Stefano Manni <stefano.manni at gmail.com>
---
 common/imx-bbu-nand-fcb.c | 23 ++++++++++++++++-------
 include/bbu.h             | 18 ++++++++++++------
 2 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
index d0261140cf..0d17a7bf6a 100644
--- a/common/imx-bbu-nand-fcb.c
+++ b/common/imx-bbu-nand-fcb.c
@@ -1219,6 +1219,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 	int used = 0;
 	int fw_orig_len = 0;
 	int used_refresh = 0, unused_refresh = 0;
+	const char *devname = handler->devicefile;
 
 	if (data->image) {
 		filetype = file_detect_type(data->image, data->len);
@@ -1230,7 +1231,12 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
 			return -EINVAL;
 	}
 
-	bcb_cdev = cdev_by_name(handler->devicefile);
+	/* Support both boot /dev/nand0.barebox and boot nand0.barebox */
+	devname += str_has_prefix(devname, "/dev/");
+
+	device_detect_by_name(devname);
+
+	bcb_cdev = cdev_by_name(devname);
 	if (!bcb_cdev) {
 		pr_err("%s: No FCB device!\n", __func__);
 		return -ENODEV;
@@ -1432,7 +1438,8 @@ static void imx6_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
 	fcb->MetadataBytes = 10;
 }
 
-int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
+int imx6_bbu_nand_register_handler(const char *name,
+		const char *devicefile, unsigned long flags)
 {
 	struct imx_nand_fcb_bbu_handler *imx_handler;
 	struct bbu_handler *handler;
@@ -1451,7 +1458,7 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
 	}
 
 	handler = &imx_handler->handler;
-	handler->devicefile = "nand0.barebox";
+	handler->devicefile = devicefile;
 	handler->name = name;
 	handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
 	handler->handler = imx_bbu_nand_update;
@@ -1526,7 +1533,8 @@ static void imx28_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
 	fcb->EraseThreshold = readl(bch_regs + BCH_MODE);
 }
 
-int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
+int imx28_bbu_nand_register_handler(const char *name,
+		const char *devicefile, unsigned long flags)
 {
 	struct imx_nand_fcb_bbu_handler *imx_handler;
 	struct bbu_handler *handler;
@@ -1540,7 +1548,7 @@ int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
 	imx_handler->filetype = filetype_mxs_bootstream;
 
 	handler = &imx_handler->handler;
-	handler->devicefile = "nand0.barebox";
+	handler->devicefile = devicefile;
 	handler->name = name;
 	handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
 	handler->handler = imx_bbu_nand_update;
@@ -1599,7 +1607,8 @@ static int imx7_fcb_write(struct mtd_info *mtd, int block, struct fcb_block *fcb
 	return mxs_nand_write_fcb_bch62(block, fcb, sizeof(*fcb));
 }
 
-int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
+int imx7_bbu_nand_register_handler(const char *name
+	   const char *devicefile, unsigned long flags)
 {
 	struct imx_nand_fcb_bbu_handler *imx_handler;
 	struct bbu_handler *handler;
@@ -1612,7 +1621,7 @@ int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
 	imx_handler->filetype = filetype_arm_barebox;
 
 	handler = &imx_handler->handler;
-	handler->devicefile = "nand0.barebox";
+	handler->devicefile = devicefile;
 	handler->name = name;
 	handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
 	handler->handler = imx_bbu_nand_update;
diff --git a/include/bbu.h b/include/bbu.h
index 5105d2ac70..087d3ee827 100644
--- a/include/bbu.h
+++ b/include/bbu.h
@@ -98,19 +98,25 @@ static inline int bbu_mmcboot_register_handler(const char *name,
 #endif
 
 #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB)
-int imx6_bbu_nand_register_handler(const char *name, unsigned long flags);
-int imx7_bbu_nand_register_handler(const char *name, unsigned long flags);
-int imx28_bbu_nand_register_handler(const char *name, unsigned long flags);
+int imx6_bbu_nand_register_handler(const char *name, const char *devicefile, unsigned long flags);
+int imx7_bbu_nand_register_handler(const char *name, const char *devicefile, unsigned long flags);
+int imx28_bbu_nand_register_handler(const char *name, const char *devicefile, unsigned long flags);
 #else
-static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
+static inline int imx6_bbu_nand_register_handler(const char *name,
+					       const char *devicefile,
+					       unsigned long flags)
 {
 	return -ENOSYS;
 }
-static inline int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
+static inline int imx7_bbu_nand_register_handler(const char *name,
+					       const char *devicefile,
+					       unsigned long flags)
 {
 	return -ENOSYS;
 }
-static inline int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
+static inline int imx28_bbu_nand_register_handler(const char *name,
+					       const char *devicefile,
+					       unsigned long flags)
 {
 	return -ENOSYS;
 }
-- 
2.25.1



From stefano.manni at gmail.com  Fri Feb 21 10:01:09 2025
From: stefano.manni at gmail.com (Stefano Manni)
Date: Fri, 21 Feb 2025 19:01:09 +0100
Subject: [PATCH 2/2] ARM: boards: fix nand bbu_handler device paths
In-Reply-To: <20250221180109.14129-1-stefano.manni@gmail.com>
References: <20250221180109.14129-1-stefano.manni@gmail.com>
Message-ID: <20250221180109.14129-2-stefano.manni@gmail.com>

The bbu handler for nand now takes the device
path as parameter and no longer use the hardcoded
value.
Make the change accordingly to all the boards
using it.

Signed-off-by: Stefano Manni <stefano.manni at gmail.com>
---
 arch/arm/boards/digi-ccimx6ulsom/board.c  | 3 ++-
 arch/arm/boards/gateworks-ventana/board.c | 4 +++-
 arch/arm/boards/karo-tx6x/board.c         | 3 ++-
 arch/arm/boards/phytec-som-imx6/board.c   | 4 +++-
 4 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boards/digi-ccimx6ulsom/board.c b/arch/arm/boards/digi-ccimx6ulsom/board.c
index ef6828c02c..9765c65839 100644
--- a/arch/arm/boards/digi-ccimx6ulsom/board.c
+++ b/arch/arm/boards/digi-ccimx6ulsom/board.c
@@ -11,7 +11,8 @@ static int digi_ccimx6ulsbcpro_device_init(void)
 	if (!of_machine_is_compatible("digi,ccimx6ulsbcpro"))
 		return 0;
 
-	imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+	imx6_bbu_nand_register_handler("nand", "/dev/nand0.barebox",
+			BBU_HANDLER_FLAG_DEFAULT);
 
 	barebox_set_hostname("ccimx6ulsbcpro");
 
diff --git a/arch/arm/boards/gateworks-ventana/board.c b/arch/arm/boards/gateworks-ventana/board.c
index aa2137a971..9c0012b359 100644
--- a/arch/arm/boards/gateworks-ventana/board.c
+++ b/arch/arm/boards/gateworks-ventana/board.c
@@ -72,7 +72,9 @@ static int gw54xx_devices_init(void)
 	if (gsc_get_rev(&client) < 'E')
 		of_register_fixup(gw54xx_wdog_of_fixup, NULL);
 
-	imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+	imx6_bbu_nand_register_handler("nand",
+			"/dev/nand0.barebox",
+			BBU_HANDLER_FLAG_DEFAULT);
 
 	barebox_set_hostname("gw54xx");
 
diff --git a/arch/arm/boards/karo-tx6x/board.c b/arch/arm/boards/karo-tx6x/board.c
index f964ddefd1..1e14a75272 100644
--- a/arch/arm/boards/karo-tx6x/board.c
+++ b/arch/arm/boards/karo-tx6x/board.c
@@ -110,7 +110,8 @@ static int tx6x_devices_init(void)
 	 * this board has eMMC or NAND.
 	 */
 	if (sbmr1 & (1 << 7)) {
-		imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+		imx6_bbu_nand_register_handler("nand", "/dev/nand0.barebox",
+								BBU_HANDLER_FLAG_DEFAULT);
 		of_device_enable_and_register_by_name("environment-nand");
 		of_device_enable_and_register_by_alias("nand");
 	} else {
diff --git a/arch/arm/boards/phytec-som-imx6/board.c b/arch/arm/boards/phytec-som-imx6/board.c
index 2db3fa1db8..7e6f61bc36 100644
--- a/arch/arm/boards/phytec-som-imx6/board.c
+++ b/arch/arm/boards/phytec-som-imx6/board.c
@@ -259,7 +259,9 @@ static int physom_imx6_probe(struct device *dev)
 		imx6_bbu_internal_mmcboot_register_handler("mmc1-boot",
 						"mmc1", 0);
 	} else {
-		imx6_bbu_nand_register_handler("nand", BBU_HANDLER_FLAG_DEFAULT);
+		imx6_bbu_nand_register_handler("nand",
+						"/dev/nand0.barebox",
+						BBU_HANDLER_FLAG_DEFAULT);
 	}
 
 	defaultenv_append_directory(defaultenv_physom_imx6);
-- 
2.25.1



From a.fatoum at pengutronix.de  Fri Feb 21 09:33:04 2025
From: a.fatoum at pengutronix.de (Ahmad Fatoum)
Date: Fri, 21 Feb 2025 18:33:04 +0100
Subject: [PATCH 1/2] imx-bbu-nand-fcb: do not use hardcoded devicefile
In-Reply-To: <20250221180109.14129-1-stefano.manni@gmail.com>
References: <20250221180109.14129-1-stefano.manni@gmail.com>
Message-ID: <06d40295-264c-4119-a201-f6e045def59d@pengutronix.de>

Hello Stefano,

On 21.02.25 19:01, Stefano Manni wrote:
> Device file was hardcoded to "nand0.barebox".
> This patch harmonize the signature of
> 
> imx6_bbu_nand_register_handler()
> imx7_bbu_nand_register_handler()
> imx28_bbu_nand_register_handler()
> 
> with the other bbu register functions in order to take
> the devicefile as parameter.

Is this this the sole motivation behind the patch or do you
intend to actually make use of the ability of varying
the devicefile?

Thanks,
Ahmad

> 
> Signed-off-by: Stefano Manni <stefano.manni at gmail.com>
> ---
>  common/imx-bbu-nand-fcb.c | 23 ++++++++++++++++-------
>  include/bbu.h             | 18 ++++++++++++------
>  2 files changed, 28 insertions(+), 13 deletions(-)
> 
> diff --git a/common/imx-bbu-nand-fcb.c b/common/imx-bbu-nand-fcb.c
> index d0261140cf..0d17a7bf6a 100644
> --- a/common/imx-bbu-nand-fcb.c
> +++ b/common/imx-bbu-nand-fcb.c
> @@ -1219,6 +1219,7 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
>  	int used = 0;
>  	int fw_orig_len = 0;
>  	int used_refresh = 0, unused_refresh = 0;
> +	const char *devname = handler->devicefile;
>  
>  	if (data->image) {
>  		filetype = file_detect_type(data->image, data->len);
> @@ -1230,7 +1231,12 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
>  			return -EINVAL;
>  	}
>  
> -	bcb_cdev = cdev_by_name(handler->devicefile);
> +	/* Support both boot /dev/nand0.barebox and boot nand0.barebox */
> +	devname += str_has_prefix(devname, "/dev/");
> +
> +	device_detect_by_name(devname);
> +
> +	bcb_cdev = cdev_by_name(devname);
>  	if (!bcb_cdev) {
>  		pr_err("%s: No FCB device!\n", __func__);
>  		return -ENODEV;
> @@ -1432,7 +1438,8 @@ static void imx6_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
>  	fcb->MetadataBytes = 10;
>  }
>  
> -int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
> +int imx6_bbu_nand_register_handler(const char *name,
> +		const char *devicefile, unsigned long flags)
>  {
>  	struct imx_nand_fcb_bbu_handler *imx_handler;
>  	struct bbu_handler *handler;
> @@ -1451,7 +1458,7 @@ int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
>  	}
>  
>  	handler = &imx_handler->handler;
> -	handler->devicefile = "nand0.barebox";
> +	handler->devicefile = devicefile;
>  	handler->name = name;
>  	handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>  	handler->handler = imx_bbu_nand_update;
> @@ -1526,7 +1533,8 @@ static void imx28_fcb_create(struct imx_nand_fcb_bbu_handler *imx_handler,
>  	fcb->EraseThreshold = readl(bch_regs + BCH_MODE);
>  }
>  
> -int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
> +int imx28_bbu_nand_register_handler(const char *name,
> +		const char *devicefile, unsigned long flags)
>  {
>  	struct imx_nand_fcb_bbu_handler *imx_handler;
>  	struct bbu_handler *handler;
> @@ -1540,7 +1548,7 @@ int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
>  	imx_handler->filetype = filetype_mxs_bootstream;
>  
>  	handler = &imx_handler->handler;
> -	handler->devicefile = "nand0.barebox";
> +	handler->devicefile = devicefile;
>  	handler->name = name;
>  	handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>  	handler->handler = imx_bbu_nand_update;
> @@ -1599,7 +1607,8 @@ static int imx7_fcb_write(struct mtd_info *mtd, int block, struct fcb_block *fcb
>  	return mxs_nand_write_fcb_bch62(block, fcb, sizeof(*fcb));
>  }
>  
> -int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
> +int imx7_bbu_nand_register_handler(const char *name
> +	   const char *devicefile, unsigned long flags)
>  {
>  	struct imx_nand_fcb_bbu_handler *imx_handler;
>  	struct bbu_handler *handler;
> @@ -1612,7 +1621,7 @@ int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
>  	imx_handler->filetype = filetype_arm_barebox;
>  
>  	handler = &imx_handler->handler;
> -	handler->devicefile = "nand0.barebox";
> +	handler->devicefile = devicefile;
>  	handler->name = name;
>  	handler->flags = flags | BBU_HANDLER_CAN_REFRESH;
>  	handler->handler = imx_bbu_nand_update;
> diff --git a/include/bbu.h b/include/bbu.h
> index 5105d2ac70..087d3ee827 100644
> --- a/include/bbu.h
> +++ b/include/bbu.h
> @@ -98,19 +98,25 @@ static inline int bbu_mmcboot_register_handler(const char *name,
>  #endif
>  
>  #if defined(CONFIG_BAREBOX_UPDATE_IMX_NAND_FCB)
> -int imx6_bbu_nand_register_handler(const char *name, unsigned long flags);
> -int imx7_bbu_nand_register_handler(const char *name, unsigned long flags);
> -int imx28_bbu_nand_register_handler(const char *name, unsigned long flags);
> +int imx6_bbu_nand_register_handler(const char *name, const char *devicefile, unsigned long flags);
> +int imx7_bbu_nand_register_handler(const char *name, const char *devicefile, unsigned long flags);
> +int imx28_bbu_nand_register_handler(const char *name, const char *devicefile, unsigned long flags);
>  #else
> -static inline int imx6_bbu_nand_register_handler(const char *name, unsigned long flags)
> +static inline int imx6_bbu_nand_register_handler(const char *name,
> +					       const char *devicefile,
> +					       unsigned long flags)
>  {
>  	return -ENOSYS;
>  }
> -static inline int imx7_bbu_nand_register_handler(const char *name, unsigned long flags)
> +static inline int imx7_bbu_nand_register_handler(const char *name,
> +					       const char *devicefile,
> +					       unsigned long flags)
>  {
>  	return -ENOSYS;
>  }
> -static inline int imx28_bbu_nand_register_handler(const char *name, unsigned long flags)
> +static inline int imx28_bbu_nand_register_handler(const char *name,
> +					       const char *devicefile,
> +					       unsigned long flags)
>  {
>  	return -ENOSYS;
>  }


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From jonathanbaror at gmail.com  Sat Feb 22 12:46:18 2025
From: jonathanbaror at gmail.com (Jonathan Bar Or)
Date: Sat, 22 Feb 2025 12:46:18 -0800
Subject: [PATCH 0/5] Filesystem memory corruption fixes
In-Reply-To: <174012323334.2354255.16758545638294107895.b4-ty@pengutronix.de>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de> <174012323334.2354255.16758545638294107895.b4-ty@pengutronix.de>
Message-ID: <CABMsoEGDcxSCSfdnV0B1dKvvJaQYBYhpAu2R_t31j5g_Q8fVBg@mail.gmail.com>

Those are awesome, thank you.
We intend to publicly disclose March 19th, is that okay?

Jonathan

On Thu, Feb 20, 2025 at 11:33?PM Sascha Hauer <s.hauer at pengutronix.de> wrote:
>
>
> On Wed, 19 Feb 2025 15:18:39 +0100, Sascha Hauer wrote:
> > These are some fixes for memory corruptions that can occur on corrupted
> > or manipulated filesystems.
> >
> > In case you use one of the affected filesystems in a secure boot chain
> > you should apply these patches.
> >
> > Normally you shouldn't use a barebox filesystem in a secure boot chain,
> > but instead use FIT images on a raw partition. We never made this explicit
> > though. Ahmad has done this recently:
> >
> > [...]
>
> Applied, thanks!
>
> [1/5] CVE-2025-26722: fs: squashfs: Ensure positive inode length
>       https://git.pengutronix.de/cgit/barebox/commit/?id=6281a871e2c6 (link may not be stable)
> [2/5] CVE-2025-26724: fs: cramfs: fix malloc(size + constant) buffer overflow issues
>       https://git.pengutronix.de/cgit/barebox/commit/?id=f86e528c8fba (link may not be stable)
> [3/5] CVE-2025-26723: fs: ext4: fix malloc(size + constant) buffer overflow issues
>       https://git.pengutronix.de/cgit/barebox/commit/?id=51eea5c16fd2 (link may not be stable)
> [4/5] CVE-2025-26725: fs: jffs2: fix malloc(size + constant) buffer overflow issues
>       https://git.pengutronix.de/cgit/barebox/commit/?id=e7397340359d (link may not be stable)
> [5/5] CVE-2025-26721: fs: pstore: fix malloc(size + constant) buffer overflow issues
>       https://git.pengutronix.de/cgit/barebox/commit/?id=7563f5722dfd (link may not be stable)
>
> Best regards,
> --
> Sascha Hauer <s.hauer at pengutronix.de>
>


From s.hauer at pengutronix.de  Mon Feb 24 01:09:38 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Mon, 24 Feb 2025 10:09:38 +0100
Subject: [PATCH 1/2] fip: Store image data in single buffer
In-Reply-To: <20250217122538.3216703-1-s.hauer@pengutronix.de>
References: <20250217122538.3216703-1-s.hauer@pengutronix.de>
Message-ID: <174038817832.624372.5677842270749676017.b4-ty@pengutronix.de>


On Mon, 17 Feb 2025 13:25:37 +0100, Sascha Hauer wrote:
> Right now in fip_parse() we read the whole FIP image into an allocated
> buffer, then allocate buffers for the different blobs contained in the
> FIP image and memcpy the blobs there from the full buffer. Let's
> optimize this a bit by keeping the full buffer. Instead of allocating
> separate buffers for the blobs, just put pointers to the full buffers
> into struct fip_image and set the buf_no_free flag indicating that they
> should not be freed.
> 
> [...]

Applied, thanks!

[1/2] fip: Store image data in single buffer
      https://git.pengutronix.de/cgit/barebox/commit/?id=e48141941199 (link may not be stable)
[2/2] fip: add function to parse FIP from a buffer
      https://git.pengutronix.de/cgit/barebox/commit/?id=748ba0627681 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From stefano.manni at gmail.com  Mon Feb 24 07:49:54 2025
From: stefano.manni at gmail.com (Stefano Manni)
Date: Mon, 24 Feb 2025 16:49:54 +0100
Subject: [PATCH 1/2] imx-bbu-nand-fcb: do not use hardcoded devicefile
In-Reply-To: <06d40295-264c-4119-a201-f6e045def59d@pengutronix.de>
References: <20250221180109.14129-1-stefano.manni@gmail.com>
	<06d40295-264c-4119-a201-f6e045def59d@pengutronix.de>
Message-ID: <6N27SS.D8B9D3CEGOUH3@gmail.com>

Hello Ahmad,

On ven, feb 21 2025 at 18:33:04 +01:00:00, Ahmad Fatoum 
<a.fatoum at pengutronix.de> wrote:
> Hello Stefano,
> 
> On 21.02.25 19:01, Stefano Manni wrote:
>>  Device file was hardcoded to "nand0.barebox".
>>  This patch harmonize the signature of
>> 
>>  imx6_bbu_nand_register_handler()
>>  imx7_bbu_nand_register_handler()
>>  imx28_bbu_nand_register_handler()
>> 
>>  with the other bbu register functions in order to take
>>  the devicefile as parameter.
> 
> Is this this the sole motivation behind the patch or do you
> intend to actually make use of the ability of varying
> the devicefile?

my purpose is to let people use a device/partition different from the 
hardcoded one.

> 
> Thanks,
> Ahmad




From s.kerkmann at pengutronix.de  Tue Feb 25 02:56:40 2025
From: s.kerkmann at pengutronix.de (Stefan Kerkmann)
Date: Tue, 25 Feb 2025 11:56:40 +0100
Subject: [PATCH] i.mx8: ocotp: add GPx defines
Message-ID: <20250225-imx8-ocotp-gp-defines-v1-1-344b291675a7@pengutronix.de>

The general purpose GPx registers changed position in the fuse map from
the i.MX6 series and derivates to the i.MX8 series. The i.MX8MP has 4
additional 128-bit wide fuse banks which have been added as well.

The defines have been derived from:

IMX8MNRM Rev. 2 (i.MX8MN)
IMX8MPRM Rev. 3 (i.MX8MP)
IMX8MMRM Rev. 3 (i.MX8MM)

Signed-off-by: Stefan Kerkmann <s.kerkmann at pengutronix.de>
---
 include/mach/imx/ocotp-fusemap.h | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/include/mach/imx/ocotp-fusemap.h b/include/mach/imx/ocotp-fusemap.h
index 3c961998b0fc4bd374331342baaa2051163309ae..74f3a55d182d50046d7d544603110fefd590e368 100644
--- a/include/mach/imx/ocotp-fusemap.h
+++ b/include/mach/imx/ocotp-fusemap.h
@@ -17,6 +17,10 @@
 #define MX8M_OCOTP_GP1_LOCK		(OCOTP_WORD(0x400) | OCOTP_BIT(20) | OCOTP_WIDTH(2))
 #define MX8M_OCOTP_GP2_LOCK		(OCOTP_WORD(0x400) | OCOTP_BIT(22) | OCOTP_WIDTH(2))
 #define MX8M_OCOTP_GP5_LOCK		(OCOTP_WORD(0x400) | OCOTP_BIT(24) | OCOTP_WIDTH(2))
+#define MX8M_OCOTP_GP1_0		(OCOTP_WORD(0x780) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8M_OCOTP_GP1_1		(OCOTP_WORD(0x790) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8M_OCOTP_GP2_0		(OCOTP_WORD(0x7A0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8M_OCOTP_GP2_1		(OCOTP_WORD(0x7B0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
 
 /* available on i.MX8MP */
 #define MX8MP_OCOTP_GP1_LOCK	MX8M_OCOTP_GP1_LOCK
@@ -27,6 +31,22 @@
 #define MX8MP_OCOTP_GP7_LOCK	(OCOTP_WORD(0x410) | OCOTP_BIT(12) | OCOTP_WIDTH(2))
 #define MX8MP_OCOTP_GP8_LOCK	(OCOTP_WORD(0x410) | OCOTP_BIT(14) | OCOTP_WIDTH(2))
 #define MX8MP_OCOTP_GP9_LOCK	(OCOTP_WORD(0x410) | OCOTP_BIT(16) | OCOTP_WIDTH(2))
+#define MX8MP_OCOTP_GP6_0		(OCOTP_WORD(0xE40) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP6_1		(OCOTP_WORD(0xE50) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP6_2		(OCOTP_WORD(0xE60) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP6_3		(OCOTP_WORD(0xE70) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP7_0		(OCOTP_WORD(0xE80) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP7_1		(OCOTP_WORD(0xE90) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP7_2		(OCOTP_WORD(0xEA0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP7_3		(OCOTP_WORD(0xEB0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP8_0		(OCOTP_WORD(0xEC0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP8_1		(OCOTP_WORD(0xED0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP8_2		(OCOTP_WORD(0xEE0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP8_3		(OCOTP_WORD(0xEF0) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP9_0		(OCOTP_WORD(0xF00) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP9_1		(OCOTP_WORD(0xF30) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP9_2		(OCOTP_WORD(0xF40) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
+#define MX8MP_OCOTP_GP9_3		(OCOTP_WORD(0xF50) | OCOTP_BIT(0) | OCOTP_WIDTH(32))
 
 #define OCOTP_SRK_LOCK			(OCOTP_WORD(0x400) | OCOTP_BIT(14) | OCOTP_WIDTH(1))
 #define OCOTP_ANALOG_LOCK		(OCOTP_WORD(0x400) | OCOTP_BIT(18) | OCOTP_WIDTH(2))

---
base-commit: a2e7a50e3417b93effd9cce56ea94fec8b40f814
change-id: 20250225-imx8-ocotp-gp-defines-2990fa080367

Best regards,
-- 
Stefan Kerkmann <s.kerkmann at pengutronix.de>



From Oliver.Rohe at wago.com  Wed Feb 26 06:29:48 2025
From: Oliver.Rohe at wago.com (Oliver ROHE)
Date: Wed, 26 Feb 2025 14:29:48 +0000
Subject: [PATCH] fix partuuid format
Message-ID: <AS4PR08MB8093429FE84A32C579C03FE69EC22@AS4PR08MB8093.eurprd08.prod.outlook.com>

root=PARTUUID=SSSSSSSS-PP

Where SSSSSSSS is a zero-filled 32-bit MBR disk signature,
and PP is a zero-filled partition number in hexadecimal format.

Signed-off-by: Oliver Rohe <oliver.rohe at wago.com>

diff --git a/common/partitions/dos.c b/common/partitions/dos.c
index 95b71af7ff8..6204fdabc81 100644
--- a/common/partitions/dos.c
+++ b/common/partitions/dos.c
@@ -172,7 +172,7 @@ static void dos_extended_partition(struct block_device *blk, struct dos_partitio
                pentry->size = get_unaligned_le32(&table[0].partition_size);
                pentry->dos_partition_type = table[0].type;
                pentry->num = partno;
-               sprintf(pentry->partuuid, "%08x-%02u", signature, partno + 1);
+               sprintf(pentry->partuuid, "%08x-%02x", signature, partno + 1);

                list_add_tail(&pentry->list, &dpd->pd.partitions);

@@ -270,7 +270,7 @@ static struct partition_desc *dos_partition(void *buf, struct block_device *blk)
                extract_flags(&table[i], pentry);
                pentry->num = i;

-               sprintf(pentry->partuuid, "%08x-%02d", signature, i + 1);
+               sprintf(pentry->partuuid, "%08x-%02x", signature, i + 1);
                dpd->signature = signature;

                if (is_extended_partition(pentry)) {
diff --git a/scripts/kernel-install.c b/scripts/kernel-install.c
index 240122f2d22..05e464d114c 100644
--- a/scripts/kernel-install.c
+++ b/scripts/kernel-install.c
@@ -1370,7 +1370,7 @@ int main(int argc, char *argv[])
                        goto out;
                }

-               append_option("root=PARTUUID=%08X-%02d", nt_disk_signature, root_partition_num);
+               append_option("root=PARTUUID=%08X-%02X", nt_disk_signature, root_partition_num);
        }

        if (list) {
--
2.25.1

Internal


From eagle.alexander923 at gmail.com  Wed Feb 26 22:37:37 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Thu, 27 Feb 2025 09:37:37 +0300
Subject: automount doesn't work without GPT table
Message-ID: <CAP1tNvToG8WGLUo4_e2dSdovFZBAbcdOFUqm+F+W4gWoaVnrgQ@mail.gmail.com>

Hello All.

I found that automounting does not work without a GPT table.
In the example below, it is not possible to automatically mount a
partition from an MMC card.
However, if I add the full paths to the command manually, everything works.

barebox 2025.02.0-00690-ga6a0a0ba4f61 #12 Thu Feb 27 08:27:56 MSK 2025
Board: Mega-Milas MM-SM-SAMA5D2
AT91: Detected soc type: sama5d2
AT91: Detected soc subtype: sama5d27c_d1g
...
sdhci-at91 b0000000.sdio-host at b0000000.of: registered as mmc1
mmc1: detected SD card version 2.0
mmc1: registered mmc1
...
barebox at Mega-Milas Informer SAMA5D2:/ ls /mnt/mmc1.0
mount: Device or resource busy
running automount command 'mount mmc1.0' failed
ls: No such device

barebox at Mega-Milas Informer SAMA5D2:/ automount -l
/mnt/mmc1            mount mmc1
/mnt/mmc1.0          mount mmc1.0
/mnt/mmc1.1          mount mmc1.1
/mnt/tftp            ifup -a1 && mount -t tftp $global.net.server /mnt/tftp
/mnt/nfs             ifup -a1 && mount -t nfs
${global.net.server}:/home/${global.user}/nfsroot/${global.hostname}
/mnt/nfs
/mnt/ratp            mount -t ratpfs none /mnt/ratp

barebox at Mega-Milas Informer SAMA5D2:/ automount /mnt/mmc1.0  "mount
/dev/mmc1.0 /mnt/mmc1.0"
barebox at Mega-Milas Informer SAMA5D2:/ ls /mnt/mmc1.0
BOOT.BIN           barebox.bin        barebox.env        rootfs.squashfs

With the GPT table on the MMC, everything works OK out of the box:

sdhci-at91 b0000000.sdio-host at b0000000.of: registered as mmc1
mmc1: detected SD card version 2.0
WARNING: mmc1: GPT:Primary header thinks Alt. header is not at the end
of the disk.
WARNING: mmc1: GPT:395303 != 60440575
WARNING: mmc1: GPT:Alternate GPT header not at the end of the disk.
WARNING: mmc1: GPT:395303 != 60440575
WARNING: mmc1: GPT: Use parted to correct GPT errors.
mmc1: registered mmc1
...

barebox at Mega-Milas Informer SAMA5D2:/ ls /mnt/mmc1.0
mounted /dev/mmc1.0 on /mnt/mmc1.0
BOOT.BIN           barebox.bin        barebox.env        rootfs.squashfs


From s.hauer at pengutronix.de  Thu Feb 27 01:36:15 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Thu, 27 Feb 2025 10:36:15 +0100
Subject: [PATCH 0/5] Filesystem memory corruption fixes
In-Reply-To: <CABMsoEGDcxSCSfdnV0B1dKvvJaQYBYhpAu2R_t31j5g_Q8fVBg@mail.gmail.com>
References: <20250219141844.1912413-1-s.hauer@pengutronix.de>
 <174012323334.2354255.16758545638294107895.b4-ty@pengutronix.de>
 <CABMsoEGDcxSCSfdnV0B1dKvvJaQYBYhpAu2R_t31j5g_Q8fVBg@mail.gmail.com>
Message-ID: <Z8AyD_cHzW_Wxcqz@pengutronix.de>

On Sat, Feb 22, 2025 at 12:46:18PM -0800, Jonathan Bar Or wrote:
> Those are awesome, thank you.
> We intend to publicly disclose March 19th, is that okay?

Well, this is a public list, so they are already disclosed...

Sascha

> 
> Jonathan
> 
> On Thu, Feb 20, 2025 at 11:33?PM Sascha Hauer <s.hauer at pengutronix.de> wrote:
> >
> >
> > On Wed, 19 Feb 2025 15:18:39 +0100, Sascha Hauer wrote:
> > > These are some fixes for memory corruptions that can occur on corrupted
> > > or manipulated filesystems.
> > >
> > > In case you use one of the affected filesystems in a secure boot chain
> > > you should apply these patches.
> > >
> > > Normally you shouldn't use a barebox filesystem in a secure boot chain,
> > > but instead use FIT images on a raw partition. We never made this explicit
> > > though. Ahmad has done this recently:
> > >
> > > [...]
> >
> > Applied, thanks!
> >
> > [1/5] CVE-2025-26722: fs: squashfs: Ensure positive inode length
> >       https://git.pengutronix.de/cgit/barebox/commit/?id=6281a871e2c6 (link may not be stable)
> > [2/5] CVE-2025-26724: fs: cramfs: fix malloc(size + constant) buffer overflow issues
> >       https://git.pengutronix.de/cgit/barebox/commit/?id=f86e528c8fba (link may not be stable)
> > [3/5] CVE-2025-26723: fs: ext4: fix malloc(size + constant) buffer overflow issues
> >       https://git.pengutronix.de/cgit/barebox/commit/?id=51eea5c16fd2 (link may not be stable)
> > [4/5] CVE-2025-26725: fs: jffs2: fix malloc(size + constant) buffer overflow issues
> >       https://git.pengutronix.de/cgit/barebox/commit/?id=e7397340359d (link may not be stable)
> > [5/5] CVE-2025-26721: fs: pstore: fix malloc(size + constant) buffer overflow issues
> >       https://git.pengutronix.de/cgit/barebox/commit/?id=7563f5722dfd (link may not be stable)
> >
> > Best regards,
> > --
> > Sascha Hauer <s.hauer at pengutronix.de>
> >
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Thu Feb 27 09:00:59 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Thu, 27 Feb 2025 18:00:59 +0100
Subject: automount doesn't work without GPT table
In-Reply-To: <CAP1tNvToG8WGLUo4_e2dSdovFZBAbcdOFUqm+F+W4gWoaVnrgQ@mail.gmail.com>
References: <CAP1tNvToG8WGLUo4_e2dSdovFZBAbcdOFUqm+F+W4gWoaVnrgQ@mail.gmail.com>
Message-ID: <Z8CaS4gLesWjG81q@pengutronix.de>

Hi ALexander,

On Thu, Feb 27, 2025 at 09:37:37AM +0300, Alexander Shiyan wrote:
> Hello All.
> 
> I found that automounting does not work without a GPT table.

So you mean it doesn't work when the device has a MBR instead of a GPT?

> In the example below, it is not possible to automatically mount a
> partition from an MMC card.
> However, if I add the full paths to the command manually, everything works.
> 
> barebox 2025.02.0-00690-ga6a0a0ba4f61 #12 Thu Feb 27 08:27:56 MSK 2025
> Board: Mega-Milas MM-SM-SAMA5D2
> AT91: Detected soc type: sama5d2
> AT91: Detected soc subtype: sama5d27c_d1g
> ...
> sdhci-at91 b0000000.sdio-host at b0000000.of: registered as mmc1
> mmc1: detected SD card version 2.0
> mmc1: registered mmc1
> ...
> barebox at Mega-Milas Informer SAMA5D2:/ ls /mnt/mmc1.0
> mount: Device or resource busy

-EBUSY is a strange error code from mount(). Can you follow where it
comes from?

I can't reproduce it here. I tried both with a MBR and a GPT.

Sascha


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From eagle.alexander923 at gmail.com  Thu Feb 27 22:06:55 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Fri, 28 Feb 2025 09:06:55 +0300
Subject: automount doesn't work without GPT table
In-Reply-To: <Z8CaS4gLesWjG81q@pengutronix.de>
References: <CAP1tNvToG8WGLUo4_e2dSdovFZBAbcdOFUqm+F+W4gWoaVnrgQ@mail.gmail.com>
 <Z8CaS4gLesWjG81q@pengutronix.de>
Message-ID: <CAP1tNvQFhZHobkaYL_v9aQ8FAqEtd--pkGxW3C6v81zMUaM-PQ@mail.gmail.com>

Hello Sascha.

The error occurs in the cdev_mount_default() function.
cdev_get_mount_path() returns "/boot".
And indeed, the partition is mounted here for some reason...
I don't understand yet why this happens.

barebox at Mega-Milas Informer SAMA5D2:/ mount
none on / type ramfs
none on /dev type devfs
/dev/mmc1.0 on /boot type fat

Update:
I found that this happens if the CONFIG_OF_BAREBOX_ENV_IN_FS option is used.
When disabled, mounting occurs as expected, but in this case I cannot
use environments from a file from a partition on the SD card.
It is not yet clear how to get out of this situation...

Thanks!

??, 27 ????. 2025??. ? 20:01, Sascha Hauer <s.hauer at pengutronix.de>:
>
> Hi ALexander,
>
> On Thu, Feb 27, 2025 at 09:37:37AM +0300, Alexander Shiyan wrote:
> > Hello All.
> >
> > I found that automounting does not work without a GPT table.
>
> So you mean it doesn't work when the device has a MBR instead of a GPT?
>
> > In the example below, it is not possible to automatically mount a
> > partition from an MMC card.
> > However, if I add the full paths to the command manually, everything works.
> >
> > barebox 2025.02.0-00690-ga6a0a0ba4f61 #12 Thu Feb 27 08:27:56 MSK 2025
> > Board: Mega-Milas MM-SM-SAMA5D2
> > AT91: Detected soc type: sama5d2
> > AT91: Detected soc subtype: sama5d27c_d1g
> > ...
> > sdhci-at91 b0000000.sdio-host at b0000000.of: registered as mmc1
> > mmc1: detected SD card version 2.0
> > mmc1: registered mmc1
> > ...
> > barebox at Mega-Milas Informer SAMA5D2:/ ls /mnt/mmc1.0
> > mount: Device or resource busy
>
> -EBUSY is a strange error code from mount(). Can you follow where it
> comes from?
>
> I can't reproduce it here. I tried both with a MBR and a GPT.
>
> Sascha
>
>
> --
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Thu Feb 27 23:16:55 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:55 +0100
Subject: [PATCH 07/13] fip: add function to calculate a sha256 over FIP
 image
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-7-4002488ff5ed@pengutronix.de>

This adds fip_sha256() to calculate a sha256 over a FIP image.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 include/fiptool.h |  3 +++
 lib/fip.c         | 23 ++++++++++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/include/fiptool.h b/include/fiptool.h
index bb63a79c16..73b0fbe398 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -38,6 +38,7 @@ struct fip_state {
 	size_t nr_image_descs;
 	int verbose;
 	void *buffer;
+	size_t bufsize;
 	bool buf_no_free;
 };
 
@@ -100,4 +101,6 @@ extern toc_entry_t plat_def_toc_entries[];
 
 struct fip_state *fip_image_open(const char *filename, size_t offset);
 
+int fip_sha256(struct fip_state *fip, char *hash);
+
 #endif /* FIPTOOL_H */
diff --git a/lib/fip.c b/lib/fip.c
index 8086b43412..7a5e3dc844 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -24,6 +24,7 @@
 #include <libfile.h>
 #include <fs.h>
 #include <linux/kernel.h>
+#include <digest.h>
 
 #include <fip.h>
 #include <fiptool.h>
@@ -168,6 +169,7 @@ static int fip_do_parse_buf(struct fip_state *fip, void *buf, size_t size,
 	int terminated = 0;
 
 	fip->buffer = buf;
+	fip->bufsize = size;
 
 	bufend = fip->buffer + size;
 
@@ -570,10 +572,29 @@ struct fip_state *fip_image_open(const char *filename, size_t offset)
 	close(fd);
 
 	return fip_state;
-
 err:
 	close(fd);
 	fip_free(fip_state);
 
 	return ERR_PTR(ret);
 }
+
+int fip_sha256(struct fip_state *fip, char *hash)
+{
+	struct digest *d;
+	int ret;
+
+	d = digest_alloc_by_algo(HASH_ALGO_SHA256);
+	if (!d)
+		return -ENOSYS;
+
+	digest_init(d);
+
+	digest_update(d, fip->buffer, fip->bufsize);
+
+	ret = digest_final(d, hash);
+
+	digest_free(d);
+
+	return ret;
+}

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:53 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:53 +0100
Subject: [PATCH 05/13] fip: rework fip_image_open()
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-5-4002488ff5ed@pengutronix.de>

fip_image_open() used to do all the parsing into a struct fip_state
itself. Instead, only load the FIP image into a buffer and call
fip_do_parse_buf() with this buffer. This has the advantage that we
have all parsing of the FIP image in a single place. Also this helps
with a followup patch which calculates a sha256 over a FIP image
which can easily done when we have the whole FIP image in a contiguous
buffer.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 lib/fip.c | 78 +++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 41 insertions(+), 37 deletions(-)

diff --git a/lib/fip.c b/lib/fip.c
index 23e82098da..aab2795476 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <libfile.h>
 #include <fs.h>
+#include <linux/kernel.h>
 
 #include <fip.h>
 #include <fiptool.h>
@@ -447,22 +448,17 @@ int fip_update(struct fip_state *fip)
 }
 
 /*
- * fip_image_open - open a FIP image for readonly access
+ * fip_image_open - open a FIP image
  * @filename: The filename of the FIP image
  * @offset: The offset of the FIP image in the file
  *
- * This opens a FIP image for readonly access. This is an alternative
- * implementation for fip_parse() with these differences:
+ * This opens a FIP image. This is an alternative implementation for
+ * fip_parse() with these differences:
  * - suitable for reading FIP images from raw partitions. This function
  *   only reads the FIP image, even when the partition is bigger than the
  *   image
  * - Allows to specify an offset within the partition where the FIP image
  *   starts
- * - Do not memdup the images from the full FIP image
- *
- * This function is for easy readonly access to the images within the FIP
- * image. Do not call any of the above FIP manipulation functions other than
- * fip_free() on an image opened with this function.
  */
 struct fip_state *fip_image_open(const char *filename, size_t offset)
 {
@@ -470,11 +466,13 @@ struct fip_state *fip_image_open(const char *filename, size_t offset)
 	int ret;
 	int fd;
 	struct fip_state *fip_state;
-	LIST_HEAD(entries);
 	size_t fip_headers_size, total = 0;
-	struct fip_image_desc *desc;
 	off_t pos;
 	int n_entries = 0;
+	struct fip_toc_entry toc_entries[16];
+	void *buf, *ptr;
+	int i;
+	struct fip_toc_entry *toc_entry;
 
 	fd = open(filename, O_RDONLY);
 	if (fd < 0)
@@ -506,11 +504,9 @@ struct fip_state *fip_image_open(const char *filename, size_t offset)
 
 	/* read all toc entries */
 	while (1) {
-		struct fip_image_desc *desc = xzalloc(sizeof(*desc));
-		struct fip_image *image = xzalloc(sizeof(*image));
-		struct fip_toc_entry *toc_entry = &image->toc_e;
+		uint64_t this_end;
 
-		desc->image = image;
+		toc_entry = &toc_entries[n_entries];
 
 		ret = read_full(fd, toc_entry, sizeof(*toc_entry));
 		if (ret < 0)
@@ -520,53 +516,61 @@ struct fip_state *fip_image_open(const char *filename, size_t offset)
 			goto err;
 		}
 
-		list_add_tail(&desc->list, &fip_state->descs);
-
 		pr_debug("Read TOC entry %pU %llu %llu\n", &toc_entry->uuid,
 			 toc_entry->offset_address, toc_entry->size);
 
-		/* Found the ToC terminator, we are done. */
-		if (uuid_is_null(&toc_entry->uuid))
-			break;
-	}
-
-	/* determine buffer size */
-	fip_for_each_desc(fip_state, desc) {
-		uint64_t this_end = desc->image->toc_e.offset_address + desc->image->toc_e.size;
+		this_end = toc_entry->offset_address + toc_entry->size;
 
 		if (this_end > total)
 			total = this_end;
+
 		n_entries++;
-	}
 
-	fip_headers_size = n_entries * sizeof(struct fip_toc_entry) + sizeof(fip_toc_header_t);
+		if (n_entries >= ARRAY_SIZE(toc_entries)) {
+			ret = -ENOSPC;
+			goto err;
+		}
 
-	total -= fip_headers_size;
+		/* Found the ToC terminator, we are done. */
+		if (uuid_is_null(&toc_entry->uuid))
+			break;
+	}
 
-	fip_state->buffer = malloc(total);
-	if (!fip_state->buffer) {
+	buf = malloc(total);
+	if (!buf) {
 		ret = -ENOMEM;
 		goto err;
 	}
 
-	ret = read_full(fd, fip_state->buffer, total);
+	ptr = buf;
+
+	memcpy(ptr, &toc_header, sizeof(toc_header));
+	ptr += sizeof(toc_header);
+
+	for (i = 0; i < n_entries; i++) {
+		memcpy(ptr, &toc_entries[i], sizeof(*toc_entry));
+		ptr += sizeof(*toc_entry);
+	}
+
+	fip_headers_size = n_entries * sizeof(struct fip_toc_entry) + sizeof(fip_toc_header_t);
+
+	ret = read_full(fd, ptr, total - fip_headers_size);
 	if (ret < 0)
 		goto err;
 
-	if (ret < total) {
+	if (ret < total - fip_headers_size) {
 		ret = -ENODATA;
 		goto err;
 	}
 
-	close(fd);
+	ret = fip_do_parse_buf(fip_state, buf, total, NULL);
+	if (ret)
+		goto err;
 
-	fip_for_each_desc(fip_state, desc) {
-		desc->image->buffer = fip_state->buffer +
-			desc->image->toc_e.offset_address - fip_headers_size;
-		desc->image->buf_no_free = true;
-	}
+	close(fd);
 
 	return fip_state;
+
 err:
 	close(fd);
 	fip_free(fip_state);

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:57 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:57 +0100
Subject: [PATCH 09/13] ARM: k3: add support for authenticating images
 against the ROM API
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-9-4002488ff5ed@pengutronix.de>

This adds support for authenticating an image against the K3 ROM API.
Also included in this patch is a new command for testing the
authentication.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/Kconfig  |  7 ++++
 arch/arm/mach-k3/common.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++
 include/mach/k3/common.h  |  1 +
 3 files changed, 107 insertions(+)

diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig
index 561ad1dac4..37d5155577 100644
--- a/arch/arm/mach-k3/Kconfig
+++ b/arch/arm/mach-k3/Kconfig
@@ -37,4 +37,11 @@ config MACH_BEAGLEPLAY
 	help
 	  Say Y here if you are using a TI AM62x based BeaglePlay board
 
+config ARCH_K3_COMMAND_AUTHENTICATE
+	bool "k3_authenticate_image command"
+	depends on COMMAND_SUPPORT
+	help
+	  Add k3_authenticate_image command to test authenticating images
+	  against the K3 ROM API.
+
 endmenu
diff --git a/arch/arm/mach-k3/common.c b/arch/arm/mach-k3/common.c
index 8dc9d3bc9e..a324e2d5f6 100644
--- a/arch/arm/mach-k3/common.c
+++ b/arch/arm/mach-k3/common.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 #include <of.h>
 #include <io.h>
+#include <dma.h>
 #include <deep-probe.h>
 #include <init.h>
 #include <envfs.h>
@@ -8,11 +9,15 @@
 #include <stdio.h>
 #include <xfuncs.h>
 #include <malloc.h>
+#include <command.h>
+#include <getopt.h>
+#include <libfile.h>
 #include <pm_domain.h>
 #include <bootsource.h>
 #include <linux/bits.h>
 #include <linux/bitfield.h>
 #include <mach/k3/common.h>
+#include <soc/ti/ti_sci_protocol.h>
 
 static const struct of_device_id k3_of_match[] = {
 	{
@@ -334,3 +339,97 @@ static int omap_env_init(void)
 	return 0;
 }
 late_initcall(omap_env_init);
+
+int k3_authenticate_image(void **buf, size_t *size)
+{
+	const struct ti_sci_handle *ti_sci;
+	u64 image_addr;
+	int ret;
+	unsigned int s = *size;
+
+	ti_sci = ti_sci_get_handle(NULL);
+	if (IS_ERR(ti_sci))
+		return -EINVAL;
+
+	image_addr = dma_map_single(NULL, *buf, *size, DMA_BIDIRECTIONAL);
+
+	ret = ti_sci->ops.proc_ops.proc_auth_boot_image(ti_sci, &image_addr, &s);
+
+	dma_unmap_single(NULL, image_addr, *size, DMA_BIDIRECTIONAL);
+
+	if (ret)
+		*size = 0;
+	else
+		*size = s;
+
+	return ret;
+}
+
+#ifdef CONFIG_ARCH_K3_COMMAND_AUTHENTICATE
+static int do_k3_authenticate_image(int argc, char *argv[])
+{
+	void *buf;
+	size_t size;
+	int ret;
+	int opt;
+	const char *outfile = NULL;
+	const char *filename;
+
+	while ((opt = getopt(argc, argv, "o:")) > 0) {
+		switch (opt) {
+		case 'o':
+			outfile = optarg;
+			break;
+		}
+	}
+
+	argc -= optind;
+
+	if (argc == 0)
+		return COMMAND_ERROR_USAGE;
+
+	filename = argv[0];
+
+	ret = read_file_2(filename, &size, &buf, FILESIZE_MAX);
+	if (ret)
+		return ret;
+
+	ret = k3_authenticate_image(&buf, &size);
+	if (ret) {
+		printf("authenticating %s failed: %pe\n", filename, ERR_PTR(ret));
+		ret = COMMAND_ERROR;
+		goto err;
+	}
+
+	printf("%s successfully authenticated\n", filename);
+
+	if (outfile) {
+		ret = write_file(outfile, buf, size);
+		if (ret) {
+			printf("Failed to write output file: %pe\n", ERR_PTR(ret));
+			goto err;
+		}
+	}
+
+	ret = 0;
+err:
+	free(buf);
+
+	return ret;
+}
+
+BAREBOX_CMD_HELP_START(k3_authenticate_image)
+BAREBOX_CMD_HELP_TEXT("Authenticate image with K3 ROM API")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT ("-o <out>",  "store unpacked authenticated image in <out>")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(k3_authenticate_image)
+	.cmd = do_k3_authenticate_image,
+	BAREBOX_CMD_DESC("authenticate file with K3 ROM API")
+	BAREBOX_CMD_OPTS("[-o <out>] file")
+	BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+	BAREBOX_CMD_HELP(k3_authenticate_image)
+BAREBOX_CMD_END
+#endif
diff --git a/include/mach/k3/common.h b/include/mach/k3/common.h
index 871e9f39e3..94c5fba19d 100644
--- a/include/mach/k3/common.h
+++ b/include/mach/k3/common.h
@@ -13,6 +13,7 @@ bool k3_boot_is_emmc(void);
 u64 am625_sdram_size(void);
 void am625_register_dram(void);
 void am625_enable_32k_crystal(void);
+int k3_authenticate_image(void **buf, size_t *size);
 
 #define K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE	SZ_1M
 

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:48 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:48 +0100
Subject: [PATCH 00/13] am625: support secure loading of full barebox
Message-ID: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>

On K3 SoCs only a small barebox is loaded by the ROM into SRAM. This
barebox then loads the full barebox from SD/eMMC or USB DFU. In a secure
boot environment the full barebox must be authenticated. This series
implements two ways for accomplishing this.

First way is to utilize the ROM API to authenticate images. The other
way is to compile a secure hash into the first stage binary and check
if the full barebox image matches the hash. Using the ROM API means
different first stage and second stage images can be combined whereas
hashing binds specific builds together avoiding mix and match attacks.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
Sascha Hauer (13):
      firmware: always generate sha256sum
      firmware: add function to verify next image
      ARM: k3: r5: drop loading of separate binaries
      ARM: k3: r5: add proper error handling
      fip: rework fip_image_open()
      fip: fix wrong function call
      fip: add function to calculate a sha256 over FIP image
      ARM: am625: support hash verification of full barebox
      ARM: k3: add support for authenticating images against the ROM API
      ARM: k3: r5: delete fip image when it can't be opened
      ARM: k3: r5: Allow to authenticate next image by ROM API
      scripts/k3img: remove temporary files
      scripts: add k3sign

 arch/arm/mach-k3/Kconfig  |  15 ++++
 arch/arm/mach-k3/common.c |  99 ++++++++++++++++++++++
 arch/arm/mach-k3/r5.c     | 206 +++++++++++++++++++++++++---------------------
 firmware/Kconfig          |  23 ++++++
 firmware/Makefile         |   8 +-
 include/fiptool.h         |   3 +
 include/firmware.h        |  28 +++++++
 include/mach/k3/common.h  |   1 +
 lib/fip.c                 | 101 ++++++++++++++---------
 scripts/k3img             |   9 +-
 scripts/k3sign            | 126 ++++++++++++++++++++++++++++
 11 files changed, 478 insertions(+), 141 deletions(-)
---
base-commit: 748ba0627681797b01a94be1b3f879ed2e52a361
change-id: 20250228-am625-secure-49301f641738

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Thu Feb 27 23:16:52 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:52 +0100
Subject: [PATCH 04/13] ARM: k3: r5: add proper error handling
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-4-4002488ff5ed@pengutronix.de>

Add missing error handling in the image loading code. Properly check for
errors and panic when mandatory binaries are missing instead of blindly
continuing.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/r5.c | 57 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 31 insertions(+), 26 deletions(-)

diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index 2418e9ae73..e12c888afa 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -283,7 +283,7 @@ static int load_fip(const char *filename, off_t offset)
 	return 0;
 }
 
-static void do_dfu(void)
+static int do_dfu(void)
 {
 	struct usbgadget_funcs funcs = {};
 	int ret;
@@ -293,37 +293,24 @@ static void do_dfu(void)
 	funcs.dfu_opts = "/fip.img(fip)cs";
 
 	ret = usbgadget_prepare_register(&funcs);
-	if (ret)
-		goto err;
+	if (ret) {
+		pr_err("DFU failed with: %pe\n", ERR_PTR(ret));
+		return ret;
+	}
 
 	while (1) {
 		ret = stat("/fip.img", &s);
 		if (!ret) {
 			printf("Downloaded FIP image, DFU done\n");
-			load_fip("/fip.img", 0);
-			break;
+			ret = load_fip("/fip.img", 0);
+			if (!ret)
+				return 0;
 		}
 
 		command_slice_release();
 		mdelay(50);
 		command_slice_acquire();
 	};
-
-	return;
-
-err:
-	pr_err("DFU failed with: %pe\n", ERR_PTR(ret));
-}
-
-static int load_images(void)
-{
-	int err;
-
-	err = load_fip("/boot/k3.fip", 0);
-	if (!err)
-		return 0;
-
-	return 0;
 }
 
 static int load_fip_emmc(void)
@@ -332,6 +319,7 @@ static int load_fip_emmc(void)
 	struct mci *mci;
 	char *fname;
 	const char *mmcdev = "mmc0";
+	int ret;
 
 	device_detect_by_name(mmcdev);
 
@@ -348,11 +336,11 @@ static int load_fip_emmc(void)
 
 	fname = xasprintf("/dev/%s.boot%d", mmcdev, bootpart - 1);
 
-	load_fip(fname, K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE);
+	ret = load_fip(fname, K3_EMMC_BOOTPART_TIBOOT3_BIN_SIZE);
 
 	free(fname);
 
-	return 0;
+	return ret;
 }
 
 static int k3_r5_start_image(void)
@@ -365,11 +353,28 @@ static int k3_r5_start_image(void)
 	struct rproc *arm64_rproc;
 
 	if (IS_ENABLED(CONFIG_USB_GADGET_DFU) && bootsource_get() == BOOTSOURCE_SERIAL)
-		do_dfu();
+		err = do_dfu();
 	else if (k3_boot_is_emmc())
-		load_fip_emmc();
+		err = load_fip_emmc();
 	else
-		load_images();
+		err = load_fip("/boot/k3.fip", 0);
+
+	if (err) {
+		pr_crit("Unable to load FIP image\n");
+		panic("Stop booting\n");
+	}
+
+	if (!have_bl31)
+		panic("No TFA found in FIP image\n");
+
+	if (!have_bl32)
+		pr_info("No OP-TEE found. Continuing without\n");
+
+	if (!have_bl33)
+		panic("No bl33 found in FIP image\n");
+
+	if (!k3_ti_dm)
+		panic("No ti-dm binary found\n");
 
 	ti_sci = ti_sci_get_handle(NULL);
 	if (IS_ERR(ti_sci))

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:51 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:51 +0100
Subject: [PATCH 03/13] ARM: k3: r5: drop loading of separate binaries
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-3-4002488ff5ed@pengutronix.de>

For starting the A52 cores we need TFA, OP-TEE, barebox and ti-dm
binaries. These can be loaded as separate files from SD/eMMC/DFU or
alternatively combined into a single FIP image.
FIP images are convenient to handle, they can easily be generated on the
command line and fiptool also has support for replacing blobs in images.
This makes handling of separate binaries rather unnecessary and support
for it only makes the loading code more complex. Drop it and make FIP
images the only option which also faciliates integrating of secure boot.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/r5.c | 70 +--------------------------------------------------
 1 file changed, 1 insertion(+), 69 deletions(-)

diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index ced1eb2856..2418e9ae73 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -288,50 +288,15 @@ static void do_dfu(void)
 	struct usbgadget_funcs funcs = {};
 	int ret;
 	struct stat s;
-	ssize_t size;
 
 	funcs.flags |= USBGADGET_DFU;
-	funcs.dfu_opts = "/optee.bin(optee)c,"
-			 "/bl31.bin(tfa)c,"
-			 "/ti-dm.bin(ti-dm)c,"
-			 "/barebox.bin(barebox)cs,"
-			 "/fip.img(fip)cs";
+	funcs.dfu_opts = "/fip.img(fip)cs";
 
 	ret = usbgadget_prepare_register(&funcs);
 	if (ret)
 		goto err;
 
 	while (1) {
-		if (!have_bl32) {
-			size = read_file_into_buf("/optee.bin", BL32_ADDRESS, SZ_32M);
-			if (size > 0) {
-				printf("Downloaded OP-TEE\n");
-				have_bl32 = true;
-			}
-		}
-
-		if (!have_bl31) {
-			size = read_file_into_buf("/bl31.bin", BL31_ADDRESS, SZ_32M);
-			if (size > 0) {
-				printf("Downloaded TF-A\n");
-				have_bl31 = true;
-			}
-		}
-
-		if (!k3_ti_dm) {
-			ret = read_file_2("/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
-			if (!ret) {
-				printf("Downloaded TI-DM\n");
-			}
-		}
-
-		size = read_file_into_buf("/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
-		if (size > 0) {
-			have_bl33 = true;
-			printf("Downloaded barebox image, DFU done\n");
-			break;
-		}
-
 		ret = stat("/fip.img", &s);
 		if (!ret) {
 			printf("Downloaded FIP image, DFU done\n");
@@ -352,45 +317,12 @@ static void do_dfu(void)
 
 static int load_images(void)
 {
-	ssize_t size;
 	int err;
 
 	err = load_fip("/boot/k3.fip", 0);
 	if (!err)
 		return 0;
 
-	size = read_file_into_buf("/boot/optee.bin", BL32_ADDRESS, SZ_32M);
-	if (size < 0) {
-		if (size != -ENOENT) {
-			pr_err("Cannot load optee.bin: %pe\n", ERR_PTR(size));
-			return size;
-		}
-		pr_info("optee.bin not found, continue without\n");
-	} else {
-		pr_debug("Loaded optee.bin (size %u) to 0x%p\n", size, BL32_ADDRESS);
-	}
-
-	size = read_file_into_buf("/boot/barebox.bin", BAREBOX_ADDRESS, SZ_32M);
-	if (size < 0) {
-		pr_err("Cannot load barebox.bin: %pe\n", ERR_PTR(size));
-		return size;
-	}
-	pr_debug("Loaded barebox.bin (size %u) to 0x%p\n", size, BAREBOX_ADDRESS);
-
-	size = read_file_into_buf("/boot/bl31.bin", BL31_ADDRESS, SZ_32M);
-	if (size < 0) {
-		pr_err("Cannot load bl31.bin: %pe\n", ERR_PTR(size));
-		return size;
-	}
-	pr_debug("Loaded bl31.bin (size %u) to 0x%p\n", size, BL31_ADDRESS);
-
-	err = read_file_2("/boot/ti-dm.bin", &size, &k3_ti_dm, FILESIZE_MAX);
-	if (err) {
-		pr_err("Cannot load ti-dm.bin: %pe\n", ERR_PTR(err));
-		return err;
-	}
-	pr_debug("Loaded ti-dm.bin (size %u)\n", size);
-
 	return 0;
 }
 

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:50 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:50 +0100
Subject: [PATCH 02/13] firmware: add function to verify next image
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-2-4002488ff5ed@pengutronix.de>

Some SoCs use a startup sequence that includes multiple stages where a
full barebox is loaded by an early small barebox that fits into the
SoC's SRAM. This is commonly referred to as xload. In a secure boot
environment it's necessary to load only trusted barebox images. One
way to accomplish this is to compile a sha256 into the first stage
barebox and to verify the full barebox against this hash.

This patch adds the generic parts for this. The full barebox binary
can be put into the first stage build as a firmware file. The firmware
itself won't be used, only the hash is compiled into the image. SoC
code can then check the full barebox image against the hash. As this
requires SoC code to check the hash, the option is hidden behind
CONFIG_HAVE_FIRMWARE_VERIFY_NEXT_IMAGE. SoC code can select this option
when it implements the required hash checking.

It's worth noting that using a hash for verification has one advantage
over cryptographicaly signing followup images: It ties first stage
and full barebox stages together effectively avoiding mix-and-match
attacks.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 firmware/Kconfig   | 23 +++++++++++++++++++++++
 firmware/Makefile  |  2 ++
 include/firmware.h | 28 ++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)

diff --git a/firmware/Kconfig b/firmware/Kconfig
index ba005976c5..bdb71321bc 100644
--- a/firmware/Kconfig
+++ b/firmware/Kconfig
@@ -108,4 +108,27 @@ config FIRMWARE_LS1028A_ATF
 config FIRMWARE_LS1046A_ATF
 	bool
 
+config HAVE_FIRMWARE_VERIFY_NEXT_IMAGE
+	bool
+
+config FIRMWARE_VERIFY_NEXT_IMAGE
+	depends on HAVE_FIRMWARE_VERIFY_NEXT_IMAGE
+	bool "verify next image to load"
+	help
+	  The boot process of some SoCs uses multiple stages where the first stage is
+	  a stripped down barebox loaded by the SoC's ROM and the next state is a full
+	  barebox loaded by the first stage. In a trusted boot scenario the next stage
+	  has to be verified by the first stage,
+
+	  This option allows to specify the next image to be loaded. Put the next stage
+	  image to firmware/next-image.bin. The image itself is not used, but a sha256
+	  hash of the image will be generated and compiled into the first stage which
+	  can be used to verify the next stage.
+
+	  Note that this option only enabled generation of the sha256 hash. Loading and
+	  starting the next stage is highly SoC dependent and it's the SoC code's
+	  responsibility to actually verify the hash and to only start successfully
+	  verified images. The function to check the next stage image hash is
+	  firmware_next_image_verify(), make sure your SoC code uses it.
+
 endmenu
diff --git a/firmware/Makefile b/firmware/Makefile
index 095d6f0e31..67fd898890 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -34,6 +34,8 @@ pbl-firmware-$(CONFIG_ARCH_RK3588) += rk3588-bl32.bin
 pbl-firmware-$(CONFIG_ARCH_RK3399) += rk3399-bl32.bin
 endif
 
+firmware-$(CONFIG_FIRMWARE_NEXT_IMAGE) += next-image.bin
+
 firmware-$(CONFIG_DRIVER_NET_FSL_FMAN) += fsl_fman_ucode_ls1046_r1.0_106_4_18.bin
 
 fw-external-$(CONFIG_FIRMWARE_LS1028A_ATF) += ls1028a-bl31.bin
diff --git a/include/firmware.h b/include/firmware.h
index d7feae1371..7225b55e4f 100644
--- a/include/firmware.h
+++ b/include/firmware.h
@@ -13,6 +13,8 @@
 #include <debug_ll.h>
 #include <linux/kernel.h>
 #include <asm/sections.h>
+#include <crypto/sha.h>
+#include <crypto.h>
 
 struct firmware {
 	size_t size;
@@ -113,4 +115,30 @@ static inline void firmware_ext_verify(const void *data_start, size_t data_size,
 #define get_builtin_firmware_ext(name, base, start, size)		\
 	__get_builtin_firmware(name, (long)base - (long)_text, start, size)
 
+static inline int firmware_next_image_verify(const void *hash_start, size_t hash_size, bool verbose)
+{
+	extern char _fw_next_image_bin_sha_start[];
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_FIRMWARE_NEXT_IMAGE))
+		return -EINVAL;
+
+	if (hash_size != SHA256_DIGEST_SIZE)
+		return -EINVAL;
+
+	ret = crypto_memneq(hash_start, _fw_next_image_bin_sha_start, hash_size);
+
+	if (verbose) {
+		if (ret) {
+			pr_err("next image hash mismatch!\n");
+			pr_err("expected: sha256=%*phN\n", hash_size, _fw_next_image_bin_sha_start);
+			pr_err("found:    sha256=%*phN\n", hash_size, hash_start);
+		} else {
+			pr_info("hash sha256=%*phN OK\n", hash_size, _fw_next_image_bin_sha_start);
+		}
+	}
+
+	return ret;
+}
+
 #endif /* FIRMWARE_H */

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:54 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:54 +0100
Subject: [PATCH 06/13] fip: fix wrong function call
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-6-4002488ff5ed@pengutronix.de>

fip_parse_buf() is to be called when a buffer shall be parsed that is
allocated externally and thus shall not be freed in fip_free(). This
is not what we want in fip_parse(), we want exactly the buffer to be
freed, so call fip_do_parse_buf() instead.

Fixes: 748ba06276 ("fip: add function to parse FIP from a buffer")
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 lib/fip.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/fip.c b/lib/fip.c
index aab2795476..8086b43412 100644
--- a/lib/fip.c
+++ b/lib/fip.c
@@ -274,7 +274,7 @@ int fip_parse(struct fip_state *fip,
 		return ret;
 	}
 
-	ret = fip_parse_buf(fip, buf, size, toc_header_out);
+	ret = fip_do_parse_buf(fip, buf, size, toc_header_out);
 
 	if (ret)
 		free(buf);

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:49 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:49 +0100
Subject: [PATCH 01/13] firmware: always generate sha256sum
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-1-4002488ff5ed@pengutronix.de>

Right now we only generate the sha256 for firmware files that are
loaded from an external binary. Instead, always generate the sha256
which helps with upcoming support for checking the next image hash.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 firmware/Makefile | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/firmware/Makefile b/firmware/Makefile
index 4cf61587d6..095d6f0e31 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -76,9 +76,6 @@ filechk_fwbin = { \
 	echo "_fwname_$(FWSTR):"				;\
 	printf '.ascii "%s"\n' 'firmware/$(FWNAME)\n'		;\
 	echo "\#endif" 						;\
-}
-
-__fwbin_sha = { \
 	echo "    .section .rodata.$(FWSTR).sha"		;\
 	echo "    .p2align ASM_LGPTR"				;\
 	echo ".global _fw_$(FWSTR)_sha_start"			;\
@@ -90,10 +87,9 @@ __fwbin_sha = { \
 
 filechk_fwbin_ext = { \
 	$(filechk_fwbin)					;\
-	$(__fwbin_sha)						;\
 }
 
-$(obj)/%.gen.S: FORCE
+$(obj)/%.gen.S: $(obj)/%.sha.bin FORCE
 	$(call filechk,fwbin,.rodata.$(FWSTR),)
 
 $(obj)/%.extgen.S: $(obj)/%.sha.bin FORCE

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:56 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:56 +0100
Subject: [PATCH 08/13] ARM: am625: support hash verification of full
 barebox
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-8-4002488ff5ed@pengutronix.de>

This implements the necessary SoC code to check the full barebox against
a sha256 compiled into the first stage barebox.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/Kconfig |  1 +
 arch/arm/mach-k3/r5.c    | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig
index 50919dc7e3..561ad1dac4 100644
--- a/arch/arm/mach-k3/Kconfig
+++ b/arch/arm/mach-k3/Kconfig
@@ -16,6 +16,7 @@ config MACH_K3_CORTEX_R5
 	select ELF
 	select K3_DDRSS
 	select FIP
+	select HAVE_FIRMWARE_VERIFY_NEXT_IMAGE
 	depends on 32BIT
 	select ARM_USE_COMPRESSED_DTB
 	default y
diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index e12c888afa..cb52ff364d 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -248,6 +248,8 @@ static int load_fip(const char *filename, off_t offset)
 {
 	struct fip_state *fip;
 	struct fip_image_desc *desc;
+	unsigned char shasum[SHA256_DIGEST_SIZE];
+	int ret;
 
 	fip = fip_image_open(filename, offset);
 	if (IS_ERR(fip)) {
@@ -255,6 +257,18 @@ static int load_fip(const char *filename, off_t offset)
 		return PTR_ERR(fip);
 	}
 
+	if (IS_ENABLED(CONFIG_FIRMWARE_VERIFY_NEXT_IMAGE)) {
+		ret = fip_sha256(fip, shasum);
+		if (ret) {
+			pr_err("Cannot calc fip sha256: %pe\n", ERR_PTR(ret));
+			return ret;
+		}
+
+		ret = firmware_next_image_verify(shasum, SHA256_DIGEST_SIZE, true);
+		if (ret)
+			return ret;
+	}
+
 	fip_for_each_desc(fip, desc) {
 		struct fip_toc_entry *toc_entry = &desc->image->toc_e;
 

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:17:00 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:17:00 +0100
Subject: [PATCH 12/13] scripts/k3img: remove temporary files
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-12-4002488ff5ed@pengutronix.de>

Remove temporary files when exiting the script. While at it add a "set
-e" to exit the script when a command fails.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 scripts/k3img | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/scripts/k3img b/scripts/k3img
index 048da82b92..a514852fcd 100755
--- a/scripts/k3img
+++ b/scripts/k3img
@@ -1,5 +1,7 @@
 #!/bin/bash
 
+set -e
+
 TEMP=$(getopt -o '' --long 'sysfw:,sysfwdata:,dmdata:,out:,sbl:,key:,innerdata:' -n 'k3img' -- "$@")
 
 if [ $? -ne 0 ]; then
@@ -76,8 +78,11 @@ dmdatasize=$(stat -c%s $dmdata)
 
 total=$(($sblsize + $sysfwsize + $sysfwdatasize + $dmdatasize))
 
-certcfg=$(mktemp k3img.XXXXXXX)
-cert=$(mktemp k3img.XXXXXXX)
+TMPDIR="$(mktemp -d)"
+trap 'rm -rf -- "$TMPDIR"' EXIT
+
+certcfg=${TMPDIR}/certcfg
+cert=${TMPDIR}/cert
 
 num_comp=4
 

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:17:01 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:17:01 +0100
Subject: [PATCH 13/13] scripts: add k3sign
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-13-4002488ff5ed@pengutronix.de>

This adds k3sign which is a small example script to generate a
certificate from an input file suitable for verification against the K3
ROM API.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 scripts/k3sign | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/scripts/k3sign b/scripts/k3sign
new file mode 100755
index 0000000000..df66501eee
--- /dev/null
+++ b/scripts/k3sign
@@ -0,0 +1,126 @@
+#!/bin/bash
+
+set -e
+
+myname=${0##*/}
+
+usage() {
+	cat >&2 << EOL
+
+Sign an image suitable for authenticating with the K3 ROM API
+Usage:
+$myname options <INFILE>
+options:
+	--key <KEYFILE>	The key to sign the image with
+	--out <OUTFILE>	Write output to OUTFILE
+	--help		This help
+EOL
+	exit 1
+}
+
+TEMP=$(getopt -o '' --long 'out:,key:,help' -n 'k3img' -- "$@")
+
+if [ $? -ne 0 ]; then
+	echo 'Terminating...' >&2
+	exit 1
+fi
+
+# Note the quotes around "$TEMP": they are essential!
+eval set -- "$TEMP"
+unset TEMP
+
+while true; do
+        case "$1" in
+	'--out')
+		out="$2"
+		shift 2
+		continue
+	;;
+	'--key')
+		key="$2"
+		shift 2
+		continue
+	;;
+	'--help')
+		usage
+		continue
+	;;
+	'--')
+		shift
+		break
+	;;
+	*)
+		echo 'Internal error!' >&2
+		exit 1
+	;;
+	esac
+done
+
+if [ $# = 0 ]; then
+	echo "No input file given"
+	usage
+fi
+
+in=$1
+
+if [ -z "$out" ]; then
+	out=$in.cert
+fi
+
+if [ -z "$key" ]; then
+	echo "No key given (--key)"
+	exit 1
+fi
+
+filesha=$(sha512sum $in | sed 's/ .*//')
+filesize=$(stat -c%s $in)
+
+TMPDIR="$(mktemp -d)"
+trap 'rm -rf -- "$TMPDIR"' EXIT
+
+certcfg=${TMPDIR}/certcfg
+cert=${TMPDIR}/cert
+
+cat > $certcfg <<EndOfHereDocument
+[ req ]
+distinguished_name     = req_distinguished_name
+x509_extensions        = v3_ca
+prompt                 = no
+dirstring_type         = nobmp
+
+[ req_distinguished_name ]
+C                      = US
+ST                     = TX
+L                      = Dallas
+O                      = Texas Instruments Incorporated
+OU                     = Processors
+CN                     = TI Support
+emailAddress           = support at ti.com
+
+[ v3_ca ]
+basicConstraints       = CA:true
+1.3.6.1.4.1.294.1.3    = ASN1:SEQUENCE:swrv
+1.3.6.1.4.1.294.1.34   = ASN1:SEQUENCE:sysfw_image_integrity
+1.3.6.1.4.1.294.1.35   = ASN1:SEQUENCE:sysfw_image_load
+1.3.6.1.4.1.294.1.37   = ASN1:SEQUENCE:firewall
+
+[ swrv ]
+swrv = INTEGER:1
+
+[ sysfw_image_integrity ]
+shaType                = OID:2.16.840.1.101.3.4.2.3
+shaValue               = FORMAT:HEX,OCT:$filesha
+imageSize              = INTEGER:$filesize
+
+[ sysfw_image_load ]
+destAddr = FORMAT:HEX,OCT:00000000
+authInPlace = INTEGER:0x2
+
+[ firewall ]
+numFirewallRegions = INTEGER:0
+
+EndOfHereDocument
+
+openssl req -new -x509 -key $key -nodes -outform DER -out $cert -config $certcfg -sha512
+
+cat $cert $in > $out

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:58 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:58 +0100
Subject: [PATCH 10/13] ARM: k3: r5: delete fip image when it can't be
 opened
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-10-4002488ff5ed@pengutronix.de>

In case the uploaded FIP image can't be opened due to corruption of
the image we end up in an endless loop trying to open the same image
again and again. Delete the uploaded image in this case to give the
user a chance to upload another image.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/r5.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index cb52ff364d..c8a91e2597 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -319,6 +319,7 @@ static int do_dfu(void)
 			ret = load_fip("/fip.img", 0);
 			if (!ret)
 				return 0;
+			unlink("/fip.img");
 		}
 
 		command_slice_release();

-- 
2.39.5



From s.hauer at pengutronix.de  Thu Feb 27 23:16:59 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 08:16:59 +0100
Subject: [PATCH 11/13] ARM: k3: r5: Allow to authenticate next image by ROM
 API
In-Reply-To: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
References: <20250228-am625-secure-v1-0-4002488ff5ed@pengutronix.de>
Message-ID: <20250228-am625-secure-v1-11-4002488ff5ed@pengutronix.de>

This adds the Kconfig option CONFIG_ARCH_K3_AUTHENTICATE_IMAGE. When
enabled, the full barebox image will only be started when it can be
authenticated using the ROM API.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 arch/arm/mach-k3/Kconfig |  7 ++++++
 arch/arm/mach-k3/r5.c    | 64 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-k3/Kconfig b/arch/arm/mach-k3/Kconfig
index 37d5155577..e93e3154c8 100644
--- a/arch/arm/mach-k3/Kconfig
+++ b/arch/arm/mach-k3/Kconfig
@@ -37,6 +37,13 @@ config MACH_BEAGLEPLAY
 	help
 	  Say Y here if you are using a TI AM62x based BeaglePlay board
 
+config ARCH_K3_AUTHENTICATE_IMAGE
+	bool "Force authentication of FIP image against ROM API"
+	help
+	  By enabling this option the FIP image loaded by the first stage
+	  will be authenticated against the K3 ROM API. Images which fail
+	  to authenticate will not be started.
+
 config ARCH_K3_COMMAND_AUTHENTICATE
 	bool "k3_authenticate_image command"
 	depends on COMMAND_SUPPORT
diff --git a/arch/arm/mach-k3/r5.c b/arch/arm/mach-k3/r5.c
index c8a91e2597..d0093a3be7 100644
--- a/arch/arm/mach-k3/r5.c
+++ b/arch/arm/mach-k3/r5.c
@@ -244,6 +244,64 @@ static uuid_t uuid_ti_dm_fw = UUID_TI_DM_FW;
 static uuid_t uuid_bl33 = UUID_NON_TRUSTED_FIRMWARE_BL33;
 static uuid_t uuid_bl32 = UUID_SECURE_PAYLOAD_BL32;
 
+static struct fip_state *fip_image_load_auth(const char *filename, size_t offset)
+{
+	struct fip_state *fip = NULL;
+	int fd;
+	unsigned int maxsize = SZ_4M;
+	size_t size;
+	void *buf = NULL;
+	int ret;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return ERR_PTR(-errno);
+
+	if (offset) {
+		loff_t pos;
+		pos = lseek(fd, offset, SEEK_SET);
+		if (pos < 0) {
+			ret = -errno;
+			goto err;
+		}
+	}
+
+	buf = xzalloc(maxsize);
+
+	/*
+	 * There is no easy way to determine the size of the certificates the ROM
+	 * takes as images, so the best we can do here is to assume a maximum size
+	 * and load this.
+	 */
+	ret = read_full(fd, buf, maxsize);
+	if (ret < 0)
+		goto err;
+
+	size = maxsize;
+
+	ret = k3_authenticate_image(&buf, &size);
+	if (ret) {
+		pr_err("Failed to authenticate %s\n", filename);
+		goto err;
+	}
+
+	fip = fip_new();
+	ret = fip_parse_buf(fip, buf, size, NULL);
+	if (ret)
+		goto err;
+
+	close(fd);
+
+	return fip;
+err:
+	if (fip)
+		fip_free(fip);
+	close(fd);
+	free(buf);
+
+	return ERR_PTR(ret);
+}
+
 static int load_fip(const char *filename, off_t offset)
 {
 	struct fip_state *fip;
@@ -251,7 +309,11 @@ static int load_fip(const char *filename, off_t offset)
 	unsigned char shasum[SHA256_DIGEST_SIZE];
 	int ret;
 
-	fip = fip_image_open(filename, offset);
+	if (IS_ENABLED(CONFIG_ARCH_K3_AUTHENTICATE_IMAGE))
+		fip = fip_image_load_auth(filename, offset);
+	else
+		fip = fip_image_open(filename, offset);
+
 	if (IS_ERR(fip)) {
 		pr_err("Cannot open FIP image: %pe\n", fip);
 		return PTR_ERR(fip);

-- 
2.39.5



From s.hauer at pengutronix.de  Fri Feb 28 00:02:14 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 09:02:14 +0100
Subject: [PATCH] barebox-environment: Use default mount path
Message-ID: <20250228080214.1319495-1-s.hauer@pengutronix.de>

When using a file inside a partition for the barebox environment we
mount the partition to a non standard path ("/boot") which can cause
problems with autmounting. Mount the partition to the standard location
and create a symlink from /boot to the mounted path.

Reported-by: Alexander Shiyan <eagle.alexander923 at gmail.com>
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/of/barebox.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/drivers/of/barebox.c b/drivers/of/barebox.c
index e6bcff7116..e52cdcf52a 100644
--- a/drivers/of/barebox.c
+++ b/drivers/of/barebox.c
@@ -35,7 +35,9 @@ static char *environment_probe_2node_binding(struct device *dev)
 {
 	const char *filepath;
 	char *devpath = NULL;
+	const char *path = NULL;
 	int ret;
+	struct cdev *cdev;
 
 	ret = of_find_path(dev->of_node, "device-path", &devpath,
 			   OF_FIND_PATH_FLAGS_BB);
@@ -55,22 +57,31 @@ static char *environment_probe_2node_binding(struct device *dev)
 		goto out;
 	}
 
-	/* Get device env is on and mount it */
-	mkdir(ENV_MNT_DIR, 0777);
-	ret = mount(devpath, "fat", ENV_MNT_DIR, NULL);
-	if (ret) {
-		dev_err(dev, "Failed to load environment: mount %s failed (%d)\n",
-			devpath, ret);
+	cdev = cdev_by_name(kbasename(devpath));
+	if (!cdev) {
+		dev_err(dev, "Cannot find device for %s\n", devpath);
+		ret = -ENOENT;
 		goto out;
 	}
 
+	path = cdev_mount_default(cdev, NULL);
+	if (IS_ERR(path)) {
+		dev_err(dev, "Cannot mount %s\n", devpath);
+		ret = PTR_ERR(path);
+		goto out;
+	}
+
+	symlink(path, ENV_MNT_DIR);
+
 	/* Set env to be in a file on the now mounted device */
 	dev_dbg(dev, "Loading default env from %s on device %s\n",
 		filepath, devpath);
 
+	ret = 0;
+
 out:
 	free(devpath);
-	return ret ? ERR_PTR(ret) : basprintf("%s/%s", ENV_MNT_DIR, filepath);
+	return ret ? ERR_PTR(ret) : basprintf("%s/%s", path, filepath);
 }
 
 static int environment_probe(struct device *dev)
-- 
2.39.5



From s.hauer at pengutronix.de  Fri Feb 28 00:05:14 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 09:05:14 +0100
Subject: automount doesn't work without GPT table
In-Reply-To: <CAP1tNvQFhZHobkaYL_v9aQ8FAqEtd--pkGxW3C6v81zMUaM-PQ@mail.gmail.com>
References: <CAP1tNvToG8WGLUo4_e2dSdovFZBAbcdOFUqm+F+W4gWoaVnrgQ@mail.gmail.com>
 <Z8CaS4gLesWjG81q@pengutronix.de>
 <CAP1tNvQFhZHobkaYL_v9aQ8FAqEtd--pkGxW3C6v81zMUaM-PQ@mail.gmail.com>
Message-ID: <Z8FuOsc_Eg-p6zCJ@pengutronix.de>

On Fri, Feb 28, 2025 at 09:06:55AM +0300, Alexander Shiyan wrote:
> Hello Sascha.
> 
> The error occurs in the cdev_mount_default() function.
> cdev_get_mount_path() returns "/boot".
> And indeed, the partition is mounted here for some reason...
> I don't understand yet why this happens.
> 
> barebox at Mega-Milas Informer SAMA5D2:/ mount
> none on / type ramfs
> none on /dev type devfs
> /dev/mmc1.0 on /boot type fat
> 
> Update:
> I found that this happens if the CONFIG_OF_BAREBOX_ENV_IN_FS option is used.
> When disabled, mounting occurs as expected, but in this case I cannot
> use environments from a file from a partition on the SD card.
> It is not yet clear how to get out of this situation...

Ok, so the partition is already mounted for the environment to /boot, so
you get -EBUSY when trying to automount it somewhere else.

The question arises why you want to access it via automount when you
already mounted it for your environment.

Anyway, maybe we can do better by just mounting the partition to its
standard location the autmount would use anyway and just create a
symlink from /boot to /mnt/mmc1.0. I just sent a patch for this, you
could give it a try.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From eagle.alexander923 at gmail.com  Fri Feb 28 00:18:44 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Fri, 28 Feb 2025 11:18:44 +0300
Subject: automount doesn't work without GPT table
In-Reply-To: <Z8FuOsc_Eg-p6zCJ@pengutronix.de>
References: <CAP1tNvToG8WGLUo4_e2dSdovFZBAbcdOFUqm+F+W4gWoaVnrgQ@mail.gmail.com>
 <Z8CaS4gLesWjG81q@pengutronix.de> <CAP1tNvQFhZHobkaYL_v9aQ8FAqEtd--pkGxW3C6v81zMUaM-PQ@mail.gmail.com>
 <Z8FuOsc_Eg-p6zCJ@pengutronix.de>
Message-ID: <CAP1tNvTG-Na4pCD0qqh=hm647=UkQ7CzEFFHztgzHcq3m1bh=w@mail.gmail.com>

Hello.

> > The error occurs in the cdev_mount_default() function.
> > cdev_get_mount_path() returns "/boot".
> > And indeed, the partition is mounted here for some reason...
> > I don't understand yet why this happens.
> >
> > barebox at Mega-Milas Informer SAMA5D2:/ mount
> > none on / type ramfs
> > none on /dev type devfs
> > /dev/mmc1.0 on /boot type fat
> >
> > Update:
> > I found that this happens if the CONFIG_OF_BAREBOX_ENV_IN_FS option is used.
> > When disabled, mounting occurs as expected, but in this case I cannot
> > use environments from a file from a partition on the SD card.
> > It is not yet clear how to get out of this situation...
>
> Ok, so the partition is already mounted for the environment to /boot, so
> you get -EBUSY when trying to automount it somewhere else.
>
> The question arises why you want to access it via automount when you
> already mounted it for your environment.

Mounting the FULL partition with the environment file to /boot was a
surprise to me :)
I just expected the usual behavior of the automount command.

Thanks!


From eagle.alexander923 at gmail.com  Fri Feb 28 00:19:01 2025
From: eagle.alexander923 at gmail.com (Alexander Shiyan)
Date: Fri, 28 Feb 2025 11:19:01 +0300
Subject: [PATCH] barebox-environment: Use default mount path
In-Reply-To: <20250228080214.1319495-1-s.hauer@pengutronix.de>
References: <20250228080214.1319495-1-s.hauer@pengutronix.de>
Message-ID: <CAP1tNvQ95MoXMdW1KK=23rS7kD6w=1Q49-v9WNfyuX1yo+Humg@mail.gmail.com>

Tested-by: Alexander Shiyan <eagle.alexander923 at gmail.com>

??, 28 ????. 2025??. ? 11:02, Sascha Hauer <s.hauer at pengutronix.de>:
>
> When using a file inside a partition for the barebox environment we
> mount the partition to a non standard path ("/boot") which can cause
> problems with autmounting. Mount the partition to the standard location
> and create a symlink from /boot to the mounted path.
>
> Reported-by: Alexander Shiyan <eagle.alexander923 at gmail.com>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> ---
>  drivers/of/barebox.c | 25 ++++++++++++++++++-------
>  1 file changed, 18 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/of/barebox.c b/drivers/of/barebox.c
> index e6bcff7116..e52cdcf52a 100644
> --- a/drivers/of/barebox.c
> +++ b/drivers/of/barebox.c
> @@ -35,7 +35,9 @@ static char *environment_probe_2node_binding(struct device *dev)
>  {
>         const char *filepath;
>         char *devpath = NULL;
> +       const char *path = NULL;
>         int ret;
> +       struct cdev *cdev;
>
>         ret = of_find_path(dev->of_node, "device-path", &devpath,
>                            OF_FIND_PATH_FLAGS_BB);
> @@ -55,22 +57,31 @@ static char *environment_probe_2node_binding(struct device *dev)
>                 goto out;
>         }
>
> -       /* Get device env is on and mount it */
> -       mkdir(ENV_MNT_DIR, 0777);
> -       ret = mount(devpath, "fat", ENV_MNT_DIR, NULL);
> -       if (ret) {
> -               dev_err(dev, "Failed to load environment: mount %s failed (%d)\n",
> -                       devpath, ret);
> +       cdev = cdev_by_name(kbasename(devpath));
> +       if (!cdev) {
> +               dev_err(dev, "Cannot find device for %s\n", devpath);
> +               ret = -ENOENT;
>                 goto out;
>         }
>
> +       path = cdev_mount_default(cdev, NULL);
> +       if (IS_ERR(path)) {
> +               dev_err(dev, "Cannot mount %s\n", devpath);
> +               ret = PTR_ERR(path);
> +               goto out;
> +       }
> +
> +       symlink(path, ENV_MNT_DIR);
> +
>         /* Set env to be in a file on the now mounted device */
>         dev_dbg(dev, "Loading default env from %s on device %s\n",
>                 filepath, devpath);
>
> +       ret = 0;
> +
>  out:
>         free(devpath);
> -       return ret ? ERR_PTR(ret) : basprintf("%s/%s", ENV_MNT_DIR, filepath);
> +       return ret ? ERR_PTR(ret) : basprintf("%s/%s", path, filepath);
>  }
>
>  static int environment_probe(struct device *dev)
> --
> 2.39.5
>


From s.hauer at pengutronix.de  Fri Feb 28 01:44:45 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 10:44:45 +0100
Subject: [PATCH] fix partuuid format
In-Reply-To: <AS4PR08MB8093429FE84A32C579C03FE69EC22@AS4PR08MB8093.eurprd08.prod.outlook.com>
References: <AS4PR08MB8093429FE84A32C579C03FE69EC22@AS4PR08MB8093.eurprd08.prod.outlook.com>
Message-ID: <174073588549.1400807.11147703567146583574.b4-ty@pengutronix.de>


On Wed, 26 Feb 2025 14:29:48 +0000, Oliver ROHE wrote:
> root=PARTUUID=SSSSSSSS-PP
> 
> Where SSSSSSSS is a zero-filled 32-bit MBR disk signature,
> and PP is a zero-filled partition number in hexadecimal format.
> 
> 

Applied, thanks!

[1/1] fix partuuid format
      https://git.pengutronix.de/cgit/barebox/commit/?id=faa88fc2d97b (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 28 01:46:38 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 10:46:38 +0100
Subject: [PATCH] fix partuuid format
In-Reply-To: <AS4PR08MB8093429FE84A32C579C03FE69EC22@AS4PR08MB8093.eurprd08.prod.outlook.com>
References: <AS4PR08MB8093429FE84A32C579C03FE69EC22@AS4PR08MB8093.eurprd08.prod.outlook.com>
Message-ID: <Z8GF_npuAubAt7Jg@pengutronix.de>

Hi Oliver,

On Wed, Feb 26, 2025 at 02:29:48PM +0000, Oliver ROHE wrote:
> root=PARTUUID=SSSSSSSS-PP
> 
> Where SSSSSSSS is a zero-filled 32-bit MBR disk signature,
> and PP is a zero-filled partition number in hexadecimal format.

Thanks for fixing this. This doesn't seem to be documented in Linux, so
I digged in the code and added this to the commit message:

| This is not explicitly documented in Linux, but can be seen in [1].
| 
| [1] https://github.com/torvalds/linux/blob/76544811c850a1f4c055aa182b513b7a843868ea/block/partitions/msdos.c#L108

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Fri Feb 28 01:47:09 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 10:47:09 +0100
Subject: [PATCH] i.mx8: ocotp: add GPx defines
In-Reply-To: <20250225-imx8-ocotp-gp-defines-v1-1-344b291675a7@pengutronix.de>
References: <20250225-imx8-ocotp-gp-defines-v1-1-344b291675a7@pengutronix.de>
Message-ID: <174073602993.1401123.3995544501767465635.b4-ty@pengutronix.de>


On Tue, 25 Feb 2025 11:56:40 +0100, Stefan Kerkmann wrote:
> The general purpose GPx registers changed position in the fuse map from
> the i.MX6 series and derivates to the i.MX8 series. The i.MX8MP has 4
> additional 128-bit wide fuse banks which have been added as well.
> 
> The defines have been derived from:
> 
> IMX8MNRM Rev. 2 (i.MX8MN)
> IMX8MPRM Rev. 3 (i.MX8MP)
> IMX8MMRM Rev. 3 (i.MX8MM)
> 
> [...]

Applied, thanks!

[1/1] i.mx8: ocotp: add GPx defines
      https://git.pengutronix.de/cgit/barebox/commit/?id=13019e9b6a49 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 28 01:48:36 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 10:48:36 +0100
Subject: [PATCH] parted: add partition type msdos to help text
Message-ID: <20250228094836.1401338-1-s.hauer@pengutronix.de>

Partition type can be either "gpt" or "msdos", but only the former was
listed in the help text. Add the latter.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 commands/parted.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/commands/parted.c b/commands/parted.c
index 6af18cdc57..68b056a075 100644
--- a/commands/parted.c
+++ b/commands/parted.c
@@ -359,7 +359,7 @@ BAREBOX_CMD_HELP_OPT ("refresh", "refresh a partition table")
 BAREBOX_CMD_HELP_TEXT("")
 BAREBOX_CMD_HELP_TEXT("<unit> can be one of \"s\" (sectors), \"B\" (bytes), \"kB\", \"MB\", \"GB\", \"TB\",")
 BAREBOX_CMD_HELP_TEXT("\"KiB\", \"MiB\", \"GiB\" or \"TiB\"")
-BAREBOX_CMD_HELP_TEXT("<type> must be \"gpt\"")
+BAREBOX_CMD_HELP_TEXT("<type> must be \"gpt\" or \"msdos\"")
 BAREBOX_CMD_HELP_TEXT("<fstype> can be one of  \"ext2\", \"ext3\", \"ext4\", \"fat16\", \"fat32\" or \"bbenv\"")
 BAREBOX_CMD_HELP_TEXT("<name> for MBR partition tables can be one of \"primary\", \"extended\" or")
 BAREBOX_CMD_HELP_TEXT("\"logical\". For GPT this is a name string.")
-- 
2.39.5



From s.hauer at pengutronix.de  Fri Feb 28 02:57:02 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 11:57:02 +0100
Subject: Mount NFSv4.2 filesystem in barebox?
In-Reply-To: <CANH4o6NRK2+ekNe_LrUaoAi8PVbi-MC3hWerv4g6F-WmXmyK5w@mail.gmail.com>
References: <CANH4o6Njc3uHE=NbasRJrRr0W5B89R8MTM_BwGwab7t5fNWuaA@mail.gmail.com>
 <Z6yxUVTp0vGWqs7Q@pengutronix.de>
 <CANH4o6NRK2+ekNe_LrUaoAi8PVbi-MC3hWerv4g6F-WmXmyK5w@mail.gmail.com>
Message-ID: <Z8GWfv4oIhB7CDSU@pengutronix.de>

On Fri, Feb 21, 2025 at 12:54:00PM +0100, Martin Wege wrote:
> On Wed, Feb 12, 2025 at 3:33?PM Sascha Hauer <s.hauer at pengutronix.de> wrote:
> >
> > Hi Martin,
> >
> > On Tue, Feb 11, 2025 at 01:56:58PM +0100, Martin Wege wrote:
> > > Hello!
> > >
> > > Does barebox have support to mount a NFSv.2 filesystem?
> >
> > No, not yet. For NFSv4 we would first need TCP support. While we started
> > to integrate a TCP stack we are not there yet unfortunately.
> 
> How long is this going to take?

I don't think this will happen anytime soon. It's quite some work and
our bandwidth for adding such a feature without (paying) customer
demand is limited.

That said, the lack of NFSv4 support is nagging me personally as well.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


From s.hauer at pengutronix.de  Fri Feb 28 02:58:13 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 11:58:13 +0100
Subject: [PATCH] parted: add partition type msdos to help text
In-Reply-To: <20250228094836.1401338-1-s.hauer@pengutronix.de>
References: <20250228094836.1401338-1-s.hauer@pengutronix.de>
Message-ID: <174074029333.1434641.14768496192575603136.b4-ty@pengutronix.de>


On Fri, 28 Feb 2025 10:48:36 +0100, Sascha Hauer wrote:
> Partition type can be either "gpt" or "msdos", but only the former was
> listed in the help text. Add the latter.
> 
> 

Applied, thanks!

[1/1] parted: add partition type msdos to help text
      https://git.pengutronix.de/cgit/barebox/commit/?id=02a7aa117778 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



From s.hauer at pengutronix.de  Fri Feb 28 04:14:27 2025
From: s.hauer at pengutronix.de (Sascha Hauer)
Date: Fri, 28 Feb 2025 13:14:27 +0100
Subject: [PATCH 1/2] ARM: i.MX6: Enable PBL_VERIFY_PIGGY with HABV4
 support
In-Reply-To: <20250218140407.1224499-1-s.hauer@pengutronix.de>
References: <20250218140407.1224499-1-s.hauer@pengutronix.de>
Message-ID: <174074486730.2603876.9589199751001079496.b4-ty@pengutronix.de>


On Tue, 18 Feb 2025 15:04:06 +0100, Sascha Hauer wrote:
> Some i.MX6 configurations use the xload mechanism. With this the ROM
> only loads and verifies the PBL. The PBL will then load barebox proper.
> Without verification the barebox proper binary is untrusted and could be
> modified. Select PBL_VERIFY_PIGGY when HABV4 is enabled to ensure the
> barebox proper binary has not been tempered with.
> 
> boards not using the xload mechanism don't need this option, but there
> is no good way to detect currently if the xload mechanism is used, so
> these boards will have to live with a slightly increased binary size
> for now.
> 
> [...]

Applied, thanks!

[1/2] ARM: i.MX6: Enable PBL_VERIFY_PIGGY with HABV4 support
      https://git.pengutronix.de/cgit/barebox/commit/?id=c2cf17685bf6 (link may not be stable)
[2/2] ARM: i.MX9: Enable PBL_VERIFY_PIGGY with non INSECURE
      https://git.pengutronix.de/cgit/barebox/commit/?id=cab919df26f5 (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer at pengutronix.de>



