Merge patch series "Bug-fixes for a few boards"

Simon Glass <sjg@chromium.org> says:

This series includes fixes to get some rockchip and nvidia boards
working again. It also drops the broken Beaglebone Black config and
provides a devicetree fix for coral (x86).
diff --git a/MAINTAINERS b/MAINTAINERS
index c283234..ddcb712 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -997,6 +997,13 @@
 F:	doc/arch/m68k.rst
 F:	drivers/watchdog/mcf_wdt.c
 
+CPU
+M:	Simon Glass <sjg@chromium.org>
+M:	Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
+S:	Maintained
+F:	cmd/cpu.c
+F:	doc/usage/cpu.rst
+
 CYCLIC
 M:	Stefan Roese <sr@denx.de>
 S:	Maintained
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 3ae4110..82d37ad 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -883,7 +883,6 @@
 	imx7-cm.dtb \
 	imx7d-colibri-emmc-eval-v3.dtb \
 	imx7d-colibri-eval-v3.dtb \
-	imx7s-warp.dtb \
 	imx7d-meerkat96.dtb \
 	imx7d-pico-pi.dtb \
 	imx7d-pico-hobbit.dtb \
diff --git a/arch/arm/dts/imx7s-warp.dts b/arch/arm/dts/imx7s-warp.dts
deleted file mode 100644
index e8734d2..0000000
--- a/arch/arm/dts/imx7s-warp.dts
+++ /dev/null
@@ -1,500 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
-/*
- * Copyright (C) 2016 NXP Semiconductors.
- * Author: Fabio Estevam <fabio.estevam@nxp.com>
- */
-
-/dts-v1/;
-
-#include <dt-bindings/input/input.h>
-#include "imx7s.dtsi"
-
-/ {
-	model = "Element14 Warp i.MX7 Board";
-	compatible = "element14,imx7s-warp", "fsl,imx7s";
-
-	memory@80000000 {
-		device_type = "memory";
-		reg = <0x80000000 0x20000000>;
-	};
-
-	gpio-keys {
-		compatible = "gpio-keys";
-		pinctrl-0 = <&pinctrl_gpio>;
-		autorepeat;
-
-		back {
-			label = "Back";
-			gpios = <&gpio7 1 GPIO_ACTIVE_HIGH>;
-			linux,code = <KEY_BACK>;
-			wakeup-source;
-		};
-	};
-
-	reg_brcm: regulator-brcm {
-		compatible = "regulator-fixed";
-		enable-active-high;
-		gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_brcm_reg>;
-		regulator-name = "brcm_reg";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		startup-delay-us = <200000>;
-	};
-
-	reg_bt: regulator-bt {
-		compatible = "regulator-fixed";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_bt_reg>;
-		enable-active-high;
-		gpio = <&gpio5 17 GPIO_ACTIVE_HIGH>;
-		regulator-name = "bt_reg";
-		regulator-min-microvolt = <3300000>;
-		regulator-max-microvolt = <3300000>;
-		regulator-always-on;
-	};
-
-	reg_peri_3p15v: regulator-peri-3p15v {
-		compatible = "regulator-fixed";
-		regulator-name = "peri_3p15v_reg";
-		regulator-min-microvolt = <3150000>;
-		regulator-max-microvolt = <3150000>;
-		regulator-always-on;
-	};
-
-	sound {
-		compatible = "simple-audio-card";
-		simple-audio-card,name = "imx7-sgtl5000";
-		simple-audio-card,format = "i2s";
-		simple-audio-card,bitclock-master = <&dailink_master>;
-		simple-audio-card,frame-master = <&dailink_master>;
-		simple-audio-card,cpu {
-			sound-dai = <&sai1>;
-		};
-
-		dailink_master: simple-audio-card,codec {
-			sound-dai = <&codec>;
-			clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
-		};
-	};
-};
-
-&clks {
-	assigned-clocks = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
-	assigned-clock-rates = <884736000>;
-};
-
-&csi {
-	status = "okay";
-};
-
-&i2c1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c1>;
-	status = "okay";
-
-	pmic: pfuze3000@8 {
-		compatible = "fsl,pfuze3000";
-		reg = <0x08>;
-
-		regulators {
-			sw1a_reg: sw1a {
-				regulator-min-microvolt = <700000>;
-				regulator-max-microvolt = <1475000>;
-				regulator-boot-on;
-				regulator-always-on;
-				regulator-ramp-delay = <6250>;
-			};
-
-			/* use sw1c_reg to align with pfuze100/pfuze200 */
-			sw1c_reg: sw1b {
-				regulator-min-microvolt = <700000>;
-				regulator-max-microvolt = <1475000>;
-				regulator-boot-on;
-				regulator-always-on;
-				regulator-ramp-delay = <6250>;
-			};
-
-			sw2_reg: sw2 {
-				regulator-min-microvolt = <1500000>;
-				regulator-max-microvolt = <1850000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			sw3a_reg: sw3 {
-				regulator-min-microvolt = <900000>;
-				regulator-max-microvolt = <1650000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			swbst_reg: swbst {
-				regulator-min-microvolt = <5000000>;
-				regulator-max-microvolt = <5150000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			snvs_reg: vsnvs {
-				regulator-min-microvolt = <1000000>;
-				regulator-max-microvolt = <3000000>;
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			vref_reg: vrefddr {
-				regulator-boot-on;
-				regulator-always-on;
-			};
-
-			vgen1_reg: vldo1 {
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
-			};
-
-			vgen2_reg: vldo2 {
-				regulator-min-microvolt = <800000>;
-				regulator-max-microvolt = <1550000>;
-			};
-
-			vgen3_reg: vccsd {
-				regulator-min-microvolt = <2850000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
-			};
-
-			vgen4_reg: v33 {
-				regulator-min-microvolt = <2850000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
-			};
-
-			vgen5_reg: vldo3 {
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
-			};
-
-			vgen6_reg: vldo4 {
-				regulator-min-microvolt = <1800000>;
-				regulator-max-microvolt = <3300000>;
-				regulator-always-on;
-			};
-		};
-	};
-};
-
-&i2c2 {
-	clock-frequency = <100000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c2>;
-	status = "okay";
-
-	ov2680: camera@36 {
-		compatible = "ovti,ov2680";
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_ov2680>;
-		reg = <0x36>;
-		clocks = <&osc>;
-		clock-names = "xvclk";
-		reset-gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
-		DOVDD-supply = <&sw2_reg>;
-		DVDD-supply = <&sw2_reg>;
-		AVDD-supply = <&reg_peri_3p15v>;
-
-		port {
-			ov2680_to_mipi: endpoint {
-				remote-endpoint = <&mipi_from_sensor>;
-				clock-lanes = <0>;
-				data-lanes = <1>;
-			};
-		};
-	};
-};
-
-&i2c3 {
-	clock-frequency = <100000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c3>;
-	status = "okay";
-};
-
-&i2c4 {
-	clock-frequency = <100000>;
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_i2c4>;
-	status = "okay";
-
-	codec: sgtl5000@a {
-		#sound-dai-cells = <0>;
-		reg = <0x0a>;
-		compatible = "fsl,sgtl5000";
-		clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_DIV>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_sai1_mclk>;
-		VDDA-supply = <&vgen4_reg>;
-		VDDIO-supply = <&vgen4_reg>;
-		VDDD-supply = <&vgen2_reg>;
-	};
-
-	mpl3115@60 {
-		compatible = "fsl,mpl3115";
-		reg = <0x60>;
-	};
-};
-
-&mipi_csi {
-	clock-frequency = <166000000>;
-	status = "okay";
-
-	ports {
-		port@0 {
-			reg = <0>;
-
-			mipi_from_sensor: endpoint {
-				remote-endpoint = <&ov2680_to_mipi>;
-				data-lanes = <1>;
-			};
-		};
-	};
-};
-
-&sai1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_sai1>;
-	assigned-clocks = <&clks IMX7D_SAI1_ROOT_SRC>,
-			  <&clks IMX7D_SAI1_ROOT_CLK>;
-	assigned-clock-parents = <&clks IMX7D_PLL_AUDIO_POST_DIV>;
-	assigned-clock-rates = <0>, <36864000>;
-	status = "okay";
-};
-
-&uart1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart1>;
-	assigned-clocks = <&clks IMX7D_UART1_ROOT_SRC>;
-	assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
-	status = "okay";
-};
-
-&uart3  {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart3>;
-	assigned-clocks = <&clks IMX7D_UART3_ROOT_SRC>;
-	assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
-	uart-has-rtscts;
-	status = "okay";
-};
-
-&uart6 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_uart6>;
-	assigned-clocks = <&clks IMX7D_UART6_ROOT_SRC>;
-	assigned-clock-parents = <&clks IMX7D_PLL_SYS_MAIN_240M_CLK>;
-	fsl,dte-mode;
-	status = "okay";
-};
-
-&usbotg1 {
-	dr_mode = "peripheral";
-	status = "okay";
-};
-
-&usdhc1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_usdhc1>;
-	bus-width = <4>;
-	keep-power-in-suspend;
-	no-1-8-v;
-	non-removable;
-	vmmc-supply = <&reg_brcm>;
-	status = "okay";
-};
-
-&usdhc3 {
-	pinctrl-names = "default", "state_100mhz", "state_200mhz";
-	pinctrl-0 = <&pinctrl_usdhc3>;
-	pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
-	pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
-	assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>;
-	assigned-clock-rates = <400000000>;
-	bus-width = <8>;
-	no-1-8-v;
-	fsl,tuning-step = <2>;
-	non-removable;
-	status = "okay";
-};
-
-&video_mux {
-	status = "okay";
-};
-
-&wdog1 {
-	pinctrl-names = "default";
-	pinctrl-0 = <&pinctrl_wdog>;
-	fsl,ext-reset-output;
-	status = "okay";
-};
-
-&iomuxc {
-	pinctrl_brcm_reg: brcmreggrp {
-		fsl,pins = <
-			MX7D_PAD_SD2_WP__GPIO5_IO10	0x14 /* WL_REG_ON */
-		>;
-	};
-
-	pinctrl_bt_reg: btreggrp {
-		fsl,pins = <
-			MX7D_PAD_SD2_DATA3__GPIO5_IO17	0x14 /* BT_REG_ON */
-		>;
-	};
-
-	pinctrl_gpio: gpiogrp {
-		fsl,pins = <
-			MX7D_PAD_ENET1_RGMII_RD1__GPIO7_IO1	0x14
-		>;
-	};
-
-	pinctrl_i2c1: i2c1grp {
-		fsl,pins = <
-			MX7D_PAD_I2C1_SDA__I2C1_SDA		0x4000007f
-			MX7D_PAD_I2C1_SCL__I2C1_SCL		0x4000007f
-		>;
-	};
-
-	pinctrl_i2c2: i2c2grp {
-		fsl,pins = <
-			MX7D_PAD_I2C2_SDA__I2C2_SDA	0x4000007f
-			MX7D_PAD_I2C2_SCL__I2C2_SCL	0x4000007f
-		>;
-	};
-
-	pinctrl_i2c3: i2c3grp {
-		fsl,pins = <
-			MX7D_PAD_I2C3_SDA__I2C3_SDA	0x4000007f
-			MX7D_PAD_I2C3_SCL__I2C3_SCL	0x4000007f
-		>;
-	};
-
-	pinctrl_i2c4: i2c4grp {
-		fsl,pins = <
-			MX7D_PAD_I2C4_SCL__I2C4_SCL	0x4000007f
-			MX7D_PAD_I2C4_SDA__I2C4_SDA	0x4000007f
-		>;
-	};
-
-	pinctrl_ov2680: ov2660grp {
-		fsl,pins = <
-			MX7D_PAD_LPSR_GPIO1_IO03__GPIO1_IO3	0x14
-		>;
-	};
-
-	pinctrl_sai1: sai1grp {
-		fsl,pins = <
-			MX7D_PAD_SAI1_RX_DATA__SAI1_RX_DATA0	0x1f
-			MX7D_PAD_SAI1_TX_BCLK__SAI1_TX_BCLK	0x1f
-			MX7D_PAD_SAI1_TX_SYNC__SAI1_TX_SYNC	0x1f
-			MX7D_PAD_SAI1_TX_DATA__SAI1_TX_DATA0	0x30
-		>;
-	};
-
-	pinctrl_sai1_mclk: sai1mclkgrp {
-		fsl,pins = <
-			MX7D_PAD_SAI1_MCLK__SAI1_MCLK           0x1f
-		>;
-	};
-
-	pinctrl_uart1: uart1grp {
-		fsl,pins = <
-			MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX	0x79
-			MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX	0x79
-		>;
-	};
-
-	pinctrl_uart3: uart3grp {
-		fsl,pins = <
-			MX7D_PAD_UART3_TX_DATA__UART3_DCE_TX	0x79
-			MX7D_PAD_UART3_RX_DATA__UART3_DCE_RX	0x79
-			MX7D_PAD_UART3_CTS_B__UART3_DCE_CTS	0x79
-			MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS	0x79
-		>;
-	};
-
-	pinctrl_uart6: uart6grp {
-		fsl,pins = <
-			MX7D_PAD_ECSPI1_MOSI__UART6_DTE_RX	0x79
-			MX7D_PAD_ECSPI1_SCLK__UART6_DTE_TX	0x79
-		>;
-	};
-
-	pinctrl_usdhc1: usdhc1grp {
-		fsl,pins = <
-			MX7D_PAD_SD1_CMD__SD1_CMD	0x59
-			MX7D_PAD_SD1_CLK__SD1_CLK	0x19
-			MX7D_PAD_SD1_DATA0__SD1_DATA0	0x59
-			MX7D_PAD_SD1_DATA1__SD1_DATA1	0x59
-			MX7D_PAD_SD1_DATA2__SD1_DATA2	0x59
-			MX7D_PAD_SD1_DATA3__SD1_DATA3	0x59
-			MX7D_PAD_SD2_RESET_B__GPIO5_IO11 0x14 /* WL_HOST_WAKE */
-		>;
-	};
-
-	pinctrl_usdhc3: usdhc3grp {
-		fsl,pins = <
-			MX7D_PAD_SD3_CMD__SD3_CMD		0x59
-			MX7D_PAD_SD3_CLK__SD3_CLK		0x19
-			MX7D_PAD_SD3_DATA0__SD3_DATA0		0x59
-			MX7D_PAD_SD3_DATA1__SD3_DATA1		0x59
-			MX7D_PAD_SD3_DATA2__SD3_DATA2		0x59
-			MX7D_PAD_SD3_DATA3__SD3_DATA3		0x59
-			MX7D_PAD_SD3_DATA4__SD3_DATA4		0x59
-			MX7D_PAD_SD3_DATA5__SD3_DATA5		0x59
-			MX7D_PAD_SD3_DATA6__SD3_DATA6		0x59
-			MX7D_PAD_SD3_DATA7__SD3_DATA7		0x59
-			MX7D_PAD_SD3_RESET_B__SD3_RESET_B	0x19
-		>;
-	};
-
-	pinctrl_usdhc3_100mhz: usdhc3grp_100mhz {
-		fsl,pins = <
-			MX7D_PAD_SD3_CMD__SD3_CMD		0x5a
-			MX7D_PAD_SD3_CLK__SD3_CLK		0x1a
-			MX7D_PAD_SD3_DATA0__SD3_DATA0		0x5a
-			MX7D_PAD_SD3_DATA1__SD3_DATA1		0x5a
-			MX7D_PAD_SD3_DATA2__SD3_DATA2		0x5a
-			MX7D_PAD_SD3_DATA3__SD3_DATA3		0x5a
-			MX7D_PAD_SD3_DATA4__SD3_DATA4		0x5a
-			MX7D_PAD_SD3_DATA5__SD3_DATA5		0x5a
-			MX7D_PAD_SD3_DATA6__SD3_DATA6		0x5a
-			MX7D_PAD_SD3_DATA7__SD3_DATA7		0x5a
-			MX7D_PAD_SD3_RESET_B__SD3_RESET_B	0x1a
-		>;
-	};
-
-	pinctrl_usdhc3_200mhz: usdhc3grp_200mhz {
-		fsl,pins = <
-			MX7D_PAD_SD3_CMD__SD3_CMD		0x5b
-			MX7D_PAD_SD3_CLK__SD3_CLK		0x1b
-			MX7D_PAD_SD3_DATA0__SD3_DATA0		0x5b
-			MX7D_PAD_SD3_DATA1__SD3_DATA1		0x5b
-			MX7D_PAD_SD3_DATA2__SD3_DATA2		0x5b
-			MX7D_PAD_SD3_DATA3__SD3_DATA3		0x5b
-			MX7D_PAD_SD3_DATA4__SD3_DATA4		0x5b
-			MX7D_PAD_SD3_DATA5__SD3_DATA5		0x5b
-			MX7D_PAD_SD3_DATA6__SD3_DATA6		0x5b
-			MX7D_PAD_SD3_DATA7__SD3_DATA7		0x5b
-			MX7D_PAD_SD3_RESET_B__SD3_RESET_B	0x1b
-		>;
-	};
-};
-
-&iomuxc_lpsr {
-	pinctrl_wdog: wdoggrp {
-		fsl,pins = <
-			MX7D_PAD_LPSR_GPIO1_IO00__WDOG1_WDOG_B	0x74
-		>;
-	};
-};
diff --git a/arch/arm/mach-imx/mx7/Kconfig b/arch/arm/mach-imx/mx7/Kconfig
index 3c0208e..2e68557 100644
--- a/arch/arm/mach-imx/mx7/Kconfig
+++ b/arch/arm/mach-imx/mx7/Kconfig
@@ -87,6 +87,7 @@
 	select DM_THERMAL
 	select MX7D
 	imply CMD_DM
