Merge branch 'qcom-main' of https://source.denx.de/u-boot/custodians/u-boot-snapdragon

Various minor fixes and improvements:

* Fix Qualcomm SPMI v5 support
* Move default environment to a file
* Add support for special pins (e.g ufs/mmc reset/data pins)
* IPQ moves to OF_UPSTREAM and receives some cleanup and MAINTAINERS
  changes
* Add a reset driver for devices without PSCI
* msm8916 USB clock improvements for mobile devices
diff --git a/MAINTAINERS b/MAINTAINERS
index 6b32a6d..2c6de3a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -334,17 +334,16 @@
 
 ARM IPQ40XX
 M:	Robert Marko <robert.marko@sartura.hr>
-M:	Luka Kovacic <luka.kovacic@sartura.hr>
 M:	Luka Perkov <luka.perkov@sartura.hr>
 S:	Maintained
 F:	arch/arm/mach-ipq40xx/
-F:	include/dt-bindings/clock/qcom,ipq4019-gcc.h
-F:	include/dt-bindings/reset/qcom,ipq4019-reset.h
-F:	drivers/reset/reset-ipq4019.c
+F:	include/dt-bindings/clock/qcom,gcc-ipq4019.h
+F:	drivers/clk/qcom/clock-ipq4019.c
 F:	drivers/phy/phy-qcom-ipq4019-usb.c
 F:	drivers/spi/spi-qup.c
 F:	drivers/net/mdio-ipq4019.c
 F:	drivers/rng/msm_rng.c
+F:	drivers/pinctrl/qcom/pinctrl-ipq4019.c
 
 ARM LAYERSCAPE SFP
 M:	Sean Anderson <sean.anderson@seco.com>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index db692b2..ba0359f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -769,6 +769,7 @@
 	select CLK_QCOM_IPQ4019
 	select PINCTRL_QCOM_IPQ4019
 	imply CMD_DM
+	imply OF_UPSTREAM
 
 config ARCH_KEYSTONE
 	bool "TI Keystone"
