diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk
index bf48a70a3a381d3de26427e1d1a42028d3514278..da83b5e17fef70188bf7048fd6bed12185dd5836 100644
--- a/plat/allwinner/common/allwinner-common.mk
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -20,8 +20,6 @@ PLAT_BL_COMMON_SOURCES	:=	drivers/ti/uart/${ARCH}/16550_console.S	\
 				${AW_PLAT}/common/sunxi_common.c
 
 BL31_SOURCES		+=	drivers/allwinner/axp/common.c		\
-				drivers/allwinner/sunxi_msgbox.c	\
-				drivers/arm/css/scpi/css_scpi.c		\
 				${GICV2_SOURCES}			\
 				drivers/delay_timer/delay_timer.c	\
 				drivers/delay_timer/generic_delay_timer.c \
@@ -29,14 +27,40 @@ BL31_SOURCES		+=	drivers/allwinner/axp/common.c		\
 				plat/common/plat_gicv2.c		\
 				plat/common/plat_psci_common.c		\
 				${AW_PLAT}/common/sunxi_bl31_setup.c	\
-				${AW_PLAT}/common/sunxi_cpu_ops.c	\
-				${AW_PLAT}/common/sunxi_native_pm.c	\
 				${AW_PLAT}/common/sunxi_pm.c		\
-				${AW_PLAT}/common/sunxi_scpi_pm.c	\
 				${AW_PLAT}/${PLAT}/sunxi_power.c	\
 				${AW_PLAT}/common/sunxi_security.c	\
 				${AW_PLAT}/common/sunxi_topology.c
 
+# By default, attempt to use SCPI to the ARISC management processor. If SCPI
+# is not enabled or SCP firmware is not loaded, fall back to a simpler native
+# implementation that does not support CPU or system suspend.
+#
+# If SCP firmware will always be present (or absent), the unused implementation
+# can be compiled out.
+SUNXI_PSCI_USE_NATIVE	?=	1
+SUNXI_PSCI_USE_SCPI	?=	1
+
+$(eval $(call assert_boolean,SUNXI_PSCI_USE_NATIVE))
+$(eval $(call assert_boolean,SUNXI_PSCI_USE_SCPI))
+$(eval $(call add_define,SUNXI_PSCI_USE_NATIVE))
+$(eval $(call add_define,SUNXI_PSCI_USE_SCPI))
+
+ifeq (${SUNXI_PSCI_USE_NATIVE}${SUNXI_PSCI_USE_SCPI},00)
+$(error "At least one of SCPI or native PSCI ops must be enabled")
+endif
+
+ifeq (${SUNXI_PSCI_USE_NATIVE},1)
+BL31_SOURCES		+=	${AW_PLAT}/common/sunxi_cpu_ops.c	\
+				${AW_PLAT}/common/sunxi_native_pm.c
+endif
+
+ifeq (${SUNXI_PSCI_USE_SCPI},1)
+BL31_SOURCES		+=	drivers/allwinner/sunxi_msgbox.c	\
+				drivers/arm/css/scpi/css_scpi.c		\
+				${AW_PLAT}/common/sunxi_scpi_pm.c
+endif
+
 # The bootloader is guaranteed to only run on CPU 0 by the boot ROM.
 COLD_BOOT_SINGLE_CPU		:=	1
 
diff --git a/plat/allwinner/common/include/sunxi_private.h b/plat/allwinner/common/include/sunxi_private.h
index 79474e50238118665372f5547effe64fb34b5750..b68d23f3de30c1406b12ef52bafca320ccd6bc5b 100644
--- a/plat/allwinner/common/include/sunxi_private.h
+++ b/plat/allwinner/common/include/sunxi_private.h
@@ -16,8 +16,21 @@ void sunxi_cpu_power_off_others(void);
 void sunxi_cpu_power_off_self(void);
 void sunxi_power_down(void);
 
+#if SUNXI_PSCI_USE_NATIVE
 void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops);
+#else
+static inline void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+}
+#endif
+#if SUNXI_PSCI_USE_SCPI
 int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops);
+#else
+static inline int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+	return -1;
+}
+#endif
 int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint);
 
 int sunxi_pmic_setup(uint16_t socid, const void *fdt);