+	imply OF_UPSTREAM
 
 config TARGET_COLIBRI_IMX7
 	bool "Support Colibri iMX7S/iMX7D modules"
diff --git a/cmd/cpu.c b/cmd/cpu.c
index 9e32306..2755250 100644
--- a/cmd/cpu.c
+++ b/cmd/cpu.c
@@ -3,6 +3,7 @@
  * Copyright (c) 2015 Google, Inc
  * Written by Simon Glass <sjg@chromium.org>
  * Copyright (c) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright 2024 NXP
  */
 
 #include <command.h>
@@ -18,6 +19,19 @@
 	"Device ID",
 };
 
+static struct udevice *cpu_find_device(unsigned long cpu_id)
+{
+	struct udevice *dev;
+
+	for (uclass_first_device(UCLASS_CPU, &dev); dev;
+	     uclass_next_device(&dev)) {
+		if (cpu_id == dev_seq(dev))
+			return dev;
+	}
+
+	return NULL;
+}
+
 static int print_cpu_list(bool detail)
 {
 	struct udevice *dev;
@@ -82,10 +96,36 @@
 	return 0;
 }
 
+static int do_cpu_release(struct cmd_tbl *cmdtp, int flag, int argc,
+			  char *const argv[])
+{
+	struct udevice *dev;
+	unsigned long cpu_id;
+	unsigned long long boot_addr;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	cpu_id = dectoul(argv[1], NULL);
+	dev = cpu_find_device(cpu_id);
+	if (!dev)
+		return CMD_RET_FAILURE;
+
+	boot_addr = simple_strtoull(argv[2], NULL, 16);
+
+	if (cpu_release_core(dev, boot_addr))
+		return CMD_RET_FAILURE;
+
+	return 0;
+}
+
 U_BOOT_LONGHELP(cpu,
 	"list	- list available CPUs\n"
-	"cpu detail	- show CPU detail");
+	"cpu detail	- show CPU detail\n"
+	"cpu release <core ID> <addr>	- Release CPU <core ID> at <addr>\n"
+	"            <core ID>: the sequence number in list subcommand outputs");
 
 U_BOOT_CMD_WITH_SUBCMDS(cpu, "display information about CPUs", cpu_help_text,
 	U_BOOT_SUBCMD_MKENT(list, 1, 1, do_cpu_list),
-	U_BOOT_SUBCMD_MKENT(detail, 1, 0, do_cpu_detail));
+	U_BOOT_SUBCMD_MKENT(detail, 1, 0, do_cpu_detail),
+	U_BOOT_SUBCMD_MKENT(release, 3, 0, do_cpu_release));
diff --git a/common/Kconfig b/common/Kconfig
index 4bb9f08..83c81ed 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -626,8 +626,17 @@
 
 if CYCLIC
 
+config SPL_CYCLIC
+	bool "General-purpose cyclic execution mechanism (SPL)"
+	help
+	  This enables a general-purpose cyclic execution infrastructure in SPL,
+	  to allow "small" (run-time wise) functions to be executed at
+	  a specified frequency. Things like LED blinking or watchdog
+	  triggering are examples for such tasks.
+
 config CYCLIC_MAX_CPU_TIME_US
 	int "Sets the max allowed time for a cyclic function in us"
+	default 100000 if SANDBOX  # sandbox video is quite slow
 	default 5000
 	help
 	  The max allowed time for a cyclic function in us. If a functions
diff --git a/common/Makefile b/common/Makefile
index e983547..d871113c 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -79,7 +79,7 @@
 obj-y += dlmalloc.o
 obj-$(CONFIG_$(SPL_TPL_)SYS_MALLOC_F) += malloc_simple.o
 
-obj-$(CONFIG_CYCLIC) += cyclic.o
+obj-$(CONFIG_$(SPL_TPL_)CYCLIC) += cyclic.o
 obj-$(CONFIG_$(SPL_TPL_)EVENT) += event.o
 
 obj-$(CONFIG_$(SPL_TPL_)HASH) += hash.o
diff --git a/configs/imx8mm-phygate-tauri-l_defconfig b/configs/imx8mm-phygate-tauri-l_defconfig
index 41765f1..16ba7d4 100644
--- a/configs/imx8mm-phygate-tauri-l_defconfig
+++ b/configs/imx8mm-phygate-tauri-l_defconfig
@@ -46,6 +46,7 @@
 CONFIG_SYS_PROMPT="u-boot=> "
 # CONFIG_CMD_EXPORTENV is not set
 # CONFIG_CMD_IMPORTENV is not set