diff --git a/arch/arm/dts/qcom-ipq4019.dtsi b/arch/arm/dts/qcom-ipq4019.dtsi
deleted file mode 100644
index f9489e4..0000000
--- a/arch/arm/dts/qcom-ipq4019.dtsi
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2019 Sartura Ltd.
- *
- * Author: Robert Marko <robert.marko@sartura.hr>
- */
-
- /dts-v1/;
-
-#include "skeleton.dtsi"
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/clock/qcom,ipq4019-gcc.h>
-#include <dt-bindings/reset/qcom,ipq4019-reset.h>
-
-/ {
-	#address-cells = <1>;
-	#size-cells = <1>;
-
-	model = "Qualcomm Technologies, Inc. IPQ4019";
-	compatible = "qcom,ipq4019";
-
-	aliases {
-		serial0 = &blsp1_uart1;
-		spi0 = &blsp1_spi1;
-	};
-
-	reserved-memory {
-		#address-cells = <0x1>;
-		#size-cells = <0x1>;
-		ranges;
-
-		smem_mem: smem_region: smem@87e00000 {
-			reg = <0x87e00000 0x080000>;
-			no-map;
-		};
-
-		tz@87e80000 {
-			reg = <0x87e80000 0x180000>;
-			no-map;
-		};
-	};
-
-	smem {
-		compatible = "qcom,smem";
-		memory-region = <&smem_mem>;
-	};
-
-	soc: soc {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		ranges;
-		compatible = "simple-bus";
-
-		gcc: clock-controller@1800000 {
-			compatible = "qcom,gcc-ipq4019";
-			reg = <0x1800000 0x60000>;
-			#clock-cells = <1>;
-			#reset-cells = <1>;
-			bootph-all;
-		};
-
-		rng: rng@22000 {
-			compatible = "qcom,prng";
-			reg = <0x22000 0x140>;
-			clocks = <&gcc GCC_PRNG_AHB_CLK>;
-			status = "disabled";
-		};
-
-		soc_gpios: pinctrl@1000000 {
-			compatible = "qcom,ipq4019-pinctrl";
-			reg = <0x1000000 0x300000>;
-			gpio-controller;
-			gpio-count = <100>;
-			gpio-bank-name="soc";
-			#gpio-cells = <2>;
-			bootph-all;
-		};
-
-		blsp1_uart1: serial@78af000 {
-			compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
-			reg = <0x78af000 0x200>;
-			clock = <&gcc GCC_BLSP1_UART1_APPS_CLK>;
-			bit-rate = <0xFF>;
-			status = "disabled";
-			bootph-all;
-		};
-
-		blsp1_spi1: spi@78b5000 {
-			compatible = "qcom,spi-qup-v2.2.1";
-			reg = <0x78b5000 0x600>;
-			clocks = <&gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>;
-			#address-cells = <1>;
-			#size-cells = <0>;
-			status = "disabled";
-			bootph-all;
-		};
-
-		mdio: mdio@90000 {
-			#address-cells = <1>;
-			#size-cells = <0>;
-			compatible = "qcom,ipq4019-mdio";
-			reg = <0x90000 0x64>;
-			status = "disabled";
-
-			ethphy0: ethernet-phy@0 {
-				reg = <0>;
-			};
-
-			ethphy1: ethernet-phy@1 {
-				reg = <1>;
-			};
-
-			ethphy2: ethernet-phy@2 {
-				reg = <2>;
-			};
-
-			ethphy3: ethernet-phy@3 {
-				reg = <3>;
-			};
-
-			ethphy4: ethernet-phy@4 {
-				reg = <4>;
-			};
-		};
-
-		usb3_ss_phy: ssphy@9a000 {
-			compatible = "qcom,usb-ss-ipq4019-phy";
-			#phy-cells = <0>;
-			reg = <0x9a000 0x800>;
-			reg-names = "phy_base";
-			resets = <&gcc USB3_UNIPHY_PHY_ARES>;
-			reset-names = "por_rst";
-			status = "disabled";
-		};
-
-		usb3_hs_phy: hsphy@a6000 {
-			compatible = "qcom,usb-hs-ipq4019-phy";
-			#phy-cells = <0>;
-			reg = <0xa6000 0x40>;
-			reg-names = "phy_base";
-			resets = <&gcc USB3_HSPHY_POR_ARES>, <&gcc USB3_HSPHY_S_ARES>;
-			reset-names = "por_rst", "srif_rst";
-			status = "disabled";
-		};
-
-		usb3: usb3@8af8800 {
-			compatible = "qcom,dwc3";
-			reg = <0x8af8800 0x100>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			clocks = <&gcc GCC_USB3_MASTER_CLK>,
-				 <&gcc GCC_USB3_SLEEP_CLK>,
-				 <&gcc GCC_USB3_MOCK_UTMI_CLK>;
-			clock-names = "master", "sleep", "mock_utmi";
-			ranges;
-			status = "disabled";
-
-			dwc3@8a00000 {
-				compatible = "snps,dwc3";
-				reg = <0x8a00000 0xf8000>;
-				phys = <&usb3_hs_phy>, <&usb3_ss_phy>;
-				phy-names = "usb2-phy", "usb3-phy";
-				dr_mode = "host";
-				maximum-speed = "super-speed";
-				snps,dis_u2_susphy_quirk;
-			};
-		};
-
-		usb2_hs_phy: hsphy@a8000 {
-			compatible = "qcom,usb-hs-ipq4019-phy";
-			#phy-cells = <0>;
-			reg = <0xa8000 0x40>;
-			reg-names = "phy_base";
-			resets = <&gcc USB2_HSPHY_POR_ARES>, <&gcc USB2_HSPHY_S_ARES>;
-			reset-names = "por_rst", "srif_rst";
-			status = "disabled";
-		};
-
-		usb2: usb2@60f8800 {
-			compatible = "qcom,dwc3";
-			reg = <0x60f8800 0x100>;
-			#address-cells = <1>;
-			#size-cells = <1>;
-			clocks = <&gcc GCC_USB2_MASTER_CLK>,
-				 <&gcc GCC_USB2_SLEEP_CLK>,
-				 <&gcc GCC_USB2_MOCK_UTMI_CLK>;
-			clock-names = "master", "sleep", "mock_utmi";
-			ranges;
-			status = "disabled";
-
-			dwc3@6000000 {
-				compatible = "snps,dwc3";
-				reg = <0x6000000 0xf8000>;
-				phys = <&usb2_hs_phy>;
-				phy-names = "usb2-phy";
-				dr_mode = "host";
-				maximum-speed = "high-speed";
-				snps,dis_u2_susphy_quirk;
-			};
-		};
-	};
-};
diff --git a/arch/arm/mach-ipq40xx/Makefile b/arch/arm/mach-ipq40xx/Makefile
new file mode 100644
index 0000000..d611de9
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2024 Sartura Ltd.
+#
+# Author: Robert Marko <robert.marko@sartura.hr>
+
+obj-y += cpu.o
diff --git a/arch/arm/mach-ipq40xx/cpu.c b/arch/arm/mach-ipq40xx/cpu.c
new file mode 100644
index 0000000..92c34d6
--- /dev/null
+++ b/arch/arm/mach-ipq40xx/cpu.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * CPU code for Qualcomm IPQ40xx SoC
+ *
+ * Copyright (c) 2024 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ */
+
+#include <cpu_func.h>
+#include <init.h>
+
+int dram_init(void)
+{
+	int ret;
+
+	ret = fdtdec_setup_memory_banksize();
+	if (ret)
+		return ret;
+	return fdtdec_setup_mem_size_base();
+}
+
+/*
+ * Enable/Disable D-cache.
+ * I-cache is already enabled in start.S
+ */
+void enable_caches(void)
+{
+	dcache_enable();
+}
+
+void disable_caches(void)
+{
+	dcache_disable();
+}
+
+/*
+ * In case boards need specific init code, they can override this stub.
+ */
+int __weak board_init(void)
+{
+	return 0;
+}
diff --git a/arch/arm/mach-snapdragon/include/mach/gpio.h b/arch/arm/mach-snapdragon/include/mach/gpio.h
index 53c6ae0..cc8f405 100644
--- a/arch/arm/mach-snapdragon/include/mach/gpio.h
+++ b/arch/arm/mach-snapdragon/include/mach/gpio.h
@@ -10,11 +10,25 @@
 #include <asm/types.h>
 #include <stdbool.h>
 
