diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index ef958b3a7a..f10d1aaf4b 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -37,4 +37,12 @@ config ZYNQMP_FIRMWARE
 	  Say yes to enable ZynqMP firmware interface driver.
 	  If in doubt, say N.
 
+config ARM_SMCCC_FEATURES
+	bool "Arm SMCCC features discovery"
+	depends on ARM_PSCI_FW
+	help
+	  Discover Arm SMCCC features for which a U-Boot driver is defined. When enabled,
+	  the PSCI driver is always probed and binds dirvers registered to the Arm SMCCC
+	  services if any and reported as supported by the SMCCC firmware.
+
 source "drivers/firmware/scmi/Kconfig"
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index f845ba67f8..ef3e983646 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -11,9 +11,11 @@
 #include <dm.h>
 #include <efi_loader.h>
 #include <irq_func.h>
+#include <linker_lists.h>
 #include <log.h>
 #include <sysreset.h>
 #include <asm/system.h>
+#include <dm/device-internal.h>
 #include <dm/lists.h>
 #include <linux/arm-smccc.h>
 #include <linux/delay.h>
@@ -95,6 +97,76 @@ static bool psci_is_system_reset2_supported(void)
 	return false;
 }
 
+static void smccc_invoke_hvc(unsigned long a0, unsigned long a1,
+			     unsigned long a2, unsigned long a3,
+			     unsigned long a4, unsigned long a5,
+			     unsigned long a6, unsigned long a7,
+			     struct arm_smccc_res *res)
+{
+	arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+static void smccc_invoke_smc(unsigned long a0, unsigned long a1,
+			     unsigned long a2, unsigned long a3,
+			     unsigned long a4, unsigned long a5,
+			     unsigned long a6, unsigned long a7,
+			     struct arm_smccc_res *res)
+{
+	arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+static int bind_smccc_features(struct udevice *dev, int psci_method)
+{
+	struct psci_plat_data *pdata = dev_get_plat(dev);
+	struct arm_smccc_feature *feature;
+	size_t feature_cnt, n;
+
+	if (!IS_ENABLED(CONFIG_ARM_SMCCC_FEATURES))
+		return 0;
+
+	/*
+	 * SMCCC features discovery invoke SMCCC standard function ID
+	 * ARM_SMCCC_ARCH_FEATURES but this sequence requires that this
+	 * standard ARM_SMCCC_ARCH_FEATURES function ID itself is supported.
+	 * It is queried here with invoking PSCI_FEATURES known available
+	 * from PSCI 1.0.
+	 */
+	if (!device_is_compatible(dev, "arm,psci-1.0") ||
+	    PSCI_VERSION_MAJOR(psci_0_2_get_version()) == 0)
+		return 0;
+
+	if (request_psci_features(ARM_SMCCC_ARCH_FEATURES) ==
+	    PSCI_RET_NOT_SUPPORTED)
+		return 0;
+
+	if (psci_method == PSCI_METHOD_HVC)
+		pdata->invoke_fn = smccc_invoke_hvc;
+	else
+		pdata->invoke_fn = smccc_invoke_smc;
+
+	feature_cnt = ll_entry_count(struct arm_smccc_feature, arm_smccc_feature);
+	feature = ll_entry_start(struct arm_smccc_feature, arm_smccc_feature);
+
+	for (n = 0; n < feature_cnt; n++, feature++) {
+		const char *drv_name = feature->driver_name;
+		struct udevice *dev2;
+		int ret;
+
+		if (!feature->is_supported || !feature->is_supported(pdata->invoke_fn))
+			continue;
+
+		ret = device_bind_driver(dev, drv_name, drv_name, &dev2);
+		if (ret) {
+			pr_warn("%s was not bound: %d, ignore\n", drv_name, ret);
+			continue;
+		}
+
+		dev_set_parent_plat(dev2, dev_get_plat(dev));
+	}
+
+	return 0;
+}
+
 static int psci_bind(struct udevice *dev)
 {
 	/* No SYSTEM_RESET support for PSCI 0.1 */
@@ -109,6 +181,10 @@ static int psci_bind(struct udevice *dev)
 			pr_debug("PSCI System Reset was not bound.\n");
 	}
 
+	/* From PSCI v1.0 onward we can discover services through ARM_SMCCC_FEATURE */
+	if (IS_ENABLED(CONFIG_ARM_SMCCC_FEATURES) && device_is_compatible(dev, "arm,psci-1.0"))
+		dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
+
 	return 0;
 }
 
@@ -136,7 +212,7 @@ static int psci_probe(struct udevice *dev)
 		return -EINVAL;
 	}
 
-	return 0;
+	return bind_smccc_features(dev, psci_method);
 }
 
 /**
@@ -240,4 +316,7 @@ U_BOOT_DRIVER(psci) = {
 	.of_match = psci_of_match,
 	.bind = psci_bind,
 	.probe = psci_probe,
+#ifdef CONFIG_ARM_SMCCC_FEATURES
+	.plat_auto = sizeof(struct psci_plat_data),
+#endif
 };
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 94a20c9793..e1d09884a1 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -83,6 +83,22 @@ struct arm_smccc_quirk {
 	} state;
 };
 
+/**
+ * struct arm_smccc_feature - Driver registration data for discoverable feature
+ * @driver_name: name of the driver relate to the SMCCC feature
+ * @is_supported: callback to test if SMCCC feature is supported
+ */
+struct arm_smccc_feature {
+	const char *driver_name;
+	bool (*is_supported)(void (*invoke_fn)(unsigned long a0, unsigned long a1, unsigned long a2,
+					       unsigned long a3, unsigned long a4, unsigned long a5,
+					       unsigned long a6, unsigned long a7,
+					       struct arm_smccc_res *res));
+};
+
+#define ARM_SMCCC_FEATURE_DRIVER(__name) \
+	ll_entry_declare(struct arm_smccc_feature, __name, arm_smccc_feature)
+
 /**
  * __arm_smccc_smc() - make SMC calls
  * @a0-a7: arguments passed in registers 0 to 7
diff --git a/include/linux/psci.h b/include/linux/psci.h
index c78c1079a8..03e4186343 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -11,6 +11,8 @@
 #ifndef _UAPI_LINUX_PSCI_H
 #define _UAPI_LINUX_PSCI_H
 
+#include <linux/arm-smccc.h>
+
 /*
  * PSCI v0.1 interface
  *
@@ -115,6 +117,18 @@
 #define PSCI_RET_DISABLED			-8
 #define PSCI_RET_INVALID_ADDRESS		-9
 
+/**
+ * struct psci_plat_data - PSCI driver platform data
+ * @method: Selected invocation conduit
+ */
+struct psci_plat_data {
+	void (*invoke_fn)(unsigned long arg0, unsigned long arg1,
+			  unsigned long arg2, unsigned long arg3,
+			  unsigned long arg4, unsigned long arg5,
+			  unsigned long arg6, unsigned long arg7,
+			  struct arm_smccc_res *res);
+};
+
 #ifdef CONFIG_ARM_PSCI_FW
 unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1,
 			     unsigned long a2, unsigned long a3);