+CONFIG_CMD_ERASEENV=y
 # CONFIG_CMD_CRC32 is not set
 CONFIG_CMD_EEPROM=y
 CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2
diff --git a/configs/imx8mm_evk_defconfig b/configs/imx8mm_evk_defconfig
index ff33d15..8b04586 100644
--- a/configs/imx8mm_evk_defconfig
+++ b/configs/imx8mm_evk_defconfig
@@ -118,3 +118,6 @@
 CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_SPL_USB_SDP_SUPPORT=y
 CONFIG_IMX_WATCHDOG=y
+CONFIG_CPU=y
+CONFIG_CPU_IMX=y
+CONFIG_CMD_CPU=y
diff --git a/configs/imx8mn_evk_defconfig b/configs/imx8mn_evk_defconfig
index 2402e9e..ee7a5e9 100644
--- a/configs/imx8mn_evk_defconfig
+++ b/configs/imx8mn_evk_defconfig
@@ -105,3 +105,6 @@
 CONFIG_SYSRESET_WATCHDOG=y
 CONFIG_DM_THERMAL=y
 CONFIG_IMX_WATCHDOG=y
+CONFIG_CPU=y
+CONFIG_CPU_IMX=y
+CONFIG_CMD_CPU=y
diff --git a/configs/imx8mp_evk_defconfig b/configs/imx8mp_evk_defconfig
index f5ba022..3176069 100644
--- a/configs/imx8mp_evk_defconfig
+++ b/configs/imx8mp_evk_defconfig
@@ -137,3 +137,6 @@
 CONFIG_USB_GADGET_VENDOR_NUM=0x0525
 CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
 CONFIG_IMX_WATCHDOG=y
+CONFIG_CPU=y
+CONFIG_CPU_IMX=y
+CONFIG_CMD_CPU=y
diff --git a/configs/imx93_11x11_evk_defconfig b/configs/imx93_11x11_evk_defconfig
index 2246715..93ab0b9 100644
--- a/configs/imx93_11x11_evk_defconfig
+++ b/configs/imx93_11x11_evk_defconfig
@@ -52,6 +52,7 @@
 # CONFIG_CMD_CRC32 is not set
 CONFIG_CMD_MEMTEST=y
 CONFIG_CMD_CLK=y
+CONFIG_CMD_CPU=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
diff --git a/configs/phycore-imx8mm_defconfig b/configs/phycore-imx8mm_defconfig
index f9fd725..6748e6f 100644
--- a/configs/phycore-imx8mm_defconfig
+++ b/configs/phycore-imx8mm_defconfig
@@ -12,6 +12,7 @@
 CONFIG_DEFAULT_DEVICE_TREE="freescale/imx8mm-phyboard-polis-rdk"
 CONFIG_SPL_TEXT_BASE=0x7E1000
 CONFIG_TARGET_PHYCORE_IMX8MM=y
+CONFIG_DM_RESET=y
 CONFIG_SYS_MONITOR_LEN=524288
 CONFIG_SPL_MMC=y
 CONFIG_SPL_SERIAL=y
@@ -23,6 +24,7 @@
 CONFIG_SPL=y
 CONFIG_ENV_OFFSET_REDUND=0x3E0000
 CONFIG_SYS_LOAD_ADDR=0x40480000
+CONFIG_PCI=y
 CONFIG_FIT=y
 CONFIG_FIT_EXTERNAL_OFFSET=0x3000
 CONFIG_SPL_LOAD_FIT=y
@@ -48,6 +50,7 @@
 CONFIG_SYS_PROMPT="u-boot=> "
 # CONFIG_CMD_EXPORTENV is not set
 # CONFIG_CMD_IMPORTENV is not set
+CONFIG_CMD_ERASEENV=y
 # CONFIG_CMD_CRC32 is not set
 CONFIG_CMD_EEPROM=y
 CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2
@@ -59,6 +62,7 @@
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
+CONFIG_CMD_PCI=y
 CONFIG_CMD_SF_TEST=y
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
@@ -110,10 +114,15 @@
 CONFIG_PHY_GIGE=y
 CONFIG_FEC_MXC=y
 CONFIG_MII=y
+CONFIG_NVME_PCI=y
+CONFIG_PCIE_DW_IMX=y
+CONFIG_PHY=y
+CONFIG_PHY_IMX8M_PCIE=y
 CONFIG_PINCTRL=y
 CONFIG_SPL_PINCTRL=y
 CONFIG_PINCTRL_IMX8M=y
-CONFIG_DM_REGULATOR=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_IMX8M_POWER_DOMAIN=y
 CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_GPIO=y
 CONFIG_DM_SERIAL=y
diff --git a/configs/phycore-imx8mp_defconfig b/configs/phycore-imx8mp_defconfig
index da7fe61..63f8a80 100644
--- a/configs/phycore-imx8mp_defconfig
+++ b/configs/phycore-imx8mp_defconfig
@@ -52,6 +52,7 @@
 CONFIG_SPL_WATCHDOG=y
 CONFIG_HUSH_PARSER=y
 CONFIG_SYS_PROMPT="u-boot=> "
+CONFIG_CMD_ERASEENV=y
 # CONFIG_CMD_CRC32 is not set
 CONFIG_CMD_EEPROM=y
 CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2
diff --git a/configs/warp7_bl33_defconfig b/configs/warp7_bl33_defconfig
index 51e5200..6b68681 100644
--- a/configs/warp7_bl33_defconfig
+++ b/configs/warp7_bl33_defconfig
@@ -4,7 +4,7 @@
 CONFIG_ENV_SIZE=0x2000
 CONFIG_ENV_OFFSET=0x80000
 CONFIG_DM_GPIO=y
-CONFIG_DEFAULT_DEVICE_TREE="imx7s-warp"
+CONFIG_DEFAULT_DEVICE_TREE="nxp/imx/imx7s-warp"
 CONFIG_TARGET_WARP7=y
 CONFIG_OF_LIBFDT_OVERLAY=y
 CONFIG_ARMV7_BOOT_SEC_DEFAULT=y
diff --git a/configs/warp7_defconfig b/configs/warp7_defconfig
index 48042b7..679b6e8 100644
--- a/configs/warp7_defconfig
+++ b/configs/warp7_defconfig
@@ -5,7 +5,7 @@
 CONFIG_ENV_SIZE=0x2000
 CONFIG_ENV_OFFSET=0xC0000
 CONFIG_DM_GPIO=y
-CONFIG_DEFAULT_DEVICE_TREE="imx7s-warp"
+CONFIG_DEFAULT_DEVICE_TREE="nxp/imx/imx7s-warp"
 CONFIG_TARGET_WARP7=y
 CONFIG_ARMV7_BOOT_SEC_DEFAULT=y
 # CONFIG_ARMV7_VIRT is not set
diff --git a/doc/usage/cmd/cpu.rst b/doc/usage/cmd/cpu.rst
new file mode 100644
index 0000000..8b0b7d5
--- /dev/null
+++ b/doc/usage/cmd/cpu.rst
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright 2024 NXP
+
+.. index::
+   single: cpu (command)
+
+cpu command
+===========
+
+Synopsis
+--------
+
+::
+
+    cpu list
+    cpu detail
+    cpu release <core ID> <addr>
+
+Description
+-----------
+
+The *cpu* command prints information about the CPUs, and release a CPU core
+to a given address to run applications.
+
+
+cpu list
+~~~~~~~~
+
+The 'list' subcommand lists and prints brief information of all the CPU cores,
+the CPU information is provided by vendors' CPU driver.
+
+cpu detail
+~~~~~~~~~~
+
+The 'detail' subcommand prints more details about the CPU cores, including
+CPU ID, core frequency and feature list.
+
+cpu release
+~~~~~~~~~~~
+
+The 'release' subcommand is used to release a CPU core to run a baremetal or
+RTOS applications.
+The parameter <core ID> is the sequence number of the CPU core to release.
+The parameter <addr> is the address to run of the specified core after release.
+
+
+Examples
+--------
+
+cpu list
+~~~~~~~~
+
+This example lists all the CPU cores On i.MX8M Plus EVK:
+::
+
+    u-boot=> cpu list
+      0: cpu@0      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 31C
+      1: cpu@1      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 30C
+      2: cpu@2      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 31C
+      3: cpu@3      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 31C
+
+cpu detail
+~~~~~~~~~~
+
+This example prints the details of the CPU cores On i.MX8M Plus EVK:
+::
+
+    u-boot=> cpu detail
+      0: cpu@0      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 31C
+            ID = 0, freq = 1.2 GHz: L1 cache, MMU
+      1: cpu@1      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 30C
+            ID = 0, freq = 1.2 GHz: L1 cache, MMU
+      2: cpu@2      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 31C
+            ID = 0, freq = 1.2 GHz: L1 cache, MMU
+      3: cpu@3      NXP i.MX8MP Rev1.1 A53 at 1200 MHz at 31C
+            ID = 0, freq = 1.2 GHz: L1 cache, MMU
+
+cpu release
+~~~~~~~~~~~
+
+This example shows release the LAST CPU core to run a RTOS application, on
+i.MX8M Plus EVK:
+::
+
+     u-boot=> load mmc 1:2 c0000000 /hello_world.bin
+     66008 bytes read in 5 ms (12.6 MiB/s)
+     u-boot=> dcache flush; icache flush
+     u-boot=> cpu release 3 c0000000
+     Released CPU core (mpidr: 0x3) to address 0xc0000000
+
+
+Configuration
+-------------
+
+The cpu command is available if CONFIG_CMD_CPU=y.
+
+Return code
+-----------
+
+The return value $? is set to 0 (true) if the command is successful,
+1 (false) otherwise.
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 49b354e..1f6518b 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -50,6 +50,7 @@
    cmd/coninfo
    cmd/conitrace
    cmd/cp
+   cmd/cpu
    cmd/cyclic
    cmd/dm
    cmd/ebtupdate
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index c48a62b..16169da 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -178,7 +178,7 @@
 bulk_get_err:
 	err = clk_release_all(bulk->clks, bulk->count);
 	if (err)
-		debug("%s: could release all clocks for %p\n",
+		debug("%s: could not release all clocks for %p\n",
 		      __func__, dev);
 
 	return ret;
@@ -609,7 +609,7 @@
 	struct clk *clkp = NULL;
 	int ret;
 
-	debug("%s(clk=%p)\n", __func__, clk);
+	debug("%s(clk=%p name=%s)\n", __func__, clk, clk->dev->name);
 	if (!clk_valid(clk))
 		return 0;
 	ops = clk_dev_ops(clk->dev);
@@ -670,7 +670,7 @@
 	struct clk *clkp = NULL;
 	int ret;
 
-	debug("%s(clk=%p)\n", __func__, clk);
+	debug("%s(clk=%p name=%s)\n", __func__, clk, clk->dev->name);
 	if (!clk_valid(clk))
 		return 0;
 	ops = clk_dev_ops(clk->dev);
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index e538f04..a91c676 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -21,6 +21,8 @@
 static const char * const sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
 static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
 
+static const char * const imx8mm_arm_core_sels[] = {"arm_a53_src", "arm_pll_out", };
+
 static const char * const imx8mm_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m",
 					       "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
 					       "audio_pll1_out", "sys_pll3_out", };