+struct msm_special_pin_data {
+	char *name;
+
+	u32 ctl_reg;
+	u32 io_reg;
+
+	unsigned pull_bit:5;
+	unsigned drv_bit:5;
+
+	unsigned oe_bit:5;
+	unsigned in_bit:5;
+	unsigned out_bit:5;
+};
+
 struct msm_pin_data {
 	int pin_count;
 	const unsigned int *pin_offsets;
-	/* Index of first special pin, these are ignored for now */
 	unsigned int special_pins_start;
+	const struct msm_special_pin_data *special_pins_data;
 };
 
 static inline u32 qcom_pin_offset(const unsigned int *offs, unsigned int selector)
diff --git a/board/qualcomm/default.env b/board/qualcomm/default.env
new file mode 100644
index 0000000..dbf6f4e
--- /dev/null
+++ b/board/qualcomm/default.env
@@ -0,0 +1,11 @@
+stdin=serial,button-kbd
+stdout=serial,vidconsole
+stderr=serial,vidconsole
+preboot=scsi scan; usb start
+fastboot=fastboot -l $fastboot_addr_r usb 0
+do_boot=bootefi bootmgr
+bootmenu_0=Boot first available device=run do_boot
+bootmenu_1=Enable fastboot mode=run fastboot
+bootmenu_2=Reset device=reset
+menucmd=bootmenu
+bootcmd=run do_boot
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig
index 37966bf..4942237 100644
--- a/configs/qcom_defconfig
+++ b/configs/qcom_defconfig
@@ -36,7 +36,11 @@
 CONFIG_CMD_LOG=y
 CONFIG_OF_LIVE=y
 CONFIG_BUTTON_QCOM_PMIC=y