@@ -417,6 +419,12 @@
 	       imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
 #endif
 
+	clk_dm(IMX8MM_CLK_ARM,
+	       imx_clk_mux2_flags("arm_core", base + 0x9880, 24, 1,
+				  imx8mm_arm_core_sels,
+				  ARRAY_SIZE(imx8mm_arm_core_sels),
+				  CLK_IS_CRITICAL));
+
 	return 0;
 }
 
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index 8911e34..125215e 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -23,6 +23,8 @@
 static const char * const sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
 static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
 
+static const char * const imx8mn_arm_core_sels[] = {"arm_a53_src", "arm_pll_out", };
+
 static const char * const imx8mn_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m",
 					       "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
 					       "audio_pll1_out", "sys_pll3_out", };
@@ -403,6 +405,12 @@
 	       imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0));
 #endif
 
+	clk_dm(IMX8MN_CLK_ARM,
+	       imx_clk_mux2_flags("arm_core", base + 0x9880, 24, 1,
+				  imx8mn_arm_core_sels,
+				  ARRAY_SIZE(imx8mn_arm_core_sels),
+				  CLK_IS_CRITICAL));
+
 	return 0;
 }
 
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index 6b18483..34d91cd 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -21,6 +21,8 @@
 static const char * const sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", };
 static const char * const sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", };
 
+static const char * const imx8mp_arm_core_sels[] = {"arm_a53_src", "arm_pll_out", };
+
 static const char * const imx8mp_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m",
 					       "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m",
 					       "audio_pll1_out", "sys_pll3_out", };
@@ -354,6 +356,12 @@
 
 	clk_dm(IMX8MP_CLK_USDHC3_ROOT, imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
 
+	clk_dm(IMX8MP_CLK_ARM,
+	       imx_clk_mux2_flags("arm_core", base + 0x9880, 24, 1,
+				  imx8mp_arm_core_sels,
+				  ARRAY_SIZE(imx8mp_arm_core_sels),
+				  CLK_IS_CRITICAL));
+
 	return 0;
 }
 
diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c
index d2c45be..66683ae 100644
--- a/drivers/clk/mediatek/clk-mtk.c
+++ b/drivers/clk/mediatek/clk-mtk.c
@@ -35,6 +35,68 @@
 
 /* shared functions */
 
+static int mtk_clk_get_id(struct clk *clk)
+{
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	int id = clk->id;
+
+	/* Remap the clk ID to the one expected by driver */
+	if (priv->tree->id_offs_map)
+		id = priv->tree->id_offs_map[id];
+
+	return id;
+}
+
+static int mtk_gate_enable(void __iomem *base, const struct mtk_gate *gate)
+{
+	u32 bit = BIT(gate->shift);
+
+	switch (gate->flags & CLK_GATE_MASK) {
+	case CLK_GATE_SETCLR:
+		writel(bit, base + gate->regs->clr_ofs);
+		break;
+	case CLK_GATE_SETCLR_INV:
+		writel(bit, base + gate->regs->set_ofs);
+		break;
+	case CLK_GATE_NO_SETCLR:
+		clrsetbits_le32(base + gate->regs->sta_ofs, bit, 0);
+		break;
+	case CLK_GATE_NO_SETCLR_INV:
+		clrsetbits_le32(base + gate->regs->sta_ofs, bit, bit);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mtk_gate_disable(void __iomem *base, const struct mtk_gate *gate)
+{
+	u32 bit = BIT(gate->shift);
+
+	switch (gate->flags & CLK_GATE_MASK) {
+	case CLK_GATE_SETCLR:
+		writel(bit, base + gate->regs->set_ofs);
+		break;
+	case CLK_GATE_SETCLR_INV:
+		writel(bit, base + gate->regs->clr_ofs);
+		break;
+	case CLK_GATE_NO_SETCLR:
+		clrsetbits_le32(base + gate->regs->sta_ofs, bit, bit);
+		break;
+	case CLK_GATE_NO_SETCLR_INV:
+		clrsetbits_le32(base + gate->regs->sta_ofs, bit, 0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /*
  * In case the rate change propagation to parent clocks is undesirable,
  * this function is recursively called to find the parent to calculate
@@ -54,13 +116,27 @@
 }
 
 static int mtk_clk_mux_set_parent(void __iomem *base, u32 parent,
+				  u32 parent_type,
 				  const struct mtk_composite *mux)
 {
 	u32 val, index = 0;
 
-	while (mux->parent[index] != parent)
-		if (++index == mux->num_parents)
-			return -EINVAL;
+	if (mux->flags & CLK_PARENT_MIXED) {
+		/*
+		 * Assume parent_type in clk_tree to be always set with
+		 * CLK_PARENT_MIXED implementation. If it's not, assume
+		 * not parent clk ID clash is possible.
+		 */
+		while (mux->parent_flags[index].id != parent ||
+		       (parent_type && (mux->parent_flags[index].flags & CLK_PARENT_MASK) !=
+			parent_type))
+			if (++index == mux->num_parents)
+				return -EINVAL;
+	} else {
+		while (mux->parent[index] != parent)
+			if (++index == mux->num_parents)
+				return -EINVAL;
+	}
 
 	if (mux->flags & CLK_MUX_SETCLR_UPD) {
 		val = (mux->mux_mask << mux->mux_shift);
@@ -117,12 +193,14 @@
  * for the integer part and the remaining bits (if present) for the
  * fractional part. Also they have a 3 bit power-of-two post divider.
  */
-static void mtk_pll_set_rate_regs(struct clk *clk, u32 pcw, int postdiv)
+static void mtk_pll_set_rate_regs(struct mtk_clk_priv *priv, u32 id,
+				  u32 pcw, int postdiv)
 {
-	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	const struct mtk_pll_data *pll;
 	u32 val, chg;
 
+	pll = &priv->tree->plls[id];
+
 	/* set postdiv */
 	val = readl(priv->base + pll->pd_reg);
 	val &= ~(POSTDIV_MASK << pll->pd_shift);
@@ -153,21 +231,24 @@
 
 /**
  * mtk_pll_calc_values - calculate good values for a given input frequency.
- * @clk:	The clk
+ * @priv:	The mtk priv struct
+ * @id:		The clk id
  * @pcw:	The pcw value (output)
  * @postdiv:	The post divider (output)
  * @freq:	The desired target frequency
  */
-static void mtk_pll_calc_values(struct clk *clk, u32 *pcw, u32 *postdiv,
-				u32 freq)
+static void mtk_pll_calc_values(struct mtk_clk_priv *priv, u32 id,
+				u32 *pcw, u32 *postdiv, u32 freq)
 {
-	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
-	unsigned long fmin = pll->fmin ? pll->fmin : 1000 * MHZ;
+	const struct mtk_pll_data *pll;
+	unsigned long fmin;
 	u64 _pcw;
 	int ibits;
 	u32 val;
 
+	pll = &priv->tree->plls[id];
+	fmin = pll->fmin ? pll->fmin : 1000 * MHZ;
+
 	if (freq > pll->fmax)
 		freq = pll->fmax;
 
@@ -187,11 +268,16 @@
 
 static ulong mtk_apmixedsys_set_rate(struct clk *clk, ulong rate)
 {
+	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	int id = mtk_clk_get_id(clk);
 	u32 pcw = 0;
 	u32 postdiv;
 
-	mtk_pll_calc_values(clk, &pcw, &postdiv, rate);
-	mtk_pll_set_rate_regs(clk, pcw, postdiv);
+	if (priv->tree->gates && id >= priv->tree->gates_offs)
+		return -EINVAL;
+
+	mtk_pll_calc_values(priv, id, &pcw, &postdiv, rate);
+	mtk_pll_set_rate_regs(priv, id, pcw, postdiv);
 
 	return 0;
 }
@@ -199,10 +285,20 @@
 static ulong mtk_apmixedsys_get_rate(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	const struct mtk_pll_data *pll;
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
 	u32 postdiv;
 	u32 pcw;
 
+	/* GATE handling */
+	if (priv->tree->gates && id >= priv->tree->gates_offs) {
+		gate = &priv->tree->gates[id - priv->tree->gates_offs];
+		return mtk_clk_find_parent_rate(clk, gate->parent, NULL);
+	}
+
+	pll = &priv->tree->plls[id];
+
 	postdiv = (readl(priv->base + pll->pd_reg) >> pll->pd_shift) &
 		   POSTDIV_MASK;
 	postdiv = 1 << postdiv;
@@ -217,9 +313,19 @@
 static int mtk_apmixedsys_enable(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	const struct mtk_pll_data *pll;
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
 	u32 r;
 
+	/* GATE handling */
+	if (priv->tree->gates && id >= priv->tree->gates_offs) {
+		gate = &priv->tree->gates[id - priv->tree->gates_offs];
+		return mtk_gate_enable(priv->base, gate);
+	}
+
+	pll = &priv->tree->plls[id];
+
 	r = readl(priv->base + pll->pwr_reg) | CON0_PWR_ON;
 	writel(r, priv->base + pll->pwr_reg);
 	udelay(1);
@@ -246,9 +352,19 @@
 static int mtk_apmixedsys_disable(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_pll_data *pll = &priv->tree->plls[clk->id];
+	const struct mtk_pll_data *pll;
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
 	u32 r;
 
+	/* GATE handling */
+	if (priv->tree->gates && id >= priv->tree->gates_offs) {
+		gate = &priv->tree->gates[id - priv->tree->gates_offs];
+		return mtk_gate_disable(priv->base, gate);
+	}
+
+	pll = &priv->tree->plls[id];
+
 	if (pll->flags & HAVE_RST_BAR) {
 		r = readl(priv->base + pll->reg + REG_CON0);
 		r &= ~pll->rst_bar_mask;
@@ -324,6 +440,19 @@
 	return mtk_factor_recalc_rate(fdiv, rate);
 }
 
+static ulong mtk_topckgen_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk,
+					   const int parent, u16 flags)
+{
+	switch (flags & CLK_PARENT_MASK) {
+	case CLK_PARENT_XTAL:
+		return priv->tree->xtal_rate;
+	case CLK_PARENT_APMIXED:
+		return mtk_clk_find_parent_rate(clk, parent, priv->parent);
+	default:
+		return mtk_clk_find_parent_rate(clk, parent, NULL);
+	}
+}
+
 static ulong mtk_topckgen_get_mux_rate(struct clk *clk, u32 off)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
@@ -334,22 +463,40 @@
 	index &= mux->mux_mask << mux->mux_shift;
 	index = index >> mux->mux_shift;
 
-	if (mux->parent[index] > 0 ||
-	    (mux->parent[index] == CLK_XTAL &&
-	     priv->tree->flags & CLK_BYPASS_XTAL)) {
-		switch (mux->flags & CLK_PARENT_MASK) {
-		case CLK_PARENT_APMIXED:
-			return mtk_clk_find_parent_rate(clk, mux->parent[index],
-							priv->parent);
-			break;
-		default:
-			return mtk_clk_find_parent_rate(clk, mux->parent[index],
-							NULL);
-			break;
-		}
+	/*
+	 * Parents can be either from APMIXED or TOPCKGEN,
+	 * inspect the mtk_parent struct to check the source
+	 */
+	if (mux->flags & CLK_PARENT_MIXED) {
+		const struct mtk_parent *parent = &mux->parent_flags[index];
+
+		return mtk_topckgen_find_parent_rate(priv, clk, parent->id,
+						     parent->flags);
 	}
 
-	return priv->tree->xtal_rate;
+	if (mux->parent[index] == CLK_XTAL &&
+	    !(priv->tree->flags & CLK_BYPASS_XTAL))
+		return priv->tree->xtal_rate;
+
+	return mtk_topckgen_find_parent_rate(priv, clk, mux->parent[index],
+					     mux->flags);
+}
+
+static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk,
+				  const int parent, u16 flags)
+{
+	switch (flags & CLK_PARENT_MASK) {
+	case CLK_PARENT_XTAL:
+		return priv->tree->xtal_rate;
+	/* Assume the second level parent is always APMIXED */
+	case CLK_PARENT_APMIXED:
+		priv = dev_get_priv(priv->parent);
+		fallthrough;
+	case CLK_PARENT_TOPCKGEN:
+		return mtk_clk_find_parent_rate(clk, parent, priv->parent);
+	default:
+		return mtk_clk_find_parent_rate(clk, parent, NULL);
+	}
 }
 
 static ulong mtk_infrasys_get_mux_rate(struct clk *clk, u32 off)
@@ -362,51 +509,69 @@
 	index &= mux->mux_mask << mux->mux_shift;
 	index = index >> mux->mux_shift;
 
-	if (mux->parent[index] > 0 ||
-	    (mux->parent[index] == CLK_XTAL &&
-	     priv->tree->flags & CLK_BYPASS_XTAL)) {
-		switch (mux->flags & CLK_PARENT_MASK) {
-		case CLK_PARENT_TOPCKGEN:
-			return mtk_clk_find_parent_rate(clk, mux->parent[index],
-							priv->parent);
-			break;
-		default:
-			return mtk_clk_find_parent_rate(clk, mux->parent[index],
-							NULL);
-			break;
-		}
+	/*
+	 * Parents can be either from TOPCKGEN or INFRACFG,
+	 * inspect the mtk_parent struct to check the source
+	 */
+	if (mux->flags & CLK_PARENT_MIXED) {
+		const struct mtk_parent *parent = &mux->parent_flags[index];
+
+		return mtk_find_parent_rate(priv, clk, parent->id, parent->flags);
 	}
-	return 0;
+
+	if (mux->parent[index] == CLK_XTAL &&
+	    !(priv->tree->flags & CLK_BYPASS_XTAL))
+		return priv->tree->xtal_rate;
+
+	return mtk_find_parent_rate(priv, clk, mux->parent[index], mux->flags);
 }
 
 static ulong mtk_topckgen_get_rate(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	int id = mtk_clk_get_id(clk);
 
-	if (clk->id < priv->tree->fdivs_offs)
-		return priv->tree->fclks[clk->id].rate;
-	else if (clk->id < priv->tree->muxes_offs)
-		return mtk_topckgen_get_factor_rate(clk, clk->id -
+	if (id < priv->tree->fdivs_offs)
+		return priv->tree->fclks[id].rate;
+	else if (id < priv->tree->muxes_offs)
+		return mtk_topckgen_get_factor_rate(clk, id -
 						    priv->tree->fdivs_offs);
 	else
-		return mtk_topckgen_get_mux_rate(clk, clk->id -
+		return mtk_topckgen_get_mux_rate(clk, id -
 						 priv->tree->muxes_offs);
 }
 
 static ulong mtk_infrasys_get_rate(struct clk *clk)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
-
+	int id = mtk_clk_get_id(clk);
 	ulong rate;
 
-	if (clk->id < priv->tree->fdivs_offs) {
-		rate = priv->tree->fclks[clk->id].rate;
-	} else if (clk->id < priv->tree->muxes_offs) {
-		rate = mtk_infrasys_get_factor_rate(clk, clk->id -
+	if (id < priv->tree->fdivs_offs) {
+		rate = priv->tree->fclks[id].rate;
+	} else if (id < priv->tree->muxes_offs) {
+		rate = mtk_infrasys_get_factor_rate(clk, id -
 						    priv->tree->fdivs_offs);
-	} else {
-		rate = mtk_infrasys_get_mux_rate(clk, clk->id -
+	/* No gates defined or ID is a MUX */
+	} else if (!priv->tree->gates || id < priv->tree->gates_offs) {
+		rate = mtk_infrasys_get_mux_rate(clk, id -
 						 priv->tree->muxes_offs);
+	/* Only valid with muxes + gates implementation */
+	} else {
+		struct udevice *parent = NULL;
+		const struct mtk_gate *gate;
+
+		gate = &priv->tree->gates[id - priv->tree->gates_offs];
+		if (gate->flags & CLK_PARENT_TOPCKGEN)
+			parent = priv->parent;
+		/*
+		 * Assume xtal_rate to be declared if some gates have
+		 * XTAL as parent
+		 */
+		else if (gate->flags & CLK_PARENT_XTAL)
+			return priv->tree->xtal_rate;
+
+		rate = mtk_clk_find_parent_rate(clk, gate->parent, parent);
 	}
 
 	return rate;
@@ -416,12 +581,13 @@
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
 	const struct mtk_composite *mux;
+	int id = mtk_clk_get_id(clk);
 	u32 val;
 
-	if (clk->id < priv->tree->muxes_offs)
+	if (id < priv->tree->muxes_offs)
 		return 0;
 
-	mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
+	mux = &priv->tree->muxes[id - priv->tree->muxes_offs];
 	if (mux->gate_shift < 0)
 		return 0;
 
@@ -449,12 +615,13 @@
 {
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
 	const struct mtk_composite *mux;
+	int id = mtk_clk_get_id(clk);
 	u32 val;
 
-	if (clk->id < priv->tree->muxes_offs)
+	if (id < priv->tree->muxes_offs)
 		return 0;
 
-	mux = &priv->tree->muxes[clk->id - priv->tree->muxes_offs];
+	mux = &priv->tree->muxes[id - priv->tree->muxes_offs];
 	if (mux->gate_shift < 0)
 		return 0;
 
@@ -473,13 +640,20 @@
 
 static int mtk_common_clk_set_parent(struct clk *clk, struct clk *parent)
 {
+	struct mtk_clk_priv *parent_priv = dev_get_priv(parent->dev);
 	struct mtk_clk_priv *priv = dev_get_priv(clk->dev);
+	int id = mtk_clk_get_id(clk);
+	u32 parent_type;
 
-	if (clk->id < priv->tree->muxes_offs)
+	if (id < priv->tree->muxes_offs)
 		return 0;
 
-	return mtk_clk_mux_set_parent(priv->base, parent->id,
-			&priv->tree->muxes[clk->id - priv->tree->muxes_offs]);
+	if (!parent_priv)
+		return 0;
+
+	parent_type = parent_priv->tree->flags & CLK_PARENT_MASK;
+	return mtk_clk_mux_set_parent(priv->base, parent->id, parent_type,
+			&priv->tree->muxes[id - priv->tree->muxes_offs]);
 }
 
 /* CG functions */
@@ -487,63 +661,88 @@
 static int mtk_clk_gate_enable(struct clk *clk)
 {
 	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_gate *gate = &priv->gates[clk->id];
-	u32 bit = BIT(gate->shift);
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
 
-	switch (gate->flags & CLK_GATE_MASK) {
-	case CLK_GATE_SETCLR:
-		writel(bit, priv->base + gate->regs->clr_ofs);
-		break;
-	case CLK_GATE_SETCLR_INV:
-		writel(bit, priv->base + gate->regs->set_ofs);
-		break;
-	case CLK_GATE_NO_SETCLR:
-		clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0);
-		break;
-	case CLK_GATE_NO_SETCLR_INV:
-		clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit);
-		break;
-
-	default:
+	if (id < priv->tree->gates_offs)
 		return -EINVAL;
-	}
 
-	return 0;
+	gate = &priv->gates[id - priv->tree->gates_offs];
+	return mtk_gate_enable(priv->base, gate);
+}
+
+static int mtk_clk_infrasys_enable(struct clk *clk)
+{
+	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
+
+	/* MUX handling */
+	if (!priv->tree->gates || id < priv->tree->gates_offs)
+		return mtk_clk_mux_enable(clk);
+
+	gate = &priv->tree->gates[id - priv->tree->gates_offs];
+	return mtk_gate_enable(priv->base, gate);
 }
 
 static int mtk_clk_gate_disable(struct clk *clk)
 {
 	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_gate *gate = &priv->gates[clk->id];
-	u32 bit = BIT(gate->shift);
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
 
-	switch (gate->flags & CLK_GATE_MASK) {
-	case CLK_GATE_SETCLR:
-		writel(bit, priv->base + gate->regs->set_ofs);
-		break;
-	case CLK_GATE_SETCLR_INV:
-		writel(bit, priv->base + gate->regs->clr_ofs);
-		break;
-	case CLK_GATE_NO_SETCLR:
-		clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, bit);
-		break;
-	case CLK_GATE_NO_SETCLR_INV:
-		clrsetbits_le32(priv->base + gate->regs->sta_ofs, bit, 0);
-		break;
-
-	default:
+	if (id < priv->tree->gates_offs)
 		return -EINVAL;
-	}
 
-	return 0;
+	gate = &priv->gates[id - priv->tree->gates_offs];
+	return mtk_gate_disable(priv->base, gate);
+}
+
+static int mtk_clk_infrasys_disable(struct clk *clk)
+{
+	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
+
+	/* MUX handling */
+	if (!priv->tree->gates || id < priv->tree->gates_offs)
+		return mtk_clk_mux_disable(clk);
+
+	gate = &priv->tree->gates[id - priv->tree->gates_offs];
+	return mtk_gate_disable(priv->base, gate);
 }
 
 static ulong mtk_clk_gate_get_rate(struct clk *clk)
 {
 	struct mtk_cg_priv *priv = dev_get_priv(clk->dev);
-	const struct mtk_gate *gate = &priv->gates[clk->id];
+	struct udevice *parent = priv->parent;
+	int id = mtk_clk_get_id(clk);
+	const struct mtk_gate *gate;
 
-	return mtk_clk_find_parent_rate(clk, gate->parent, priv->parent);
+	if (id < priv->tree->gates_offs)
+		return -EINVAL;
+
+	gate = &priv->gates[id - priv->tree->gates_offs];
+	/*
+	 * With requesting a TOPCKGEN parent, make sure the dev parent
+	 * is actually topckgen. This might not be the case for an
+	 * infracfg-ao implementation where:
+	 * parent = infracfg
+	 * parent->parent = topckgen
+	 */
+	if (gate->flags & CLK_PARENT_TOPCKGEN &&
+	    parent->driver != DM_DRIVER_GET(mtk_clk_topckgen)) {
+		priv = dev_get_priv(parent);
+		parent = priv->parent;
+	/*
+	 * Assume xtal_rate to be declared if some gates have
+	 * XTAL as parent
+	 */
+	} else if (gate->flags & CLK_PARENT_XTAL) {
+		return priv->tree->xtal_rate;
+	}
+
+	return mtk_clk_find_parent_rate(clk, gate->parent, parent);
 }
 
 const struct clk_ops mtk_clk_apmixedsys_ops = {
@@ -561,8 +760,8 @@
 };
 
 const struct clk_ops mtk_clk_infrasys_ops = {
-	.enable = mtk_clk_mux_enable,
-	.disable = mtk_clk_mux_disable,
+	.enable = mtk_clk_infrasys_enable,
+	.disable = mtk_clk_infrasys_disable,
 	.get_rate = mtk_infrasys_get_rate,
 	.set_parent = mtk_common_clk_set_parent,
 };
@@ -573,8 +772,9 @@
 	.get_rate = mtk_clk_gate_get_rate,
 };
 
-int mtk_common_clk_init(struct udevice *dev,
-			const struct mtk_clk_tree *tree)
+static int mtk_common_clk_init_drv(struct udevice *dev,
+				   const struct mtk_clk_tree *tree,
+				   const struct driver *drv)
 {
 	struct mtk_clk_priv *priv = dev_get_priv(dev);
 	struct udevice *parent;
@@ -586,8 +786,7 @@
 
 	ret = uclass_get_device_by_phandle(UCLASS_CLK, dev, "clock-parent", &parent);
 	if (ret || !parent) {
-		ret = uclass_get_device_by_driver(UCLASS_CLK,
-				DM_DRIVER_GET(mtk_clk_apmixedsys), &parent);
+		ret = uclass_get_device_by_driver(UCLASS_CLK, drv, &parent);
 		if (ret || !parent)
 			return -ENOENT;
 	}
@@ -598,6 +797,20 @@
 	return 0;
 }
 
+int mtk_common_clk_init(struct udevice *dev,
+			const struct mtk_clk_tree *tree)
+{
+	return mtk_common_clk_init_drv(dev, tree,
+				       DM_DRIVER_GET(mtk_clk_apmixedsys));
+}
+
+int mtk_common_clk_infrasys_init(struct udevice *dev,
+				 const struct mtk_clk_tree *tree)
+{
+	return mtk_common_clk_init_drv(dev, tree,
+				       DM_DRIVER_GET(mtk_clk_topckgen));
+}
+
 int mtk_common_clk_gate_init(struct udevice *dev,
 			     const struct mtk_clk_tree *tree,
 			     const struct mtk_gate *gates)
diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h
index 48ce164..c1d9901 100644
--- a/drivers/clk/mediatek/clk-mtk.h
+++ b/drivers/clk/mediatek/clk-mtk.h
@@ -13,7 +13,11 @@
 
 /* flags in struct mtk_clk_tree */
 
-/* clk id == 0 doesn't mean it's xtal clk */
+/* clk id == 0 doesn't mean it's xtal clk
+ * This doesn't apply when CLK_PARENT_MIXED is defined.
+ * With CLK_PARENT_MIXED declare CLK_PARENT_XTAL for the
+ * relevant parent.
+ */
 #define CLK_BYPASS_XTAL			BIT(0)
 
 #define HAVE_RST_BAR			BIT(0)
@@ -30,7 +34,17 @@
 #define CLK_PARENT_TOPCKGEN		BIT(5)
 #define CLK_PARENT_INFRASYS		BIT(6)
 #define CLK_PARENT_XTAL			BIT(7)
-#define CLK_PARENT_MASK			GENMASK(7, 4)
+/*
+ * For CLK_PARENT_MIXED to correctly work, is required to
+ * define in clk_tree flags the clk type using the alias.
+ */
+#define CLK_PARENT_MIXED		BIT(8)
+#define CLK_PARENT_MASK			GENMASK(8, 4)
+
+/* alias to reference clk type */
+#define CLK_APMIXED			CLK_PARENT_APMIXED
+#define CLK_TOPCKGEN			CLK_PARENT_TOPCKGEN
+#define CLK_INFRASYS			CLK_PARENT_INFRASYS
 
 #define ETHSYS_HIFSYS_RST_CTRL_OFS	0x34
 
@@ -98,10 +112,30 @@
 	}
 
 /**
+ * struct mtk_parent -  clock parent with flags. Needed for MUX that
+ *			parent with mixed infracfg and topckgen.
+ *
+ * @id:			index of parent clocks
+ * @flags:		hardware-specific flags (parent location,
+ *			infracfg, topckgen, APMIXED, xtal ...)
+ */
+struct mtk_parent {
+	const int id;
+	u16 flags;
+};
+
+#define PARENT(_id, _flags) {				\
+		.id = _id,				\
+		.flags = _flags,			\
+	}
+
+/**
  * struct mtk_composite - aggregate clock of mux, divider and gate clocks
  *
  * @id:			index of clocks
  * @parent:		index of parnet clocks
+ * @parent:		index of parnet clocks
+ * @parent_flags:	table of parent clocks with flags
  * @mux_reg:		hardware-specific mux register
  * @gate_reg:		hardware-specific gate register
  * @mux_mask:		mask to the mux bit field
@@ -112,7 +146,10 @@
  */
 struct mtk_composite {
 	const int id;
-	const int *parent;
+	union {
+		const int *parent;
+		const struct mtk_parent *parent_flags;
+	};
 	u32 mux_reg;
 	u32 mux_set_reg;
 	u32 mux_clr_reg;
@@ -142,7 +179,20 @@
 #define MUX_GATE(_id, _parents, _reg, _shift, _width, _gate)		\
 	MUX_GATE_FLAGS(_id, _parents, _reg, _shift, _width, _gate, 0)
 
-#define MUX(_id, _parents, _reg, _shift, _width) {			\
+#define MUX_MIXED_FLAGS(_id, _parents, _reg, _shift, _width, _flags) {	\
+		.id = _id,						\
+		.mux_reg = _reg,					\
+		.mux_shift = _shift,					\
+		.mux_mask = BIT(_width) - 1,				\
+		.gate_shift = -1,					\
+		.parent_flags = _parents,				\
+		.num_parents = ARRAY_SIZE(_parents),			\
+		.flags = CLK_PARENT_MIXED | (_flags),			\
+	}
+#define MUX_MIXED(_id, _parents, _reg, _shift, _width)			\
+	MUX_MIXED_FLAGS(_id, _parents, _reg, _shift, _width, 0)
+
+#define MUX_FLAGS(_id, _parents, _reg, _shift, _width, _flags) {	\
 		.id = _id,						\
 		.mux_reg = _reg,					\
 		.mux_shift = _shift,					\
@@ -150,8 +200,10 @@
 		.gate_shift = -1,					\
 		.parent = _parents,					\
 		.num_parents = ARRAY_SIZE(_parents),			\
-		.flags = 0,						\
+		.flags = _flags,					\
 	}
+#define MUX(_id, _parents, _reg, _shift, _width)			\
+	MUX_FLAGS(_id, _parents, _reg, _shift, _width, 0)
 
 #define MUX_CLR_SET_UPD_FLAGS(_id, _parents, _mux_ofs, _mux_set_ofs,\
 			_mux_clr_ofs, _shift, _width, _gate,		\
@@ -198,12 +250,22 @@
 struct mtk_clk_tree {
 	unsigned long xtal_rate;
 	unsigned long xtal2_rate;
+	/*
+	 * Clock ID offset are remapped with an auxiliary table.
+	 * Enable this by defining .id_offs_map.
+	 * This is needed for upstream linux kernel <soc>-clk.h that
+	 * have mixed clk ID and doesn't have clear distinction between
+	 * ID for factor, mux and gates.
+	 */
+	const int *id_offs_map; /* optional, table clk.h to driver ID */
 	const int fdivs_offs;
 	const int muxes_offs;
+	const int gates_offs;
 	const struct mtk_pll_data *plls;
 	const struct mtk_fixed_clk *fclks;
 	const struct mtk_fixed_factor *fdivs;
 	const struct mtk_composite *muxes;
+	const struct mtk_gate *gates;
 	u32 flags;
 };
 
@@ -227,6 +289,8 @@
 
 int mtk_common_clk_init(struct udevice *dev,
 			const struct mtk_clk_tree *tree);
+int mtk_common_clk_infrasys_init(struct udevice *dev,
+				 const struct mtk_clk_tree *tree);
 int mtk_common_clk_gate_init(struct udevice *dev,
 			     const struct mtk_clk_tree *tree,
 			     const struct mtk_gate *gates);
diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c
index 16f8f2e..2c8e46c 100644
--- a/drivers/cpu/cpu-uclass.c
+++ b/drivers/cpu/cpu-uclass.c
@@ -104,6 +104,16 @@
 	return ops->get_vendor(dev, buf, size);
 }
 
+int cpu_release_core(const struct udevice *dev, phys_addr_t addr)
+{
+	struct cpu_ops *ops = cpu_get_ops(dev);
+
+	if (!ops->release_core)
+		return -ENOSYS;
+
+	return ops->release_core(dev, addr);
+}
+
 U_BOOT_DRIVER(cpu_bus) = {
 	.name	= "cpu_bus",
 	.id	= UCLASS_SIMPLE_BUS,
diff --git a/drivers/cpu/cpu_sandbox.c b/drivers/cpu/cpu_sandbox.c
index e65e1bd..b152795 100644
--- a/drivers/cpu/cpu_sandbox.c
+++ b/drivers/cpu/cpu_sandbox.c
@@ -44,6 +44,11 @@
 	cpu_current = name;
 }
 
+static int cpu_sandbox_release_core(const struct udevice *dev, phys_addr_t addr)
+{
+	return 0;
+}
+
 static int cpu_sandbox_is_current(struct udevice *dev)
 {
 	if (!strcmp(dev->name, cpu_current))
@@ -58,6 +63,7 @@
 	.get_count = cpu_sandbox_get_count,
 	.get_vendor = cpu_sandbox_get_vendor,
 	.is_current = cpu_sandbox_is_current,
+	.release_core = cpu_sandbox_release_core,
 };
 
 static int cpu_sandbox_bind(struct udevice *dev)
diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c
index 4781a56..60deca9 100644
--- a/drivers/cpu/imx8_cpu.c
+++ b/drivers/cpu/imx8_cpu.c
@@ -1,12 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright 2019 NXP
+ * Copyright 2019, 2024 NXP
  */
 
 #include <cpu.h>
 #include <dm.h>
 #include <thermal.h>
 #include <asm/global_data.h>
+#include <asm/ptrace.h>
 #include <asm/system.h>
 #include <firmware/imx/sci/sci.h>
 #include <asm/arch/sys_proto.h>
@@ -15,6 +16,7 @@
 #include <imx_thermal.h>
 #include <linux/bitops.h>
 #include <linux/clk-provider.h>
+#include <linux/psci.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -31,6 +33,12 @@
 static const char *get_imx_type_str(u32 imxtype)
 {
 	switch (imxtype) {
+	case MXC_CPU_IMX8MM:
+		return "8MM";
+	case MXC_CPU_IMX8MN:
+		return "8MN";
+	case MXC_CPU_IMX8MP:
+		return "8MP";
 	case MXC_CPU_IMX8QXP:
 	case MXC_CPU_IMX8QXP_A0:
 		return "8QXP";
@@ -184,8 +192,6 @@
 			ret = snprintf(buf, size, " - invalid sensor data");
 	}
 
-	snprintf(buf + ret, size - ret, "\n");
-
 	return 0;
 }
 
@@ -193,7 +199,7 @@
 {
 	struct cpu_imx_plat *plat = dev_get_plat(dev);
 
-	info->cpu_freq = plat->freq_mhz * 1000;
+	info->cpu_freq = plat->freq_mhz * 1000000;
 	info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
 	return 0;
 }
@@ -236,12 +242,34 @@
 	return 0;
 }
 
+static int cpu_imx_release_core(const struct udevice *dev, phys_addr_t addr)
+{
+	struct cpu_imx_plat *plat = dev_get_plat(dev);
+	struct pt_regs regs;
+
+	regs.regs[0] = PSCI_0_2_FN64_CPU_ON;
+	regs.regs[1] = plat->mpidr;
+	regs.regs[2] = addr;
+	regs.regs[3] = 0;
+
+	smc_call(&regs);
+	if (regs.regs[0]) {
+		printf("Failed to release CPU core (mpidr: 0x%x)\n", plat->mpidr);
+		return -1;
+	}
+
+	printf("Released CPU core (mpidr: 0x%x) to address 0x%llx\n", plat->mpidr, addr);
+
+	return 0;
+}
+
 static const struct cpu_ops cpu_imx_ops = {
 	.get_desc	= cpu_imx_get_desc,
 	.get_info	= cpu_imx_get_info,
 	.get_count	= cpu_imx_get_count,
 	.get_vendor	= cpu_imx_get_vendor,
 	.is_current	= cpu_imx_is_current,
+	.release_core	= cpu_imx_release_core,
 };
 
 static const struct udevice_id cpu_imx_ids[] = {
@@ -287,7 +315,7 @@
 	cpurev = get_cpu_rev();
 	plat->cpurev = cpurev;
 	plat->rev = get_imx_rev_str(cpurev & 0xFFF);
-	plat->type = get_imx_type_str((cpurev & 0xFF000) >> 12);
+	plat->type = get_imx_type_str((cpurev & 0x1FF000) >> 12);
 	plat->freq_mhz = imx_get_cpu_rate(dev) / 1000000;
 	plat->mpidr = dev_read_addr(dev);
 	if (plat->mpidr == FDT_ADDR_T_NONE) {
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 67ac86f..43f0ec7 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -50,6 +50,7 @@
 #include <asm/arch/clock.h>
 #include <asm/mach-imx/sys_proto.h>
 #endif
+#include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/printk.h>
 
@@ -146,6 +147,25 @@
 				 1000000, true);
 }
 
+/* Bitmask common for mdio_read and mdio_write */
+#define EQOS_MDIO_BITFIELD(pa, rda, cr) \
+	FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_PA_MASK, pa)   | \
+	FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_RDA_MASK, rda) | \
+	FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_CR_MASK, cr)   | \
+	EQOS_MAC_MDIO_ADDRESS_GB
+
+static u32 eqos_mdio_bitfield(struct eqos_priv *eqos, int addr, int devad, int reg)
+{
+	int cr = eqos->config->config_mac_mdio;
+	bool c22 = devad == MDIO_DEVAD_NONE ? true : false;
+
+	if (c22)
+		return EQOS_MDIO_BITFIELD(addr, reg, cr);
+	else
+		return EQOS_MDIO_BITFIELD(addr, devad, cr) |
+		       EQOS_MAC_MDIO_ADDRESS_C45E;
+}
+
 static int eqos_mdio_read(struct mii_dev *bus, int mdio_addr, int mdio_devad,
 			  int mdio_reg)
 {
@@ -163,15 +183,17 @@
 	}
 
 	val = readl(&eqos->mac_regs->mdio_address);
-	val &= EQOS_MAC_MDIO_ADDRESS_SKAP |
-		EQOS_MAC_MDIO_ADDRESS_C45E;
-	val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) |
-		(mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) |
-		(eqos->config->config_mac_mdio <<
-		 EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) |
-		(EQOS_MAC_MDIO_ADDRESS_GOC_READ <<
-		 EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) |
-		EQOS_MAC_MDIO_ADDRESS_GB;
+	val &= EQOS_MAC_MDIO_ADDRESS_SKAP;
+
+	val |= eqos_mdio_bitfield(eqos, mdio_addr, mdio_devad, mdio_reg) |
+	       FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_GOC_MASK,
+			  EQOS_MAC_MDIO_ADDRESS_GOC_READ);
+
+	if (val & EQOS_MAC_MDIO_ADDRESS_C45E) {
+		writel(FIELD_PREP(EQOS_MAC_MDIO_DATA_RA_MASK, mdio_reg),
+		       &eqos->mac_regs->mdio_data);
+	}
+
 	writel(val, &eqos->mac_regs->mdio_address);
 
 	udelay(eqos->config->mdio_wait);