+CONFIG_USE_DEFAULT_ENV_FILE=y
+CONFIG_DEFAULT_ENV_FILE="board/qualcomm/default.env"
 CONFIG_CLK=y
+CONFIG_CLK_QCOM_APQ8016=y
+CONFIG_CLK_QCOM_APQ8096=y
 CONFIG_CLK_QCOM_QCM2290=y
 CONFIG_CLK_QCOM_QCS404=y
 CONFIG_CLK_QCOM_SDM845=y
@@ -73,6 +77,8 @@
 CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=y
 CONFIG_PHY_QCOM_SNPS_EUSB2=y
 CONFIG_PINCTRL=y
+CONFIG_PINCTRL_QCOM_APQ8016=y
+CONFIG_PINCTRL_QCOM_APQ8096=y
 CONFIG_PINCTRL_QCOM_QCM2290=y
 CONFIG_PINCTRL_QCOM_QCS404=y
 CONFIG_PINCTRL_QCOM_SDM845=y
diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c
index 41fe4d8..b5def55 100644
--- a/drivers/clk/qcom/clock-apq8016.c
+++ b/drivers/clk/qcom/clock-apq8016.c
@@ -16,6 +16,8 @@
 
 #include "clock-qcom.h"
 
+#define USB_HS_SYSTEM_CLK_CMD_RCGR	0x41010
+
 /* Clocks: (from CLK_CTL_BASE)  */
 #define GPLL0_STATUS			(0x2101C)
 #define APCS_GPLL_ENA_VOTE		(0x45000)
@@ -51,6 +53,11 @@
 	.vote_bit = BIT(10),
 };
 
+static const struct gate_clk apq8016_clks[] = {
+	GATE_CLK(GCC_USB_HS_AHB_CLK,    0x41008, 0x00000001),
+	GATE_CLK(GCC_USB_HS_SYSTEM_CLK,	0x41004, 0x00000001),
+};
+
 /* SDHCI */
 static int apq8016_clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate)
 {
@@ -116,13 +123,38 @@
 	case GCC_BLSP1_UART2_APPS_CLK: /* UART2 */
 		apq8016_clk_init_uart(priv->base, clk->id);
 		return 7372800;
+	case GCC_USB_HS_SYSTEM_CLK:
+		if (rate != 80000000)
+			log_warning("Unexpected rate %ld requested for USB_HS_SYSTEM_CLK\n",
+				    rate);
+		clk_rcg_set_rate_mnd(priv->base, USB_HS_SYSTEM_CLK_CMD_RCGR,
+				     10, 0, 0, CFG_CLK_SRC_GPLL0, 0);
+		return rate;
 	default:
 		return 0;
 	}
 }
 