@@ -194,7 +216,8 @@
 			   int mdio_reg, u16 mdio_val)
 {
 	struct eqos_priv *eqos = bus->priv;
-	u32 val;
+	u32 v_addr;
+	u32 v_data;
 	int ret;
 
 	debug("%s(dev=%p, addr=%x, reg=%d, val=%x):\n", __func__, eqos->dev,
@@ -206,20 +229,19 @@
 		return ret;
 	}
 
-	writel(mdio_val, &eqos->mac_regs->mdio_data);
+	v_addr = readl(&eqos->mac_regs->mdio_address);
+	v_addr &= EQOS_MAC_MDIO_ADDRESS_SKAP;
 
-	val = readl(&eqos->mac_regs->mdio_address);
-	val &= EQOS_MAC_MDIO_ADDRESS_SKAP |
-		EQOS_MAC_MDIO_ADDRESS_C45E;
-	val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) |
-		(mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) |
-		(eqos->config->config_mac_mdio <<
-		 EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) |
-		(EQOS_MAC_MDIO_ADDRESS_GOC_WRITE <<
-		 EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) |
-		EQOS_MAC_MDIO_ADDRESS_GB;
-	writel(val, &eqos->mac_regs->mdio_address);
+	v_addr |= eqos_mdio_bitfield(eqos, mdio_addr, mdio_devad, mdio_reg) |
+	       FIELD_PREP(EQOS_MAC_MDIO_ADDRESS_GOC_MASK,
+			  EQOS_MAC_MDIO_ADDRESS_GOC_WRITE);
 
+	v_data = mdio_val;
+	if (v_addr & EQOS_MAC_MDIO_ADDRESS_C45E)
+		v_data |= FIELD_PREP(EQOS_MAC_MDIO_DATA_RA_MASK, mdio_reg);
+
+	writel(v_data, &eqos->mac_regs->mdio_data);
+	writel(v_addr, &eqos->mac_regs->mdio_address);
 	udelay(eqos->config->mdio_wait);
 
 	ret = eqos_mdio_wait_idle(eqos);
diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h
index 8b3d0d4..a06390a 100644
--- a/drivers/net/dwc_eth_qos.h
+++ b/drivers/net/dwc_eth_qos.h
@@ -79,19 +79,20 @@
 #define EQOS_MAC_HW_FEATURE3_ASP_SHIFT			28
 #define EQOS_MAC_HW_FEATURE3_ASP_MASK			0x3
 
-#define EQOS_MAC_MDIO_ADDRESS_PA_SHIFT			21
-#define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT			16
-#define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT			8
+#define EQOS_MAC_MDIO_ADDRESS_PA_MASK			GENMASK(25, 21)
+#define EQOS_MAC_MDIO_ADDRESS_RDA_MASK			GENMASK(20, 16)
+#define EQOS_MAC_MDIO_ADDRESS_CR_MASK			GENMASK(11, 8)
 #define EQOS_MAC_MDIO_ADDRESS_CR_100_150		1
 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35			2
 #define EQOS_MAC_MDIO_ADDRESS_CR_250_300		5
 #define EQOS_MAC_MDIO_ADDRESS_SKAP			BIT(4)
-#define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT			2
+#define EQOS_MAC_MDIO_ADDRESS_GOC_MASK			GENMASK(3, 2)
 #define EQOS_MAC_MDIO_ADDRESS_GOC_READ			3
 #define EQOS_MAC_MDIO_ADDRESS_GOC_WRITE			1
 #define EQOS_MAC_MDIO_ADDRESS_C45E			BIT(1)
 #define EQOS_MAC_MDIO_ADDRESS_GB			BIT(0)
 
+#define EQOS_MAC_MDIO_DATA_RA_MASK			GENMASK(31, 16)
 #define EQOS_MAC_MDIO_DATA_GD_MASK			0xffff
 
 #define EQOS_MTL_REGS_BASE 0xd00
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index ec0068e..77a1558 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -138,8 +138,6 @@
 		return 0;
 
 	os_usleep(100);
-	if (IS_ENABLED(CONFIG_VIDEO) && !IS_ENABLED(CONFIG_SPL_BUILD))
-		video_sync_all();
 	avail = membuff_putraw(&priv->buf, 100, false, &data);
 	if (!avail)
 		return 1;	/* buffer full */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 7808ae7..6e79694 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -7,6 +7,7 @@
 config VIDEO
 	bool "Enable driver model support for LCD/video"
 	depends on DM
+	imply CYCLIC
 	help
 	  This enables driver model for LCD and video devices. These support
 	  a bitmap display of various sizes and depths which can be drawn on
@@ -14,6 +15,11 @@
 	  option compiles in the video uclass and routes all LCD/video access
 	  through this.
 
+	  If CYCLIC is enabled (which it is by default), the cyclic subsystem
+	  is used to flush pending output to the display periodically, rather
+	  than this happening with every chunk of output. This allows for more
+	  efficient operation and faster display output.
+
 if VIDEO
 
 config VIDEO_FONT_4X6
@@ -232,6 +238,35 @@
 	  loads takes over the screen.  This, for example, can be used to
 	  keep splash image on screen until grub graphical boot menu starts.
 