+static int apq8016_clk_enable(struct clk *clk)
+{
+	struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
+	if (priv->data->num_clks < clk->id) {
+		log_warning("%s: unknown clk id %lu\n", __func__, clk->id);
+		return 0;
+	}
+
+	debug("%s: clk %s\n", __func__, apq8016_clks[clk->id].name);
+	qcom_gate_clk_en(priv, clk->id);
+
+	return 0;
+}
+
 static struct msm_clk_data apq8016_clk_data = {
 	.set_rate = apq8016_clk_set_rate,
+	.clks = apq8016_clks,
+	.num_clks = ARRAY_SIZE(apq8016_clks),
+	.enable = apq8016_clk_enable,
 };
 
 static const struct udevice_id gcc_apq8016_of_match[] = {
diff --git a/drivers/clk/qcom/clock-ipq4019.c b/drivers/clk/qcom/clock-ipq4019.c
index 0e6d93b..9352ff4 100644
--- a/drivers/clk/qcom/clock-ipq4019.c
+++ b/drivers/clk/qcom/clock-ipq4019.c
@@ -15,6 +15,12 @@
 
 #include "clock-qcom.h"
 
+/* I2C controller clock control registerss */
+#define BLSP1_QUP1_I2C_APPS_CBCR	(0x2008)
+#define BLSP1_QUP1_I2C_APPS_CMD_RCGR	(0x200C)
+#define BLSP1_QUP2_I2C_APPS_CBCR	(0x3010)
+#define BLSP1_QUP2_I2C_APPS_CMD_RCGR	(0x3000)
+
 static ulong ipq4019_clk_set_rate(struct clk *clk, ulong rate)
 {
 	switch (clk->id) {
@@ -28,7 +34,22 @@
 
 static int ipq4019_clk_enable(struct clk *clk)
 {
+	struct msm_clk_priv *priv = dev_get_priv(clk->dev);
+
 	switch (clk->id) {
+	case GCC_BLSP1_AHB_CLK:
+		/* This clock is already initialized by SBL1 */
+		return 0;
+	case GCC_BLSP1_QUP1_I2C_APPS_CLK:
+		clk_enable_cbc(priv->base + BLSP1_QUP1_I2C_APPS_CBCR);
+		clk_rcg_set_rate(priv->base, BLSP1_QUP1_I2C_APPS_CMD_RCGR, 0,
+				 CFG_CLK_SRC_CXO);
+		return 0;
+	case GCC_BLSP1_QUP2_I2C_APPS_CLK:
+		clk_enable_cbc(priv->base + BLSP1_QUP2_I2C_APPS_CBCR);
+		clk_rcg_set_rate(priv->base, BLSP1_QUP2_I2C_APPS_CMD_RCGR, 0,
+				 CFG_CLK_SRC_CXO);
+		return 0;
 	case GCC_BLSP1_QUP1_SPI_APPS_CLK: /*SPI1*/
 		/* This clock is already initialized by SBL1 */
 		return 0;
diff --git a/drivers/pinctrl/qcom/pinctrl-qcom.c b/drivers/pinctrl/qcom/pinctrl-qcom.c
index 3c3336e..26a3fba 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcom.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcom.c
@@ -44,6 +44,7 @@
 	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 2 },
 	{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
 	{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 3 },
+	{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_UP, 1 },
 	{ "output-high", PIN_CONFIG_OUTPUT, 1, },
 	{ "output-low", PIN_CONFIG_OUTPUT, 0, },
 };
@@ -102,14 +103,47 @@
 	return 0;
 }
 
+static int msm_pinconf_set_special(struct msm_pinctrl_priv *priv, unsigned int pin_selector,
+				   unsigned int param, unsigned int argument)
+{
+	unsigned int offset = pin_selector - priv->data->pin_data.special_pins_start;
+	const struct msm_special_pin_data *data;
+
+	if (!priv->data->pin_data.special_pins_data)
+		return 0;
+
+	data = &priv->data->pin_data.special_pins_data[offset];
+
+	switch (param) {
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		argument = (argument / 2) - 1;
+		clrsetbits_le32(priv->base + data->ctl_reg,
+				GENMASK(2, 0) << data->drv_bit,
+				argument << data->drv_bit);
+		break;
+	case PIN_CONFIG_BIAS_DISABLE:
+		clrbits_le32(priv->base + data->ctl_reg,
+			     TLMM_GPIO_PULL_MASK << data->pull_bit);
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		clrsetbits_le32(priv->base + data->ctl_reg,
+				TLMM_GPIO_PULL_MASK << data->pull_bit,
+				argument << data->pull_bit);
+		break;
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
 static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector,
 			   unsigned int param, unsigned int argument)
 {
 	struct msm_pinctrl_priv *priv = dev_get_priv(dev);
 
-	/* Always NOP for special pins */
 	if (qcom_is_special_pin(&priv->data->pin_data, pin_selector))
-		return 0;
+		return msm_pinconf_set_special(priv, pin_selector, param, argument);
 
 	switch (param) {
 	case PIN_CONFIG_DRIVE_STRENGTH:
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8550.c b/drivers/pinctrl/qcom/pinctrl-sm8550.c
index 7265cb7..c65dfe0 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8550.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8550.c
@@ -18,6 +18,37 @@
 	{"gpio", 0},
 };
 
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)	\
+	{					        \
+		.name = pg_name,			\
+		.ctl_reg = ctl,				\
+		.io_reg = 0,				\
+		.pull_bit = pull,			\
+		.drv_bit = drv,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = -1,				\
+	}
+
+#define UFS_RESET(pg_name, ctl, io)			\
+	{					        \
+		.name = pg_name,			\
+		.ctl_reg = ctl,				\
+		.io_reg = io,				\
+		.pull_bit = 3,				\
+		.drv_bit = 0,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = 0,				\
+	}
+
+static const struct msm_special_pin_data msm_special_pins_data[] = {
+	[0] = UFS_RESET("ufs_reset", 0xde000, 0xde004),
+	[1] = SDC_QDSD_PINGROUP("sdc2_clk", 0xd6000, 14, 6),
+	[2] = SDC_QDSD_PINGROUP("sdc2_cmd", 0xd6000, 11, 3),
+	[3] = SDC_QDSD_PINGROUP("sdc2_data", 0xd6000, 9, 0),
+};
+
 static const char *sm8550_get_function_name(struct udevice *dev,
 						 unsigned int selector)
 {
@@ -27,15 +58,9 @@
 static const char *sm8550_get_pin_name(struct udevice *dev,
 					unsigned int selector)
 {
-	static const char *special_pins_names[] = {
-		"ufs_reset",
-		"sdc2_clk",
-		"sdc2_cmd",
-		"sdc2_data",
-	};
-
 	if (selector >= 210 && selector <= 213)
-		snprintf(pin_name, MAX_PIN_NAME_LEN, special_pins_names[selector - 210]);
+		snprintf(pin_name, MAX_PIN_NAME_LEN,
+			 msm_special_pins_data[selector - 210].name);
 	else
 		snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
 
@@ -52,6 +77,7 @@
 	.pin_data = {
 		.pin_count = 214,
 		.special_pins_start = 210,
+		.special_pins_data = msm_special_pins_data,
 	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = sm8550_get_function_name,
diff --git a/drivers/pinctrl/qcom/pinctrl-sm8650.c b/drivers/pinctrl/qcom/pinctrl-sm8650.c
index d6cc1bb..58fc94e 100644
--- a/drivers/pinctrl/qcom/pinctrl-sm8650.c
+++ b/drivers/pinctrl/qcom/pinctrl-sm8650.c
@@ -18,6 +18,37 @@
 	{"gpio", 0},
 };
 
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv)	\
+	{					        \
+		.name = pg_name,			\
+		.ctl_reg = ctl,				\
+		.io_reg = 0,				\
+		.pull_bit = pull,			\
+		.drv_bit = drv,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = -1,				\
+	}
+
+#define UFS_RESET(pg_name, ctl, io)			\
+	{					        \
+		.name = pg_name,			\
+		.ctl_reg = ctl,				\
+		.io_reg = io,				\
+		.pull_bit = 3,				\
+		.drv_bit = 0,				\
+		.oe_bit = -1,				\
+		.in_bit = -1,				\
+		.out_bit = 0,				\
+	}
+
+static const struct msm_special_pin_data msm_special_pins_data[] = {
+	[0] = UFS_RESET("ufs_reset", 0xde004, 0xdf000),
+	[1] = SDC_QDSD_PINGROUP("sdc2_clk", 0xd6000, 14, 6),
+	[2] = SDC_QDSD_PINGROUP("sdc2_cmd", 0xd6000, 11, 3),
+	[3] = SDC_QDSD_PINGROUP("sdc2_data", 0xd6000, 9, 0),
+};
+
 static const char *sm8650_get_function_name(struct udevice *dev,
 						 unsigned int selector)
 {
@@ -27,15 +58,9 @@
 static const char *sm8650_get_pin_name(struct udevice *dev,
 					unsigned int selector)
 {
-	static const char *special_pins_names[] = {
-		"ufs_reset",
-		"sdc2_clk",
-		"sdc2_cmd",
-		"sdc2_data",
-	};
-
 	if (selector >= 210 && selector <= 213)
-		snprintf(pin_name, MAX_PIN_NAME_LEN, special_pins_names[selector - 210]);
+		snprintf(pin_name, MAX_PIN_NAME_LEN,
+			 msm_special_pins_data[selector - 210].name);
 	else
 		snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
 
@@ -52,6 +77,7 @@
 	.pin_data = {
 		.pin_count = 214,
 		.special_pins_start = 210,
+		.special_pins_data = msm_special_pins_data,
 	},
 	.functions_count = ARRAY_SIZE(msm_pinctrl_functions),
 	.get_function_name = sm8650_get_function_name,
diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
index b0d6226..5cc5a9e 100644
--- a/drivers/spmi/spmi-msm.c
+++ b/drivers/spmi/spmi-msm.c
@@ -119,7 +119,7 @@
 
 	channel = priv->channel_map[usid][pid] & SPMI_CHANNEL_MASK;
 
-	dev_dbg(dev, "[%d:%d] %s: channel %d\n", usid, pid, __func__, channel);
+	debug("%s: [%d:%d] %s: channel %d\n", dev->name, usid, pid, __func__, channel);
 
 	switch (priv->arb_ver) {
 	case V1:
@@ -186,7 +186,7 @@
 
 	channel = priv->channel_map[usid][pid] & SPMI_CHANNEL_MASK;
 
-	dev_dbg(dev, "[%d:%d] %s: channel %d\n", usid, pid, __func__, channel);
+	debug("%s: [%d:%d] %s: channel %d\n", dev->name, usid, pid, __func__, channel);
 
 	switch (priv->arb_ver) {
 	case V1:
@@ -271,7 +271,7 @@
 	} else if (hw_ver < PMIC_ARB_VERSION_V7_MIN) {
 		priv->arb_ver = V5;
 		priv->arb_chnl = core_addr + APID_MAP_OFFSET_V5;
-		priv->max_channels = SPMI_MAX_CHANNELS;
+		priv->max_channels = SPMI_MAX_CHANNELS_V5;
 		priv->spmi_cnfg = dev_read_addr_name(dev, "cnfg");
 	} else {
 		/* TOFIX: handle second bus */
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index b64bfad..121194e 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -240,6 +240,12 @@
 	help
 	  Add support for the system reboot via the Renesas RAA215300 PMIC.
 
+config SYSRESET_QCOM_PSHOLD
+	bool "Support sysreset for Qualcomm SoCs via PSHOLD"
+	depends on ARCH_IPQ40XX
+	help
+	  Add support for the system reboot on Qualcomm SoCs via PSHOLD.
+
 endif
 
 endmenu
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index d59299a..a6a0584 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -29,4 +29,5 @@
 obj-$(CONFIG_$(SPL_TPL_)SYSRESET_AT91) += sysreset_at91.o
 obj-$(CONFIG_$(SPL_TPL_)SYSRESET_X86) += sysreset_x86.o
 obj-$(CONFIG_SYSRESET_RAA215300) += sysreset_raa215300.o
+obj-$(CONFIG_SYSRESET_QCOM_PSHOLD) += sysreset_qcom-pshold.o
 obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o
diff --git a/drivers/sysreset/sysreset_qcom-pshold.c b/drivers/sysreset/sysreset_qcom-pshold.c
new file mode 100644
index 0000000..4529047
--- /dev/null
+++ b/drivers/sysreset/sysreset_qcom-pshold.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Qualcomm PSHOLD reset driver
+ *
+ * Copyright (c) 2024 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ * Based on the Linux msm-poweroff driver.
+ *
+ */
+
+#include <dm.h>
+#include <sysreset.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+struct qcom_pshold_priv {
+	phys_addr_t base;
+};
+
+static int qcom_pshold_request(struct udevice *dev, enum sysreset_t type)
+{
+	struct qcom_pshold_priv *priv = dev_get_priv(dev);
+
+	writel(0, priv->base);
+	mdelay(10000);
+
+	return 0;
+}
+
+static struct sysreset_ops qcom_pshold_ops = {
+	.request = qcom_pshold_request,
+};
+
+static int qcom_pshold_probe(struct udevice *dev)
+{
+	struct qcom_pshold_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_read_addr(dev);
+	return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0;
+}
+
+static const struct udevice_id qcom_pshold_ids[] = {
+	{ .compatible = "qcom,pshold", },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(qcom_pshold) = {
+	.name 		= "qcom_pshold",
+	.id 		= UCLASS_SYSRESET,
+	.of_match 	= qcom_pshold_ids,
+	.probe 		= qcom_pshold_probe,
+	.priv_auto	= sizeof(struct qcom_pshold_priv),
+	.ops 		= &qcom_pshold_ops,
+};
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index a081f71..ff33608 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -7,7 +7,9 @@
  * Based on Linux driver
  */
 
+#include <clk.h>
 #include <dm.h>
+#include <dm/device_compat.h>
 #include <dm/lists.h>
 #include <errno.h>
 #include <usb.h>
@@ -24,6 +26,8 @@
 	struct usb_ehci *ehci; /* Start of IP core*/
 	struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
 	struct phy phy;
+	struct clk iface_clk;
+	struct clk core_clk;
 };
 
 static int msm_init_after_reset(struct ehci_ctrl *dev)
@@ -52,20 +56,46 @@
 	struct ehci_hcor *hcor;
 	int ret;
 
+	ret = clk_get_by_name(dev, "core", &p->core_clk);
+	if (ret) {
+		dev_err(dev, "Failed to get core clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_get_by_name(dev, "iface", &p->iface_clk);
+	if (ret) {
+		dev_err(dev, "Failed to get iface clock: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(&p->core_clk);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(&p->iface_clk);
+	if (ret)
+		goto cleanup_core;
+
 	hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
 	hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
 			HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
 
 	ret = generic_setup_phy(dev, &p->phy, 0);
 	if (ret)
-		return ret;
+		goto cleanup_iface;
 
 	ret = board_usb_init(0, plat->init_type);
 	if (ret < 0)
-		return ret;
+		goto cleanup_iface;
 
 	return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
 			     plat->init_type);
+
+cleanup_iface:
+	clk_disable_unprepare(&p->iface_clk);
+cleanup_core:
+	clk_disable_unprepare(&p->core_clk);
+	return ret;
 }
 
 static int ehci_usb_remove(struct udevice *dev)
@@ -81,6 +111,9 @@
 	/* Stop controller. */
 	clrbits_le32(&ehci->usbcmd, CMD_RUN);
 
+	clk_disable_unprepare(&p->iface_clk);
+	clk_disable_unprepare(&p->core_clk);
+
 	ret = generic_shutdown_phy(&p->phy);
 	if (ret)
 		return ret;
diff --git a/include/configs/qcom.h b/include/configs/qcom.h
index e50b3bc..5b5ebbd 100644
--- a/include/configs/qcom.h
+++ b/include/configs/qcom.h
@@ -11,11 +11,4 @@
 
 #define CFG_SYS_BAUDRATE_TABLE	{ 115200, 230400, 460800, 921600 }
 
-/* Load addressed are calculated during board_late_init(). See arm/mach-snapdragon/board.c */
-#define CFG_EXTRA_ENV_SETTINGS \
-	"stdin=serial,button-kbd\0"	\
-	"stdout=serial,vidconsole\0"	\
-	"stderr=serial,vidconsole\0" \
-	"bootcmd=bootm $prevbl_initrd_start_addr\0"
-
 #endif