+config VIDEO_SYNC_MS
+	int "Video-sync period in milliseconds for foreground processing"
+	default 300 if SANDBOX
+	default 100
+	help
+	  This sets the requested, maximum time before a video sync will take
+	  place, in milliseconds. Note that the time between video syncs
+	  may be longer than this, since syncs only happen when the video system
+	  is used, e.g. by outputting a character to the console.
+
+	  It may also be shorter, since the video uclass will automatically
+	  force a sync in certain situations.
+
+	  Many video-output systems require a sync operation before any output
+	  is visible. This may flush the CPU cache or perhaps copy the
+	  display contents to a hardware framebuffer. Without this, change to
+	  the video may never be displayed.
+
+config VIDEO_SYNC_CYCLIC_MS
+	int "Video-sync period in milliseconds for cyclic processing"
+	depends on CYCLIC
+	default 100 if SANDBOX
+	default 10
+	help
+	  This sets the frequency of cyclic video syncs. The cyclic system is
+	  used to ensure that when U-Boot is idle, it syncs the video. This
+	  improves the responsiveness of the command line to new characters
+	  being entered.
+
 config PANEL
 	bool "Enable panel uclass support"
 	default y
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
index ff1382f..a5aa8dd 100644
--- a/drivers/video/video-uclass.c
+++ b/drivers/video/video-uclass.c
@@ -8,6 +8,7 @@
 #include <bloblist.h>
 #include <console.h>
 #include <cpu_func.h>
+#include <cyclic.h>
 #include <dm.h>
 #include <log.h>
 #include <malloc.h>
@@ -52,6 +53,8 @@
  */
 DECLARE_GLOBAL_DATA_PTR;
 
+struct cyclic_info;
+
 /**
  * struct video_uc_priv - Information for the video uclass
  *
@@ -60,9 +63,12 @@
  *	available address to use for a device's framebuffer. It starts at
  *	gd->video_top and works downwards, running out of space when it hits
  *	gd->video_bottom.
+ * @cyc: handle for cyclic-execution function, or NULL if none
  */
 struct video_uc_priv {
 	ulong video_ptr;
+	bool cyc_active;
+	struct cyclic_info cyc;
 };
 
 /** struct vid_rgb - Describes a video colour */
@@ -349,6 +355,7 @@
 /* Flush video activity to the caches */
 int video_sync(struct udevice *vid, bool force)
 {
+	struct video_priv *priv = dev_get_uclass_priv(vid);
 	struct video_ops *ops = video_get_ops(vid);
 	int ret;
 
@@ -358,28 +365,26 @@
 			return ret;
 	}
 
+	if (CONFIG_IS_ENABLED(CYCLIC) && !force &&
+	    get_timer(priv->last_sync) < CONFIG_VIDEO_SYNC_MS)
+		return 0;
+
 	/*
 	 * flush_dcache_range() is declared in common.h but it seems that some
 	 * architectures do not actually implement it. Is there a way to find
 	 * out whether it exists? For now, ARM is safe.
 	 */
 #if defined(CONFIG_ARM) && !CONFIG_IS_ENABLED(SYS_DCACHE_OFF)
-	struct video_priv *priv = dev_get_uclass_priv(vid);
-
 	if (priv->flush_dcache) {
 		flush_dcache_range((ulong)priv->fb,
 				   ALIGN((ulong)priv->fb + priv->fb_size,
 					 CONFIG_SYS_CACHELINE_SIZE));
 	}
 #elif defined(CONFIG_VIDEO_SANDBOX_SDL)
-	struct video_priv *priv = dev_get_uclass_priv(vid);
-	static ulong last_sync;
-
-	if (force || get_timer(last_sync) > 100) {
-		sandbox_sdl_sync(priv->fb);
-		last_sync = get_timer(0);
-	}
+	sandbox_sdl_sync(priv->fb);
 #endif
+	priv->last_sync = get_timer(0);
+
 	return 0;
 }
 
@@ -528,10 +533,16 @@
 	return vc_priv->y_charsize;
 }
 
+static void video_idle(struct cyclic_info *cyc)
+{
+	video_sync_all();
+}
+
 /* Set up the display ready for use */
 static int video_post_probe(struct udevice *dev)
 {
 	struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+	struct video_uc_priv *uc_priv = uclass_get_priv(dev->uclass);
 	struct video_priv *priv = dev_get_uclass_priv(dev);
 	char name[30], drv[15], *str;
 	const char *drv_name = drv;
@@ -622,6 +633,16 @@
 		}
 	}
 
+	/* register cyclic as soon as the first video device is probed */
+	if (CONFIG_IS_ENABLED(CYCLIC) && (gd->flags && GD_FLG_RELOC) &&
+	    !uc_priv->cyc_active) {
+		uint ms = CONFIG_IF_ENABLED_INT(CYCLIC, VIDEO_SYNC_CYCLIC_MS);
+
+		cyclic_register(&uc_priv->cyc, video_idle, ms * 1000,
+				"video_init");
+		uc_priv->cyc_active = true;
+	}
+
 	return 0;
 };
 
@@ -661,6 +682,18 @@
 	return 0;
 }
 
+__maybe_unused static int video_destroy(struct uclass *uc)
+{
+	struct video_uc_priv *uc_priv = uclass_get_priv(uc);
+
+	if (uc_priv->cyc_active) {
+		cyclic_unregister(&uc_priv->cyc);
+		uc_priv->cyc_active = false;
+	}
+
+	return 0;
+}
+
 UCLASS_DRIVER(video) = {
 	.id		= UCLASS_VIDEO,
 	.name		= "video",
@@ -670,4 +703,5 @@
 	.priv_auto	= sizeof(struct video_uc_priv),
 	.per_device_auto	= sizeof(struct video_priv),
 	.per_device_plat_auto	= sizeof(struct video_uc_plat),
+	CONFIG_IS_ENABLED(CYCLIC, (.destroy = video_destroy, ))
 };
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 8318fd7..0c3e991 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -4,6 +4,7 @@
 	bool "Enable U-Boot watchdog reset"
 	depends on !HW_WATCHDOG
 	select CYCLIC
+	imply SPL_CYCLIC if SPL
 	help
 	  This option enables U-Boot watchdog support where U-Boot is using
 	  watchdog_reset function to service watchdog device in U-Boot. Enable
@@ -408,6 +409,7 @@
 config SPL_WDT
 	bool "Enable driver model for watchdog timer drivers in SPL"
 	depends on SPL_DM
+	select SPL_CYCLIC if CYCLIC
 	help
 	  Enable driver model for watchdog timer in SPL.
 	  This is similar to CONFIG_WDT in U-Boot.
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index aa336d6..27aa75e 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -481,7 +481,7 @@
 	 */
 	struct event_state event_state;
 #endif
-#ifdef CONFIG_CYCLIC
+#if CONFIG_IS_ENABLED(CYCLIC)
 	/**
 	 * @cyclic_list: list of registered cyclic functions
 	 */
diff --git a/include/clk.h b/include/clk.h
index af23e4f..045e923 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -444,7 +444,7 @@
 struct clk *clk_get_parent(struct clk *clk);
 
 /**
- * clk_get_parent_rate() - Get parent of current clock rate.
+ * clk_get_parent_rate() - Get rate of current clock's parent.
  * @clk:	A clock struct that was previously successfully requested by
  *		clk_request/get_by_*().
  *
diff --git a/include/cpu.h b/include/cpu.h
index 2077ff3..0018910 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -102,6 +102,15 @@
 	 *         if not.
 	 */
 	int (*is_current)(struct udevice *dev);
+
+	/**
+	 * release_core() - Relase a CPU core to the given address to run application
+	 *
+	 * @dev:	Device to check (UCLASS_CPU)
+	 * @addr:	Address to relese the CPU core
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*release_core)(const struct udevice *dev, phys_addr_t addr);
 };
 
 #define cpu_get_ops(dev)        ((struct cpu_ops *)(dev)->driver->ops)
@@ -164,4 +173,10 @@
  */
 struct udevice *cpu_get_current_dev(void);
 
+/**
+ * cpu_release_core() - Relase a CPU core to the given address to run application
+ *
+ * @return 0 if OK, -ve on error
+ */
+int cpu_release_core(const struct udevice *dev, phys_addr_t addr);
 #endif
diff --git a/include/cyclic.h b/include/cyclic.h
index 2c3d383..cd95b69 100644
--- a/include/cyclic.h
+++ b/include/cyclic.h
@@ -46,7 +46,8 @@
 /** Function type for cyclic functions */
 typedef void (*cyclic_func_t)(struct cyclic_info *c);
 
-#if defined(CONFIG_CYCLIC)
+#if CONFIG_IS_ENABLED(CYCLIC)
+
 /**
  * cyclic_register - Register a new cyclic function
  *
@@ -123,6 +124,6 @@
 {
 	return 0;
 }
-#endif
+#endif /* CYCLIC */
 
 #endif
diff --git a/include/video.h b/include/video.h
index 4d8df9b..4013a94 100644
--- a/include/video.h
+++ b/include/video.h
@@ -97,6 +97,7 @@
  *		the LCD is updated
  * @fg_col_idx:	Foreground color code (bit 3 = bold, bit 0-2 = color)
  * @bg_col_idx:	Background color code (bit 3 = bold, bit 0-2 = color)
+ * @last_sync:	Monotonic time of last video sync
  */
 struct video_priv {
 	/* Things set up by the driver: */
@@ -121,6 +122,7 @@
 	bool flush_dcache;
 	u8 fg_col_idx;
 	u8 bg_col_idx;
+	ulong last_sync;
 };
 
 /**
diff --git a/net/eth_internal.h b/net/eth_internal.h
index 0b829a8..cb302c1 100644
--- a/net/eth_internal.h
+++ b/net/eth_internal.h
@@ -11,22 +11,6 @@
 /* Do init that is common to driver model and legacy networking */
 void eth_common_init(void);
 
-/**
- * eth_env_set_enetaddr_by_index() - set the MAC address environment variable
- *
- * This sets up an environment variable with the given MAC address (@enetaddr).
- * The environment variable to be set is defined by <@base_name><@index>addr.
- * If @index is 0 it is omitted. For common Ethernet this means ethaddr,
- * eth1addr, etc.
- *
- * @base_name:	Base name for variable, typically "eth"
- * @index:	Index of interface being updated (>=0)
- * @enetaddr:	Pointer to MAC address to put into the variable
- * Return: 0 if OK, other value on error
- */
-int eth_env_set_enetaddr_by_index(const char *base_name, int index,
-				 uchar *enetaddr);
-
 int eth_mac_skip(int index);
 void eth_current_changed(void);
 void eth_set_dev(struct udevice *dev);
diff --git a/net/tftp.c b/net/tftp.c
index 65c39d7..2e07318 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -493,8 +493,15 @@
 				tftp_prev_block = tftp_cur_block;
 				tftp_cur_block = (unsigned short)(block + 1);
 				update_block_number();
-				if (ack_ok)
+				if (ack_ok) {
+					if (block == 0 &&
+					    tftp_state == STATE_SEND_WRQ){
+						/* connection's first ACK */
+						tftp_state = STATE_DATA;
+						tftp_remote_port = src;
+					}
 					tftp_send(); /* Send next data block */
+				}
 			}
 		}
 #endif
diff --git a/test/dm/cpu.c b/test/dm/cpu.c
index acba810..8af2531 100644
--- a/test/dm/cpu.c
+++ b/test/dm/cpu.c
@@ -43,6 +43,8 @@
 	ut_assertok(cpu_get_vendor(dev, text, sizeof(text)));
 	ut_assertok(strcmp(text, "Languid Example Garbage Inc."));
 
+	ut_assertok(cpu_release_core(dev, 0));
+
 	return 0;
 }