diff --git a/aarch64-bl31 b/aarch64-bl31 index 76233643bb1899b4761a22d67a8537e0926f83c6..9a67832f973ded2cf18f71fb6eec84d792e51e4e 100644 --- a/aarch64-bl31 +++ b/aarch64-bl31 @@ -8,4 +8,4 @@ rk3328 rpi3 sun50i_a64 sun50i_h6 -zynqmp \ No newline at end of file +zynqmp diff --git a/arm-trusted-firmware.spec b/arm-trusted-firmware.spec index 87b20c6a951ff9fd7f906d8ae21d34a1a855a217..5c05fac2d778f3fe7c4fa4b325118f11963fb17c 100644 --- a/arm-trusted-firmware.spec +++ b/arm-trusted-firmware.spec @@ -1,25 +1,18 @@ -%define anolis_release 3 - +%define anolis_release 1 + %global debug_package %{nil} Name: arm-trusted-firmware -Version: 2.8 +Version: 2.11.0 Release: %{anolis_release}%{dist} Summary: ARM Trusted Firmware License: BSD URL: https://github.com/ARM-software/arm-trusted-firmware Source0: https://github.com/ARM-software/arm-trusted-firmware/archive/refs/tags/v%{version}.tar.gz Source1: aarch64-bl31 -Patch0001: 0001-atf-2.8-fix-linking.patch -# https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=fd37982a19a4a291 -Patch0002: CVE-2022-47630-1.patch -# https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=72460f50e2437a85 -Patch0003: CVE-2022-47630-2.patch -# https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=f5c51855d36e399e -Patch0004: CVE-2022-47630-3.patch ExclusiveArch: aarch64 -BuildRequires: gcc dtc +BuildRequires: gcc dtc openssl %description ARM Trusted firmware is a reference implementation of secure world software for @@ -65,7 +58,6 @@ done %endif %install - mkdir -p %{buildroot}%{_datadir}/%{name} %ifarch aarch64 @@ -82,7 +74,7 @@ mkdir -p %{buildroot}%{_datadir}/%{name}/$(echo $soc)/ done # Rockchips wants the bl31.elf, plus rk3399 wants power management co-processor bits -for soc in rk3399 rk3368 rk3328 +for soc in rk3399 rk3368 rk3328 do mkdir -p %{buildroot}%{_datadir}/%{name}/$(echo $soc)/ for file in bl31/bl31.elf m0/rk3399m0.bin m0/rk3399m0.elf @@ -96,7 +88,6 @@ done %endif %generate_compatibility_deps - %ifarch aarch64 %files -n arm-trusted-firmware-armv8 %license license.rst @@ -107,6 +98,10 @@ done %doc readme.rst %changelog +* Fri Jul 4 2025 lzq11122 - 2.11.0-1 +- Remove all patch update to 2.11.0 +- fix CVE-2023-49100 CVE-2024-6564 + * Wed Dec 04 2024 Zhongkun He - 2.8-3 - Fix CVE-2022-47630 diff --git a/atf-rk35xx.patch b/atf-rk35xx.patch new file mode 100644 index 0000000000000000000000000000000000000000..f5b1d6aebe76a45ba99dc91599ce295125c81265 --- /dev/null +++ b/atf-rk35xx.patch @@ -0,0 +1,9845 @@ + + + + + + Tree - rpms/arm-trusted-firmware - src.fedoraproject.org + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+
+
+

+

+
+ +
+
+
+
+
+ + + Clone + + + +
+
+
+
+ + +
+
+ +
+ +
+
+
+
+ + +
+
+ +
+ +
+
+
+ + +
+ + Blob + + Blame + + History + + Raw +
+ +
From bb610911336c30d154df23dc36016430aa8235ef Mon Sep 17 00:00:00 2001
+From: shengfei Xu <xsf@rock-chips.com>
+Date: Fri, 30 Sep 2022 08:56:21 +0000
+Subject: [PATCH 1/5] feat(rockchip): add RK3566/RK3568 Socs support
+
+RK3566/RK3568 is a Quad-core soc and Cortex-a55 inside.
+This patch supports the following functions:
+1. basic platform setup
+2. power up/off cpus
+3. suspend/resume cpus
+4. suspend/resume system
+5. reset system
+
+Signed-off-by: shengfei Xu <xsf@rock-chips.com>
+Change-Id: I8b98a4d07664de26bd6078f63664cbc3d9c1c68c
+---
+ docs/plat/rockchip.rst                        |   1 +
+ include/lib/cpus/aarch64/dsu_def.h            |   4 +
+ lib/cpus/aarch64/dsu_helpers.S                |  13 +
+ plat/rockchip/common/aarch64/plat_helpers.S   |   7 +-
+ .../rockchip/common/aarch64/platform_common.c |  11 +-
+ plat/rockchip/common/bl31_plat_setup.c        |  11 +-
+ plat/rockchip/common/include/plat_private.h   |   7 +-
+ .../rk3568/drivers/pmu/plat_pmu_macros.S      |  18 +
+ plat/rockchip/rk3568/drivers/pmu/pmu.c        | 543 ++++++++++++++++++
+ plat/rockchip/rk3568/drivers/pmu/pmu.h        | 304 ++++++++++
+ plat/rockchip/rk3568/drivers/soc/soc.c        | 103 ++++
+ plat/rockchip/rk3568/drivers/soc/soc.h        |  63 ++
+ plat/rockchip/rk3568/include/plat.ld.S        |  36 ++
+ plat/rockchip/rk3568/include/plat_sip_calls.h |  12 +
+ plat/rockchip/rk3568/include/platform_def.h   | 136 +++++
+ plat/rockchip/rk3568/plat_sip_calls.c         |  29 +
+ plat/rockchip/rk3568/platform.mk              |  96 ++++
+ plat/rockchip/rk3568/rk3568_def.h             | 104 ++++
+ 18 files changed, 1486 insertions(+), 12 deletions(-)
+ create mode 100644 plat/rockchip/rk3568/drivers/pmu/plat_pmu_macros.S
+ create mode 100644 plat/rockchip/rk3568/drivers/pmu/pmu.c
+ create mode 100644 plat/rockchip/rk3568/drivers/pmu/pmu.h
+ create mode 100644 plat/rockchip/rk3568/drivers/soc/soc.c
+ create mode 100644 plat/rockchip/rk3568/drivers/soc/soc.h
+ create mode 100644 plat/rockchip/rk3568/include/plat.ld.S
+ create mode 100644 plat/rockchip/rk3568/include/plat_sip_calls.h
+ create mode 100644 plat/rockchip/rk3568/include/platform_def.h
+ create mode 100644 plat/rockchip/rk3568/plat_sip_calls.c
+ create mode 100644 plat/rockchip/rk3568/platform.mk
+ create mode 100644 plat/rockchip/rk3568/rk3568_def.h
+
+diff --git a/docs/plat/rockchip.rst b/docs/plat/rockchip.rst
+index 01cf176d6..53f63b59f 100644
+--- a/docs/plat/rockchip.rst
++++ b/docs/plat/rockchip.rst
+@@ -10,6 +10,7 @@ This includes right now:
+ -  rk3328: Quad-Core Cortex-A53
+ -  rk3368: Octa-Core Cortex-A53
+ -  rk3399: Hexa-Core Cortex-A53/A72
++-  rk3566/rk3568: Quad-Core Cortex-A55
+ 
+ 
+ Boot Sequence
+diff --git a/include/lib/cpus/aarch64/dsu_def.h b/include/lib/cpus/aarch64/dsu_def.h
+index 577de6199..51fbfd1db 100644
+--- a/include/lib/cpus/aarch64/dsu_def.h
++++ b/include/lib/cpus/aarch64/dsu_def.h
+@@ -30,6 +30,7 @@
+  * DSU Cluster Auxiliary Control registers definitions
+  ********************************************************************/
+ #define CLUSTERACTLR_EL1	S3_0_C15_C3_3
++#define CLUSTERPWRCTLR_EL1	S3_0_C15_C3_5
+ 
+ #define CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING	(ULL(1) << 15)
+ #define CLUSTERACTLR_EL1_DISABLE_SCLK_GATING	(ULL(3) << 15)
+@@ -39,4 +40,7 @@
+  ********************************************************************/
+ #define DSU_ERRATA_936184_MASK	(U(0x3) << 15)
+ 
++#ifndef __ASSEMBLER__
++void dsu_pwr_dwn(void);
++#endif
+ #endif /* DSU_DEF_H */
+diff --git a/lib/cpus/aarch64/dsu_helpers.S b/lib/cpus/aarch64/dsu_helpers.S
+index 8e5b4598c..3c5bf2ea1 100644
+--- a/lib/cpus/aarch64/dsu_helpers.S
++++ b/lib/cpus/aarch64/dsu_helpers.S
+@@ -24,6 +24,7 @@
+ 	 */
+ 	.globl	check_errata_dsu_798953
+ 	.globl	errata_dsu_798953_wa
++	.globl	dsu_pwr_dwn
+ 
+ func check_errata_dsu_798953
+ 	mov	x2, #ERRATA_APPLIES
+@@ -202,3 +203,15 @@ func errata_dsu_2313941_wa
+ 1:
+ 	ret	x8
+ endfunc errata_dsu_2313941_wa
++
++	/* ---------------------------------------------
++	 * controls power features of the cluster
++	 * 1. Cache portion power not request
++	 * 2. Disable the retention circuit
++	 * ---------------------------------------------
++	 */
++func dsu_pwr_dwn
++	msr	CLUSTERPWRCTLR_EL1, xzr
++	isb
++	ret
++endfunc dsu_pwr_dwn
+diff --git a/plat/rockchip/common/aarch64/plat_helpers.S b/plat/rockchip/common/aarch64/plat_helpers.S
+index c4c0dec3c..dde66aa7d 100644
+--- a/plat/rockchip/common/aarch64/plat_helpers.S
++++ b/plat/rockchip/common/aarch64/plat_helpers.S
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
++ * Copyright (c) 2013-2023, ARM Limited and Contributors. All rights reserved.
+  *
+  * SPDX-License-Identifier: BSD-3-Clause
+  */
+@@ -150,7 +150,12 @@ endfunc platform_cpu_warmboot
+ 	 * Per-CPU Secure entry point - resume or power up
+ 	 * --------------------------------------------------------------------
+ 	 */
++
++#if USE_COHERENT_MEM
+ 	.section .tzfw_coherent_mem, "a"
++#else
++	.data
++#endif
+ 	.align  3
+ cpuson_entry_point:
+ 	.rept	PLATFORM_CORE_COUNT
+diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
+index 81e852062..d563dfd8f 100644
+--- a/plat/rockchip/common/aarch64/platform_common.c
++++ b/plat/rockchip/common/aarch64/platform_common.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
++ * Copyright (c) 2013-2023, ARM Limited and Contributors. All rights reserved.
+  *
+  * SPDX-License-Identifier: BSD-3-Clause
+  */
+@@ -13,8 +13,6 @@
+ #include <common/debug.h>
+ #include <drivers/arm/cci.h>
+ #include <lib/utils.h>
+-#include <lib/xlat_tables/xlat_tables.h>
+-
+ #include <plat_private.h>
+ 
+ #ifdef PLAT_RK_CCI_BASE
+@@ -42,9 +40,10 @@ static const int cci_map[] = {
+ 		mmap_add_region(ro_start, ro_start,			\
+ 				ro_limit - ro_start,			\
+ 				MT_MEMORY | MT_RO | MT_SECURE);		\
+-		mmap_add_region(coh_start, coh_start,			\
+-				coh_limit - coh_start,			\
+-				MT_DEVICE | MT_RW | MT_SECURE);		\
++		if ((coh_limit - coh_start) != 0)			\
++			mmap_add_region(coh_start, coh_start,		\
++					coh_limit - coh_start,		\
++					MT_DEVICE | MT_RW | MT_SECURE);	\
+ 		mmap_add(plat_rk_mmap);					\
+ 		rockchip_plat_mmu_el##_el();				\
+ 		init_xlat_tables();					\
+diff --git a/plat/rockchip/common/bl31_plat_setup.c b/plat/rockchip/common/bl31_plat_setup.c
+index 59db3d85c..62147226a 100644
+--- a/plat/rockchip/common/bl31_plat_setup.c
++++ b/plat/rockchip/common/bl31_plat_setup.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
++ * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
+  *
+  * SPDX-License-Identifier: BSD-3-Clause
+  */
+@@ -93,10 +93,19 @@ void bl31_plat_arch_setup(void)
+ {
+ 	plat_cci_init();
+ 	plat_cci_enable();
++#if USE_COHERENT_MEM
+ 	plat_configure_mmu_el3(BL_CODE_BASE,
+ 			       BL_COHERENT_RAM_END - BL_CODE_BASE,
+ 			       BL_CODE_BASE,
+ 			       BL_CODE_END,
+ 			       BL_COHERENT_RAM_BASE,
+ 			       BL_COHERENT_RAM_END);
++#else
++	plat_configure_mmu_el3(BL31_START,
++			       BL31_END - BL31_START,
++			       BL_CODE_BASE,
++			       BL_CODE_END,
++			       0,
++			       0);
++#endif
+ }
+diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
+index 990d1065f..465f372e5 100644
+--- a/plat/rockchip/common/include/plat_private.h
++++ b/plat/rockchip/common/include/plat_private.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
++ * Copyright (c) 2014-2023, ARM Limited and Contributors. All rights reserved.
+  *
+  * SPDX-License-Identifier: BSD-3-Clause
+  */
+@@ -11,9 +11,9 @@
+ 
+ #include <stdint.h>
+ 
+-#include <lib/psci/psci.h>
+-#include <lib/xlat_tables/xlat_tables.h>
+ #include <lib/mmio.h>
++#include <lib/psci/psci.h>
++#include <lib/xlat_tables/xlat_tables_compat.h>
+ #include <plat_params.h>
+ 
+ #define __sramdata __attribute__((section(".sram.data")))
+@@ -135,7 +135,6 @@ extern const unsigned char rockchip_power_domain_tree_desc[];
+ extern void *pmu_cpuson_entrypoint;
+ extern u_register_t cpuson_entry_point[PLATFORM_CORE_COUNT];
+ extern uint32_t cpuson_flags[PLATFORM_CORE_COUNT];
+-
+ extern const mmap_region_t plat_rk_mmap[];
+ 
+ uint32_t rockchip_get_uart_base(void);
+diff --git a/plat/rockchip/rk3568/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3568/drivers/pmu/plat_pmu_macros.S
+new file mode 100644
+index 000000000..8ddea0ee2
+--- /dev/null
++++ b/plat/rockchip/rk3568/drivers/pmu/plat_pmu_macros.S
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <arch.h>
++#include <asm_macros.S>
++
++#include <platform_def.h>
++
++.macro	func_rockchip_clst_warmboot
++	/* Nothing to do for rk3568 */
++.endm
++
++.macro rockchip_clst_warmboot_data
++	/* Nothing to do for rk3568 */
++.endm
+diff --git a/plat/rockchip/rk3568/drivers/pmu/pmu.c b/plat/rockchip/rk3568/drivers/pmu/pmu.c
+new file mode 100644
+index 000000000..970caec52
+--- /dev/null
++++ b/plat/rockchip/rk3568/drivers/pmu/pmu.c
+@@ -0,0 +1,543 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * The power management unit (PMU) is designed for controlling power resources.
++ * The PMU is dedicated for managing the power of the whole chip.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <bakery_lock.h>
++#include <cortex_a55.h>
++#include <dsu_def.h>
++#include <mmio.h>
++#include <platform.h>
++#include <platform_def.h>
++#include <pmu.h>
++
++#include <cpus_on_fixed_addr.h>
++#include <plat_private.h>
++#include <soc.h>
++
++/*
++ * Use this macro to instantiate lock before it is used in below
++ * rockchip_pd_lock_xxx() macros
++ */
++DECLARE_BAKERY_LOCK(rockchip_pd_lock);
++
++static uint32_t grf_ddr_con3;
++static struct psram_data_t *psram_sleep_cfg =
++	(struct psram_data_t *)&sys_sleep_flag_sram;
++
++/*
++ * These are wrapper macros to the powe domain Bakery Lock API.
++ */
++#define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock)
++#define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock)
++#define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock)
++
++void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
++{
++	uint64_t ctrl;
++
++	__asm__ volatile ("mrs %0, " __XSTRING(CORTEX_A55_CPUPWRCTLR_EL1) : "=r" (ctrl));
++	ctrl |= 0x01;
++	__asm__ volatile ("msr " __XSTRING(CORTEX_A55_CPUPWRCTLR_EL1) ", %0" : : "r" (ctrl));
++	isb();
++
++	while (1)
++		wfi();
++}
++
++static void pmu_pmic_sleep_mode_config(void)
++{
++	/* pmic sleep function selection
++	 * 1'b0: From reset pulse generator, can reset external PMIC
++	 * 1'b1: From pmu block, only support sleep function for external PMIC
++	 */
++	mmio_write_32(PMUGRF_BASE + PMU_GRF_SOC_CON(0),  WRITE_MASK_SET(BIT(7)));
++	mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_IOMUX_L, PMIC_SLEEP_FUN);
++}
++
++static void pmu_wakeup_source_config(void)
++{
++	/* config wakeup source */
++	mmio_write_32(PMU_BASE + PMU_WAKEUP_INT_CON, WRITE_MASK_SET(BIT(WAKEUP_GPIO0_INT_EN)));
++
++	INFO("WAKEUP: PMU_WAKEUP_INT_CON:0x%x, reg: 0x%x\n",
++	     mmio_read_32(PMU_BASE + PMU_WAKEUP_INT_CON), PMU_WAKEUP_INT_CON);
++}
++
++static void pmu_pll_powerdown_config(void)
++{
++	uint32_t pll_id;
++
++	/* PLL power down by PMU */
++	pll_id = BIT(APLL_PD_ENA) |
++		BIT(CPLL_PD_ENA) |
++		BIT(GPLL_PD_ENA) |
++		BIT(MPLL_PD_ENA) |
++		BIT(NPLL_PD_ENA) |
++		BIT(HPLL_PD_ENA) |
++		BIT(PPLL_PD_ENA) |
++		BIT(VPLL_PD_ENA);
++	mmio_write_32(PMU_BASE + PMU_PLLPD_CON, WRITE_MASK_SET(pll_id));
++	INFO("PLL: PMU_PLLPD_CON(0x%x):0x%x\n",
++	     PMU_PLLPD_CON, mmio_read_32(PMU_BASE + PMU_PLLPD_CON));
++}
++
++static void pmu_stable_count_config(void)
++{
++	mmio_write_32(PMU_BASE + PMU_DSU_STABLE_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_PMIC_STABLE_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_OSC_STABLE_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_WAKEUP_RSTCLR_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_PLL_LOCK_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_DSU_PWRUP_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_DSU_PWRDN_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_GPU_VOLUP_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_GPU_VOLDN_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_WAKEUP_TIMEOUT_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_PWM_SWITCH_CNT, 0x180);
++	mmio_write_32(PMU_BASE + PMU_DBG_RST_CNT, 0x180);
++}
++
++static void pmu_pd_powerdown_config(void)
++{
++	uint32_t pwr_gate_con, pwr_dwn_st, pmu_bus_idle_con0 = 0;
++	uint32_t pmu_bus_idle_con1;
++
++	/* Pd power down by PMU */
++	pwr_dwn_st = mmio_read_32(PMU_BASE + PMU_PWR_DWN_ST);
++	pwr_gate_con = ~pwr_dwn_st & 0x3ff;
++
++	if (pwr_gate_con & BIT(PD_GPU_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_GPU);
++	}
++
++	if (pwr_gate_con & BIT(PD_NPU_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_NPU);
++	}
++
++	if (pwr_gate_con & BIT(PD_RKVENC_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_RKVENC);
++	}
++
++	if (pwr_gate_con & BIT(PD_RKVDEC_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_RKVDEC);
++	}
++
++	if (pwr_gate_con & BIT(PD_RGA_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_RGA);
++	}
++
++	if (pwr_gate_con & BIT(PD_VI_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_VI);
++	}
++
++	if (pwr_gate_con & BIT(PD_VO_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_VO);
++	}
++
++	if (pwr_gate_con & BIT(PD_PIPE_DWN_ENA)) {
++		pmu_bus_idle_con0 |= BIT(IDLE_REQ_PIPE);
++	}
++
++	pmu_bus_idle_con0 |= BIT(IDLE_REQ_GIC_AUDIO) |
++		BIT(IDLE_REQ_MSCH) |
++		BIT(IDLE_REQ_PHP) |
++		BIT(IDLE_REQ_SECURE_FLASH) |
++		BIT(IDLE_REQ_PERIMID) |
++		BIT(IDLE_REQ_USB) |
++		BIT(IDLE_REQ_BUS);
++
++	/* Enable power down PD by PMU automatically */
++	pwr_gate_con |= (BIT(PD_GPU_DWN_ENA) |
++		BIT(PD_NPU_DWN_ENA) |
++		BIT(PD_VPU_DWN_ENA) |
++		BIT(PD_RKVENC_DWN_ENA) |
++		BIT(PD_RKVDEC_DWN_ENA) |
++		BIT(PD_RGA_DWN_ENA) |
++		BIT(PD_VI_DWN_ENA) |
++		BIT(PD_VO_DWN_ENA) |
++		BIT(PD_PIPE_DWN_ENA)) << 16;
++
++	pmu_bus_idle_con1 = 0;
++
++	mmio_write_32(PMU_BASE + PMU_PWR_GATE_CON, pwr_gate_con);
++	mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON0, WRITE_MASK_SET(pmu_bus_idle_con0));
++	mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON1, WRITE_MASK_SET(pmu_bus_idle_con1));
++
++	/* When perform idle operation,
++	 * corresponding clock can be opened or gated automatically
++	 */
++	mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON0, 0xffffffff);
++	mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON1, 0x00070007);
++
++	mmio_write_32(PMU_BASE + PMU_VOL_GATE_SFTCON, WRITE_MASK_SET(BIT(VD_NPU_ENA)));
++
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(PWRDN_BYPASS)));
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(BUS_BYPASS)));
++
++	INFO("PD & BUS:PMU_PWR_DWN_ST(0x%x):0x%x\n",
++	     PMU_PWR_DWN_ST, mmio_read_32(PMU_BASE + PMU_PWR_DWN_ST));
++	INFO("PD & BUS:PMU_PWR_GATE_CON(0x%x):0x%x\n",
++	     PMU_PWR_GATE_CON, mmio_read_32(PMU_BASE + PMU_PWR_GATE_CON));
++	INFO("PD & BUS:PMU_BUS_IDLE_CON0(0x%x):0x%x\n",
++	     PMU_BUS_IDLE_CON0, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_CON0));
++	INFO("PD & BUS:PMU_BUS_IDLE_CON1(0x%x):0x%x\n",
++	     PMU_BUS_IDLE_CON1, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_CON1));
++	INFO("PD & BUS:PMU_PWR_CON(0x%x):0x%x\n",
++	     PMU_PWR_CON, mmio_read_32(PMU_BASE + PMU_PWR_CON));
++}
++
++static void pmu_ddr_suspend_config(void)
++{
++	uint32_t pmu_ddr_pwr_con;
++
++	pmu_ddr_pwr_con = BIT(DDR_SREF_ENA) |
++		BIT(DDRIO_RET_ENTER_ENA) |
++		BIT(DDRIO_RET_EXIT_ENA) |
++		BIT(DDRPHY_AUTO_GATING_ENA);
++
++	mmio_write_32(PMU_BASE + PMU_DDR_PWR_CON, WRITE_MASK_SET(pmu_ddr_pwr_con));
++	/* DPLL power down by PMU */
++	mmio_write_32(PMU_BASE + PMU_PLLPD_CON, WRITE_MASK_SET(BIT(DPLL_PD_ENA)));
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(DDR_BYPASS)));
++
++	grf_ddr_con3 = mmio_read_32(DDRGRF_BASE + GRF_DDR_CON3);
++
++	mmio_write_32(DDRGRF_BASE + GRF_DDR_CON3, 0x00600020);
++
++	pmu_ddr_pwr_con = mmio_read_32(PMU_BASE + PMU_DDR_PWR_CON);
++
++	INFO("DDR: PMU_PLLPD_CON(0x%x):0x%x\n",
++	     PMU_PLLPD_CON, mmio_read_32(PMU_BASE + PMU_PLLPD_CON));
++	INFO("DDR: PMU_DDR_PWR_CON(0x%x):\t0x%x\n",
++	     PMU_DDR_PWR_CON, pmu_ddr_pwr_con);
++
++	if (pmu_ddr_pwr_con & BIT(DDR_SREF_ENA)) {
++		INFO("\t DDR_SREF_ENA\n");
++	}
++
++	if (pmu_ddr_pwr_con & BIT(DDRIO_RET_ENTER_ENA)) {
++		INFO("\t DDRIO_RET_ENTER_ENA\n");
++	}
++
++	if (pmu_ddr_pwr_con & BIT(DDRIO_RET_EXIT_ENA)) {
++		INFO("\t DDRIO_RET_EXIT_ENA\n");
++	}
++
++	if (pmu_ddr_pwr_con & BIT(DDRPHY_AUTO_GATING_ENA)) {
++		INFO("\t DDRPHY_AUTO_GATING_ENA\n");
++	}
++}
++
++static void pmu_dsu_suspend_config(void)
++{
++	uint32_t pmu_dsu_pwr_con;
++
++	pmu_dsu_pwr_con = BIT(DSU_PWRDN_ENA);
++
++	mmio_write_32(PMU_BASE + PMU_CLUSTER_IDLE_CON, 0x000f000f);
++	mmio_write_32(PMU_BASE + PMU_DSU_PWR_CON, WRITE_MASK_SET(pmu_dsu_pwr_con));
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, WRITE_MASK_CLR(BIT(DSU_BYPASS)));
++	dsu_pwr_dwn();
++
++	INFO("DSU: PMU_DSU_PWR_CON(0x%x): 0x%x\n",
++	     PMU_DSU_PWR_CON, mmio_read_32(PMU_BASE + PMU_DSU_PWR_CON));
++	INFO("DSU: PMU_CLUSTER_IDLE_CON(0x%x),: 0x%x\n",
++	     PMU_CLUSTER_IDLE_CON,  mmio_read_32(PMU_BASE + PMU_CLUSTER_IDLE_CON));
++	INFO("DSU: PMU_PWR_CON(0x%x),: 0x%x\n",
++	     PMU_PWR_CON, mmio_read_32(PMU_BASE + PMU_PWR_CON));
++}
++
++static void pmu_cpu_powerdown_config(void)
++{
++	uint32_t pmu_cluster_pwr_st, cpus_state, cpus_bypass;
++
++	pmu_cluster_pwr_st = mmio_read_32(PMU_BASE + PMU_CLUSTER_PWR_ST);
++	cpus_state = pmu_cluster_pwr_st & 0x0f;
++
++	cpus_bypass = cpus_state << CPU0_BYPASS;
++
++	INFO("CPU: PMU_CLUSTER_PWR_ST(0x%x):0x%x\n",
++	     PMU_CLUSTER_PWR_ST, mmio_read_32(PMU_BASE + PMU_CLUSTER_PWR_ST));
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, (0xf << (16 + CPU0_BYPASS)) | cpus_bypass);
++
++	INFO("CPU: PMU_PWR_CON(0x%x), 0x%x\n",
++	     PMU_PWR_CON,  mmio_read_32(PMU_BASE + PMU_PWR_CON));
++}
++
++static void pvtm_32k_config(void)
++{
++	uint32_t pmu_cru_pwr_con;
++	uint32_t pvtm_freq_khz, pvtm_div;
++
++	mmio_write_32(PMUCRU_BASE + PMUCRU_PMUGATE_CON01, 0x38000000);
++	mmio_write_32(PMUPVTM_BASE + PVTM_CON0, 0x00020002);
++	dsb();
++
++	mmio_write_32(PMUPVTM_BASE + PVTM_CON0, 0x001c0000);
++
++	mmio_write_32(PMUPVTM_BASE + PVTM_CON1, PVTM_CALC_CNT);
++	dsb();
++
++	mmio_write_32(PMUPVTM_BASE + PVTM_CON0, 0x00010001);
++	dsb();
++
++	while (mmio_read_32(PMUPVTM_BASE + PVTM_STATUS1) < 30) {
++		;
++	}
++
++	dsb();
++	while (!(mmio_read_32(PMUPVTM_BASE + PVTM_STATUS0) & 0x1)) {
++		;
++	}
++
++	pvtm_freq_khz = (mmio_read_32(PMUPVTM_BASE + PVTM_STATUS1) * 24000 +
++		PVTM_CALC_CNT / 2) / PVTM_CALC_CNT;
++	pvtm_div = (pvtm_freq_khz + 16) / 32;
++
++	mmio_write_32(PMUGRF_BASE + PMU_GRF_DLL_CON0, pvtm_div);
++
++	mmio_write_32(PMUCRU_BASE + PMUCRU_PMUCLKSEL_CON00, 0x00c00000);
++
++	pmu_cru_pwr_con = BIT(ALIVE_32K_ENA) | BIT(OSC_DIS_ENA);
++
++	mmio_write_32(PMU_BASE + PMU_WAKEUP_TIMEOUT_CNT, 32000 * 10);
++
++	mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, WRITE_MASK_SET(pmu_cru_pwr_con));
++	INFO("PVTM: PMU_CRU_PWR_CON(0x0%x): 0x%x\n",
++	     PMU_CRU_PWR_CON, mmio_read_32(PMU_BASE + PMU_CRU_PWR_CON));
++}
++
++static void pmu_cru_suspendmode_config(void)
++{
++	uint32_t pmu_cru_pwr_con;
++
++	pmu_cru_pwr_con = BIT(ALIVE_OSC_ENA);
++
++	mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, WRITE_MASK_SET(pmu_cru_pwr_con));
++	INFO("CRU: PMU_CRU_PWR_CON(0x0%x): 0x%x\n",
++	     PMU_CRU_PWR_CON, mmio_read_32(PMU_BASE + PMU_CRU_PWR_CON));
++}
++
++static void pmu_suspend_cru_fsm(void)
++{
++	pmu_pmic_sleep_mode_config();
++
++	/* Global interrupt disable */
++	mmio_write_32(PMU_BASE + PMU_INT_MASK_CON, CLB_INT_DISABLE);
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, CPUS_BYPASS);
++
++	pmu_stable_count_config();
++	pmu_wakeup_source_config();
++	mmio_write_32(PMU_BASE + PMU_WAKEUP_TIMEOUT_CNT, 0x5dc0 * 20000);
++	/* default cru config */
++	mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, WRITE_MASK_SET(BIT(ALIVE_OSC_ENA)));
++
++	pmu_cru_suspendmode_config();
++	pmu_cpu_powerdown_config();
++	pmu_pll_powerdown_config();
++	pmu_pd_powerdown_config();
++	pmu_ddr_suspend_config();
++	pmu_dsu_suspend_config();
++	pvtm_32k_config();
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, 0x00010001);
++}
++
++static void pmu_reinit(void)
++{
++	mmio_write_32(DDRGRF_BASE + GRF_DDR_CON3, grf_ddr_con3 | 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_PWR_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_INT_MASK_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_WAKEUP_INT_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON0, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_DDR_PWR_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_BUS_IDLE_CON1, 0xffff0000);
++
++	mmio_write_32(PMU_BASE + PMU_PWR_GATE_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_VOL_GATE_SFTCON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_CRU_PWR_CON, 0xffff0000);
++
++	mmio_write_32(PMU_BASE + PMU_PLLPD_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_INFO_TX_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_DSU_PWR_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU_CLUSTER_IDLE_CON, 0xffff0000);
++}
++
++void rockchip_plat_mmu_el3(void)
++{
++}
++
++int rockchip_soc_cores_pwr_dm_suspend(void)
++{
++	return 0;
++}
++
++int rockchip_soc_cores_pwr_dm_resume(void)
++{
++	return 0;
++}
++
++int rockchip_soc_sys_pwr_dm_suspend(void)
++{
++	psram_sleep_cfg->pm_flag = 0;
++	flush_dcache_range((uintptr_t)&(psram_sleep_cfg->pm_flag),
++			   sizeof(uint32_t));
++	pmu_suspend_cru_fsm();
++
++	return 0;
++}
++
++int rockchip_soc_sys_pwr_dm_resume(void)
++{
++	pmu_reinit();
++	plat_rockchip_gic_cpuif_enable();
++	psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT;
++	flush_dcache_range((uintptr_t)&(psram_sleep_cfg->pm_flag),
++			   sizeof(uint32_t));
++
++	return 0;
++}
++
++static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
++{
++	uint32_t apm_value, offset, idx;
++
++	apm_value = BIT(core_pm_en) | BIT(core_pm_int_wakeup_glb_msk);
++
++	if (pd_cfg == core_pwr_wfi_int) {
++		apm_value |= BIT(core_pm_int_wakeup_en);
++	}
++
++	idx = cpu_id / 2;
++	offset = (cpu_id % 2) << 3;
++
++	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx),
++		      BITS_WITH_WMASK(apm_value, 0xf, offset));
++	dsb();
++
++	return 0;
++}
++
++static int cpus_power_domain_on(uint32_t cpu_id)
++{
++	uint32_t offset, idx;
++
++	idx = cpu_id / 2;
++	offset = (cpu_id % 2) << 3;
++
++	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx),
++		      WMSK_BIT(core_pm_en + offset));
++	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx),
++		      BIT_WITH_WMSK(core_pm_sft_wakeup_en + offset));
++	dsb();
++
++	return 0;
++}
++
++int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint)
++{
++	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
++
++	assert(cpu_id < PLATFORM_CORE_COUNT);
++
++	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
++	cpuson_entry_point[cpu_id] = entrypoint;
++	flush_dcache_range((uintptr_t)cpuson_flags, sizeof(cpuson_flags));
++	flush_dcache_range((uintptr_t)cpuson_entry_point,
++			   sizeof(cpuson_entry_point));
++
++	cpus_power_domain_on(cpu_id);
++	return 0;
++}
++
++int rockchip_soc_cores_pwr_dm_off(void)
++{
++	uint32_t cpu_id = plat_my_core_pos();
++
++	cpus_power_domain_off(cpu_id,
++			      core_pwr_wfi);
++	return 0;
++}
++
++int rockchip_soc_cores_pwr_dm_on_finish(void)
++{
++	uint32_t cpu_id = plat_my_core_pos();
++	uint32_t offset, idx;
++
++	/* Disable core_pm */
++	idx = cpu_id / 2;
++	offset = (cpu_id % 2) << 3;
++	mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(idx),
++		      BITS_WITH_WMASK(0, 0xf, offset));
++
++	return 0;
++}
++
++static void nonboot_cpus_off(void)
++{
++	uint32_t tmp;
++
++	cpus_power_domain_off(1, 0);
++	cpus_power_domain_off(2, 0);
++	cpus_power_domain_off(3, 0);
++
++	mmio_write_32(SYSSRAM_BASE + 0x04, 0xdeadbeaf);
++	mmio_write_32(SYSSRAM_BASE + 0x08, (uintptr_t)&rockchip_soc_sys_pd_pwr_dn_wfi);
++	sev();
++
++	do {
++		tmp = mmio_read_32(PMU_BASE + PMU_CLUSTER_PWR_ST);
++	} while ((tmp & 0xe) != 0xe);
++}
++
++void plat_rockchip_pmu_init(void)
++{
++	uint32_t cpu;
++
++	rockchip_pd_lock_init();
++	nonboot_cpus_off();
++	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
++		cpuson_flags[cpu] = PMU_CPU_HOTPLUG;
++
++	psram_sleep_cfg->ddr_data = (uint64_t)0;
++	psram_sleep_cfg->sp = PSRAM_SP_TOP;
++	psram_sleep_cfg->ddr_flag = 0x00;
++	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
++	psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT;
++
++	/*
++	 * When perform idle operation, corresponding clock can be
++	 * opened or gated automatically.
++	 */
++	mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON0, 0xffffffff);
++	mmio_write_32(PMU_BASE + PMU_NOC_AUTO_CON1, 0x00070007);
++
++	/* grf_con_pmic_sleep_sel
++	 * pmic sleep function selection
++	 * 1'b0: From reset pulse generator, can reset external PMIC
++	 * 1'b1: From pmu block, only support sleep function for external PMIC
++	 */
++	mmio_write_32(PMUGRF_BASE + PMU_GRF_SOC_CON(0), 0x00800080);
++
++	/*
++	 * force jtag control
++	 * 1'b0: CPU debug port IO mux is controlled by sdmmc_detect_en status
++	 * 1'b0: CPU debug port IO mux IS controlled by GRF
++	 */
++	mmio_write_32(SGRF_BASE + 0x008, 0x00100000);
++
++	/*
++	 * remap
++	 * 2'b00: Boot from boot-rom.
++	 * 2'b01: Boot from pmu mem.
++	 * 2'b10: Boot from sys mem.
++	 */
++	mmio_write_32(PMUSGRF_BASE + PMU_SGRF_SOC_CON1, 0x18000800);
++}
+diff --git a/plat/rockchip/rk3568/drivers/pmu/pmu.h b/plat/rockchip/rk3568/drivers/pmu/pmu.h
+new file mode 100644
+index 000000000..5821514ba
+--- /dev/null
++++ b/plat/rockchip/rk3568/drivers/pmu/pmu.h
+@@ -0,0 +1,304 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++#define PMU_VERSION			0x0000
++#define PMU_PWR_CON			0x0004
++#define PMU_MAIN_PWR_STATE		0x0008
++#define PMU_INT_MASK_CON		0x000C
++#define PMU_WAKEUP_INT_CON		0x0010
++#define PMU_WAKEUP_INT_ST		0x0014
++#define PMU_WAKEUP_EDGE_CON		0x0018
++#define PMU_WAKEUP_EDGE_ST		0x001C
++#define PMU_BUS_IDLE_CON0		0x0040
++#define PMU_BUS_IDLE_CON1		0x0044
++#define PMU_BUS_IDLE_SFTCON0		0x0050
++#define PMU_BUS_IDLE_SFTCON1		0x0054
++#define PMU_BUS_IDLE_ACK		0x0060
++#define PMU_BUS_IDLE_ST			0x0068
++#define PMU_NOC_AUTO_CON0		0x0070
++#define PMU_NOC_AUTO_CON1		0x0074
++#define PMU_DDR_PWR_CON			0x0080
++#define PMU_DDR_PWR_SFTCON		0x0084
++#define PMU_DDR_PWR_STATE		0x0088
++#define PMU_DDR_PWR_ST			0x008C
++#define PMU_PWR_GATE_CON		0x0090
++#define PMU_PWR_GATE_STATE		0x0094
++#define PMU_PWR_DWN_ST			0x0098
++#define PMU_PWR_GATE_SFTCON		0x00A0
++#define PMU_VOL_GATE_SFTCON		0x00A8
++#define PMU_CRU_PWR_CON			0x00B0
++#define PMU_CRU_PWR_SFTCON		0x00B4
++#define PMU_CRU_PWR_STATE		0x00B8
++#define PMU_PLLPD_CON			0x00C0
++#define PMU_PLLPD_SFTCON		0x00C4
++#define PMU_INFO_TX_CON			0x00D0
++#define PMU_DSU_STABLE_CNT		0x0100
++#define PMU_PMIC_STABLE_CNT		0x0104
++#define PMU_OSC_STABLE_CNT		0x0108
++#define PMU_WAKEUP_RSTCLR_CNT		0x010C
++#define PMU_PLL_LOCK_CNT		0x0110
++#define PMU_DSU_PWRUP_CNT		0x0118
++#define PMU_DSU_PWRDN_CNT		0x011C
++#define PMU_GPU_VOLUP_CNT		0x0120
++#define PMU_GPU_VOLDN_CNT		0x0124
++#define PMU_WAKEUP_TIMEOUT_CNT		0x0128
++#define PMU_PWM_SWITCH_CNT		0x012C
++#define PMU_DBG_RST_CNT			0x0130
++#define PMU_SYS_REG0			0x0180
++#define PMU_SYS_REG1			0x0184
++#define PMU_SYS_REG2			0x0188
++#define PMU_SYS_REG3			0x018C
++#define PMU_SYS_REG4			0x0190
++#define PMU_SYS_REG5			0x0194
++#define PMU_SYS_REG6			0x0198
++#define PMU_SYS_REG7			0x019C
++#define PMU_DSU_PWR_CON			0x0300
++#define PMU_DSU_PWR_SFTCON		0x0304
++#define PMU_DSU_AUTO_CON		0x0308
++#define PMU_DSU_PWR_STATE		0x030C
++#define PMU_CPU_AUTO_PWR_CON0		0x0310
++#define PMU_CPU_AUTO_PWR_CON1		0x0314
++#define PMU_CPU_PWR_SFTCON		0x0318
++#define PMU_CLUSTER_PWR_ST		0x031C
++#define PMU_CLUSTER_IDLE_CON		0x0320
++#define PMU_CLUSTER_IDLE_SFTCON		0x0324
++#define PMU_CLUSTER_IDLE_ACK		0x0328
++#define PMU_CLUSTER_IDLE_ST		0x032C
++#define PMU_DBG_PWR_CON			0x0330
++
++/* PMU_SGRF */
++#define PMU_SGRF_SOC_CON1		0x0004
++#define PMU_SGRF_FAST_BOOT_ADDR		0x0180
++
++/* sys grf */
++#define GRF_CPU_STATUS0			0x0420
++
++#define CRU_SOFTRST_CON00		0x0400
++
++#define CORES_PM_DISABLE		0x0
++#define PD_CHECK_LOOP			500
++#define WFEI_CHECK_LOOP			500
++
++#define PMUSGRF_SOC_CON(i)		((i) * 0x4)
++/* Needed aligned 16 bytes for sp stack top */
++#define PSRAM_SP_TOP			((PMUSRAM_BASE + PMUSRAM_RSIZE) & ~0xf)
++#define PMU_CPUAPM_CON(cpu)		(0x0310 + (cpu) * 0x4)
++
++#define PMIC_SLEEP_FUN			0x07000100
++#define PMIC_SLEEP_GPIO			0x07000000
++#define GPIO_SWPORT_DR_L		0x0000
++#define GPIO_SWPORT_DR_H		0x0004
++#define GPIO_SWPORT_DDR_L		0x0008
++#define GPIO_SWPORT_DDR_H		0x000C
++#define PMIC_SLEEP_HIGH_LEVEL		0x00040004
++#define PMIC_SLEEP_LOW_LEVEL		0x00040000
++#define PMIC_SLEEP_OUT			0x00040004
++#define CPUS_BYPASS			0x007e4f7e
++#define CLB_INT_DISABLE			0x00010001
++#define WRITE_MASK_SET(value)		((value << 16) | value)
++#define WRITE_MASK_CLR(value)		((value << 16))
++
++enum pmu_cores_pm_by_wfi {
++	core_pm_en = 0,
++	core_pm_int_wakeup_en,
++	core_pm_int_wakeup_glb_msk,
++	core_pm_sft_wakeup_en,
++};
++
++/* The ways of cores power domain contorlling */
++enum cores_pm_ctr_mode {
++	core_pwr_pd = 0,
++	core_pwr_wfi = 1,
++	core_pwr_wfi_int = 2
++};
++
++/* PMU_PWR_DWN_ST */
++enum pmu_pdid {
++	PD_GPU,
++	PD_NPU,
++	PD_VPU,
++	PD_RKVENC,
++	PD_RKVDEC,
++	PD_RGA,
++	PD_VI,
++	PD_VO,
++	PD_PIPE,
++	PD_CENTER,
++	PD_END
++};
++
++/* PMU_PWR_CON */
++enum pmu_pwr_con {
++	POWRMODE_EN,
++	DSU_BYPASS,
++	BUS_BYPASS = 4,
++	DDR_BYPASS,
++	PWRDN_BYPASS,
++	CRU_BYPASS,
++	CPU0_BYPASS,
++	CPU1_BYPASS,
++	CPU2_BYPASS,
++	CPU3_BYPASS,
++	PMU_SLEEP_LOW = 15,
++};
++
++/* PMU_CRU_PWR_CON */
++enum pmu_cru_pwr_con {
++	ALIVE_32K_ENA,
++	OSC_DIS_ENA,
++	WAKEUP_RST_ENA,
++	INPUT_CLAMP_ENA,
++
++	ALIVE_OSC_ENA,
++	POWER_OFF_ENA,
++	PWM_SWITCH_ENA,
++	PWM_GPIO_IOE_ENA,
++
++	PWM_SWITCH_IOUT,
++	PD_BUS_CLK_SRC_GATE_ENA,
++	PD_PERI_CLK_SRC_GATE_ENA,
++	PD_PMU_CLK_SRC_GATE_ENA,
++
++	PMUMEM_CLK_SRC_GATE_ENA,
++	PWR_CON_END
++};
++
++/* PMU_PLLPD_CON */
++enum pmu_pllpd_con {
++	APLL_PD_ENA,
++	DPLL_PD_ENA,
++	CPLL_PD_ENA,
++	GPLL_PD_ENA,
++	MPLL_PD_ENA,
++	NPLL_PD_ENA,
++	HPLL_PD_ENA,
++	PPLL_PD_ENA,
++	VPLL_PD_ENA,
++	PLL_PD_END
++};
++
++/* PMU_DSU_PWR_CON */
++enum pmu_dsu_pwr_con {
++	DSU_PWRDN_ENA = 2,
++	DSU_PWROFF_ENA,
++	DSU_RET_ENA = 6,
++	CLUSTER_CLK_SRC_GATE_ENA,
++	DSU_PWR_CON_END
++};
++
++enum cpu_power_state {
++	CPU_POWER_ON,
++	CPU_POWER_OFF,
++	CPU_EMULATION_OFF,
++	CPU_RETENTION,
++	CPU_DEBUG
++};
++
++enum dsu_power_state {
++	DSU_POWER_ON,
++	CLUSTER_TRANSFER_IDLE,
++	DSU_POWER_DOWN,
++	DSU_OFF,
++	DSU_WAKEUP,
++	DSU_POWER_UP,
++	CLUSTER_TRANSFER_RESUME,
++	DSU_FUNCTION_RETENTION
++};
++
++enum pmu_wakeup_int_con {
++	WAKEUP_CPU0_INT_EN,
++	WAKEUP_CPU1_INT_EN,
++	WAKEUP_CPU2_INT_EN,
++	WAKEUP_CPU3_INT_EN,
++	WAKEUP_GPIO0_INT_EN,
++	WAKEUP_UART0_EN,
++	WAKEUP_SDMMC0_EN,
++	WAKEUP_SDMMC1_EN,
++	WAKEUP_SDMMC2_EN,
++	WAKEUP_USB_EN,
++	WAKEUP_PCIE_EN,
++	WAKEUP_VAD_EN,
++	WAKEUP_TIMER_EN,
++	WAKEUP_PWM0_EN,
++	WAKEUP_TIMEROUT_EN,
++	WAKEUP_MCU_SFT_EN,
++};
++
++enum pmu_wakeup_int_st {
++	WAKEUP_CPU0_INT_ST,
++	WAKEUP_CPU1_INT_ST,
++	WAKEUP_CPU2_INT_ST,
++	WAKEUP_CPU3_INT_ST,
++	WAKEUP_GPIO0_INT_ST,
++	WAKEUP_UART0_ST,
++	WAKEUP_SDMMC0_ST,
++	WAKEUP_SDMMC1_ST,
++	WAKEUP_SDMMC2_ST,
++	WAKEUP_USB_ST,
++	WAKEUP_PCIE_ST,
++	WAKEUP_VAD_ST,
++	WAKEUP_TIMER_ST,
++	WAKEUP_PWM0_ST,
++	WAKEUP_TIMEOUT_ST,
++	WAKEUP_SYS_INT_ST,
++};
++
++enum pmu_bus_idle_con0 {
++	IDLE_REQ_MSCH,
++	IDLE_REQ_GPU,
++	IDLE_REQ_NPU,
++	IDLE_REQ_VI,
++	IDLE_REQ_VO,
++	IDLE_REQ_RGA,
++	IDLE_REQ_VPU,
++	IDLE_REQ_RKVENC,
++	IDLE_REQ_RKVDEC,
++	IDLE_REQ_GIC_AUDIO,
++	IDLE_REQ_PHP,
++	IDLE_REQ_PIPE,
++	IDLE_REQ_SECURE_FLASH,
++	IDLE_REQ_PERIMID,
++	IDLE_REQ_USB,
++	IDLE_REQ_BUS,
++};
++
++enum pmu_bus_idle_con1 {
++	IDLE_REQ_TOP1,
++	IDLE_REQ_TOP2,
++	IDLE_REQ_PMU,
++};
++
++enum pmu_pwr_gate_con {
++	PD_GPU_DWN_ENA,
++	PD_NPU_DWN_ENA,
++	PD_VPU_DWN_ENA,
++	PD_RKVENC_DWN_ENA,
++
++	PD_RKVDEC_DWN_ENA,
++	PD_RGA_DWN_ENA,
++	PD_VI_DWN_ENA,
++	PD_VO_DWN_ENA,
++
++	PD_PIPE_DWN_ENA,
++	PD_CENTER_DWN_ENA,
++};
++
++enum pmu_ddr_pwr_con {
++	DDR_SREF_ENA,
++	DDRIO_RET_ENTER_ENA,
++	DDRIO_RET_EXIT_ENA = 2,
++	DDRPHY_AUTO_GATING_ENA = 4,
++};
++
++enum pmu_vol_gate_soft_con {
++	VD_GPU_ENA,
++	VD_NPU_ENA,
++};
++
++#endif /* __PMU_H__ */
+diff --git a/plat/rockchip/rk3568/drivers/soc/soc.c b/plat/rockchip/rk3568/drivers/soc/soc.c
+new file mode 100644
+index 000000000..2af388735
+--- /dev/null
++++ b/plat/rockchip/rk3568/drivers/soc/soc.c
+@@ -0,0 +1,103 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <common/debug.h>
++#include <lib/xlat_tables/xlat_tables_v2.h>
++#include <mmio.h>
++#include <platform_def.h>
++
++#include <soc.h>
++
++const mmap_region_t plat_rk_mmap[] = {
++	MAP_REGION_FLAT(RKFPGA_DEV_RNG0_BASE, RKFPGA_DEV_RNG0_SIZE,
++			MT_DEVICE | MT_RW | MT_SECURE),
++	MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE,
++			MT_MEMORY | MT_RW | MT_SECURE),
++
++	{ 0 }
++};
++
++/* The RockChip power domain tree descriptor */
++const unsigned char rockchip_power_domain_tree_desc[] = {
++	/* No of root nodes */
++	PLATFORM_SYSTEM_COUNT,
++	/* No of children for the root node */
++	PLATFORM_CLUSTER_COUNT,
++	/* No of children for the first cluster node */
++	PLATFORM_CLUSTER0_CORE_COUNT,
++};
++
++static void secure_timer_init(void)
++{
++	mmio_write_32(STIMER0_CHN_BASE(1) + TIMER_CONTROL_REG, TIMER_DIS);
++	mmio_write_32(STIMER0_CHN_BASE(1) + TIMER_LOAD_COUNT0, 0xffffffff);
++	mmio_write_32(STIMER0_CHN_BASE(1) + TIMER_LOAD_COUNT1, 0xffffffff);
++
++	/* auto reload & enable the timer */
++	mmio_write_32(STIMER0_CHN_BASE(1) + TIMER_CONTROL_REG, TIMER_EN);
++}
++
++static void sgrf_init(void)
++{
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(0), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(1), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(2), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(3), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(4), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(5), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(6), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(7), 0xffff0000);
++	mmio_write_32(SGRF_BASE + SGRF_FIREWALL_SLV_CON(8), 0xffff0000);
++
++	mmio_write_32(DDRSGRF_BASE + FIREWALL_DDR_FW_DDR_CON_REG, 0xffff0000);
++}
++
++static void set_pll_slow_mode(uint32_t clk_pll)
++{
++	mmio_write_32(CRU_BASE + CRU_MODE_CON00, 0x03 << (16 + clk_pll * 2));
++}
++
++static void __dead2 soc_global_soft_reset(void)
++{
++	set_pll_slow_mode(CLK_CPLL);
++	set_pll_slow_mode(CLK_GPLL);
++	set_pll_slow_mode(CLK_NPLL);
++	set_pll_slow_mode(CLK_VPLL);
++	set_pll_slow_mode(CLK_USBPLL);
++	set_pll_slow_mode(CLK_APLL);
++	mmio_write_32(PMUCRU_BASE + PMUCRU_MODE_CON00, 0x000f0000);
++
++	dsb();
++	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL);
++	/*
++	 * Maybe the HW needs some times to reset the system,
++	 * so we do not hope the core to excute valid codes.
++	 */
++	while (1) {
++		;
++	}
++}
++
++static void rockchip_system_reset_init(void)
++{
++	mmio_write_32(GRF_BASE + 0x0508, 0x00100010);
++	mmio_write_32(CRU_BASE + 0x00dc, 0x01030103);
++}
++
++void __dead2 rockchip_soc_soft_reset(void)
++{
++	soc_global_soft_reset();
++}
++
++void plat_rockchip_soc_init(void)
++{
++	secure_timer_init();
++	sgrf_init();
++	rockchip_system_reset_init();
++	NOTICE("BL31: Rockchip release version: v%d.%d\n",
++		MAJOR_VERSION, MINOR_VERSION);
++}
++
+diff --git a/plat/rockchip/rk3568/drivers/soc/soc.h b/plat/rockchip/rk3568/drivers/soc/soc.h
+new file mode 100644
+index 000000000..41a2586a3
+--- /dev/null
++++ b/plat/rockchip/rk3568/drivers/soc/soc.h
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __SOC_H__
++#define __SOC_H__
++
++#define RKFPGA_DEV_RNG0_BASE		0xf8000000
++#define RKFPGA_DEV_RNG0_SIZE		0x07fff000
++
++#define CRU_MODE_CON00			0x00c0
++#define PMUCRU_MODE_CON00		0x0080
++
++#define CRU_GLB_SRST_FST		0x00d4
++#define GLB_SRST_FST_CFG_VAL		0xfdb9
++
++#define PMU_GRF_GPIO0A_IOMUX_L		0x00
++#define PMU_GRF_SOC_CON(i)		(0x0100 + i * 4)
++
++#define CRU_SOFTRST_CON			0x300
++#define CRU_SOFTRSTS_CON(n)		(CRU_SOFTRST_CON + ((n) * 4))
++#define CRU_SOFTRSTS_CON_CNT		26
++#define GRF_DDR_CON3			0x000c
++#define SGRF_FIREWALL_SLV_CON(i)	(0x240 + i * 4)
++
++#define FIREWALL_DDR_FW_DDR_CON_REG	0x80
++
++ /* low 32 bits */
++#define TIMER_LOAD_COUNT0		0x00
++#define TIMER_LOAD_COUNT1		0x04
++#define TIMER_CURRENT_VALUE0		0x08
++#define TIMER_CURRENT_VALUE1		0x0c
++#define TIMER_CONTROL_REG		0x10
++#define TIMER_INTSTATUS			0x18
++#define TIMER_DIS			0x0
++#define TIMER_EN			0x1
++#define STIMER0_CHN_BASE(n)		(STIME_BASE + 0x20 * (n))
++
++#define PMU_GRF_GPIO0B_IOMUX_L		0x0008
++#define PMUCRU_PMUCLKSEL_CON00		0x0100
++#define PMUPVTM_BASE			0xfdd80000
++#define PVTM_CON0			0x0004
++#define PVTM_CON1			0x0008
++#define PVTM_STATUS0			0x0080
++#define PVTM_STATUS1			0x0084
++#define PMUCRU_PMUGATE_CON01		0x0184
++#define PVTM_CALC_CNT			0x200
++#define PMU_GRF_DLL_CON0		0x0180
++
++enum cru_mode_con00 {
++	CLK_APLL,
++	CLK_DPLL,
++	CLK_CPLL,
++	CLK_GPLL,
++	CLK_REVSERVED,
++	CLK_NPLL,
++	CLK_VPLL,
++	CLK_USBPLL,
++};
++
++#endif /* __SOC_H__ */
+diff --git a/plat/rockchip/rk3568/include/plat.ld.S b/plat/rockchip/rk3568/include/plat.ld.S
+new file mode 100644
+index 000000000..ddd584d4a
+--- /dev/null
++++ b/plat/rockchip/rk3568/include/plat.ld.S
+@@ -0,0 +1,36 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++#ifndef ROCKCHIP_PLAT_LD_S
++#define ROCKCHIP_PLAT_LD_S
++
++MEMORY {
++    PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
++}
++
++SECTIONS
++{
++	. = PMUSRAM_BASE;
++
++	/*
++	 * pmu_cpuson_entrypoint request address
++	 * align 64K when resume, so put it in the
++	 * start of pmusram
++	 */
++	.pmusram : {
++		ASSERT(. == ALIGN(64 * 1024),
++			".pmusram.entry request 64K aligned.");
++		KEEP(*(.pmusram.entry))
++
++		__bl31_pmusram_text_start = .;
++		*(.pmusram.text)
++		*(.pmusram.rodata)
++		__bl31_pmusram_text_end = .;
++		__bl31_pmusram_data_start = .;
++		*(.pmusram.data)
++		__bl31_pmusram_data_end = .;
++	} >PMUSRAM
++}
++#endif /* ROCKCHIP_PLAT_LD_S */
+diff --git a/plat/rockchip/rk3568/include/plat_sip_calls.h b/plat/rockchip/rk3568/include/plat_sip_calls.h
+new file mode 100644
+index 000000000..6acb87628
+--- /dev/null
++++ b/plat/rockchip/rk3568/include/plat_sip_calls.h
+@@ -0,0 +1,12 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PLAT_SIP_CALLS_H__
++#define __PLAT_SIP_CALLS_H__
++
++#define RK_PLAT_SIP_NUM_CALLS	0
++
++#endif /* __PLAT_SIP_CALLS_H__ */
+diff --git a/plat/rockchip/rk3568/include/platform_def.h b/plat/rockchip/rk3568/include/platform_def.h
+new file mode 100644
+index 000000000..19363a42b
+--- /dev/null
++++ b/plat/rockchip/rk3568/include/platform_def.h
+@@ -0,0 +1,136 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PLATFORM_DEF_H__
++#define __PLATFORM_DEF_H__
++
++#include <arch.h>
++#include <common_def.h>
++#include <rk3568_def.h>
++
++#define DEBUG_XLAT_TABLE 0
++
++/*******************************************************************************
++ * Platform binary types for linking
++ ******************************************************************************/
++#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
++#define PLATFORM_LINKER_ARCH		aarch64
++
++/*******************************************************************************
++ * Generic platform constants
++ ******************************************************************************/
++
++/* Size of cacheable stacks */
++#if DEBUG_XLAT_TABLE
++#define PLATFORM_STACK_SIZE 0x800
++#elif IMAGE_BL1
++#define PLATFORM_STACK_SIZE 0x440
++#elif IMAGE_BL2
++#define PLATFORM_STACK_SIZE 0x400
++#elif IMAGE_BL31
++#define PLATFORM_STACK_SIZE 0x800
++#elif IMAGE_BL32
++#define PLATFORM_STACK_SIZE 0x440
++#endif
++
++#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
++
++#define PLATFORM_SYSTEM_COUNT		1
++#define PLATFORM_CLUSTER_COUNT		1
++#define PLATFORM_CLUSTER0_CORE_COUNT	4
++
++#define PLATFORM_CLUSTER1_CORE_COUNT	0
++#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
++					 PLATFORM_CLUSTER0_CORE_COUNT)
++
++#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
++					 PLATFORM_CLUSTER_COUNT +	\
++					 PLATFORM_CORE_COUNT)
++
++#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
++
++#define PLAT_RK_CLST_TO_CPUID_SHIFT	8
++
++/*
++ * This macro defines the deepest retention state possible. A higher state
++ * id will represent an invalid or a power down state.
++ */
++#define PLAT_MAX_RET_STATE		1
++
++/*
++ * This macro defines the deepest power down states possible. Any state ID
++ * higher than this is invalid.
++ */
++#define PLAT_MAX_OFF_STATE		2
++/*******************************************************************************
++ * Platform memory map related constants
++ ******************************************************************************/
++/* TF txet, ro, rw, Size: 512KB */
++#define TZRAM_BASE		(0x0)
++#define TZRAM_SIZE		(0x100000)
++
++/*******************************************************************************
++ * BL31 specific defines.
++ ******************************************************************************/
++/*
++ * Put BL3-1 at the top of the Trusted RAM
++ */
++#define BL31_BASE		(TZRAM_BASE + 0x40000)
++#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
++
++/*******************************************************************************
++ * Platform specific page table and MMU setup constants
++ ******************************************************************************/
++#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
++#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
++
++#define ADDR_SPACE_SIZE			(1ull << 32)
++#define MAX_XLAT_TABLES			18
++#define MAX_MMAP_REGIONS		27
++
++/*******************************************************************************
++ * Declarations and constants to access the mailboxes safely. Each mailbox is
++ * aligned on the biggest cache line size in the platform. This is known only
++ * to the platform as it might have a combination of integrated and external
++ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
++ * line at any cache level. They could belong to different cpus/clusters &
++ * get written while being protected by different locks causing corruption of
++ * a valid mailbox address.
++ ******************************************************************************/
++#define CACHE_WRITEBACK_SHIFT	6
++#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
++
++/*
++ * Define GICD and GICC and GICR base
++ */
++#define PLAT_RK_GICD_BASE	PLAT_GICD_BASE
++#define PLAT_RK_GICC_BASE	PLAT_GICC_BASE
++#define PLAT_RK_GICR_BASE	PLAT_GICR_BASE
++
++/*
++ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
++ * terminology. On a GICv2 system or mode, the lists will be merged and treated
++ * as Group 0 interrupts.
++ */
++
++#define PLAT_RK_GICV3_G1S_IRQS						\
++	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \
++		       INTR_GROUP1S, GIC_INTR_CFG_LEVEL)
++
++#define PLAT_RK_GICV3_G0_IRQS						\
++	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
++		       INTR_GROUP0, GIC_INTR_CFG_LEVEL)
++
++#define PLAT_RK_UART_BASE		FPGA_UART_BASE
++#define PLAT_RK_UART_CLOCK		FPGA_UART_CLOCK
++#define PLAT_RK_UART_BAUDRATE	FPGA_BAUDRATE
++
++#define PLAT_RK_PRIMARY_CPU	0x0
++
++#define ATAGS_PHYS_SIZE		0x2000
++#define ATAGS_PHYS_BASE		(0x200000 - ATAGS_PHYS_SIZE)/* [2M-8K, 2M] */
++
++#endif /* __PLATFORM_DEF_H__ */
+diff --git a/plat/rockchip/rk3568/plat_sip_calls.c b/plat/rockchip/rk3568/plat_sip_calls.c
+new file mode 100644
+index 000000000..b0f3a03da
+--- /dev/null
++++ b/plat/rockchip/rk3568/plat_sip_calls.c
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <common/debug.h>
++#include <common/runtime_svc.h>
++#include <lib/mmio.h>
++#include <platform_def.h>
++
++#include <plat_sip_calls.h>
++#include <rockchip_sip_svc.h>
++
++uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
++				    u_register_t x1,
++				    u_register_t x2,
++				    u_register_t x3,
++				    u_register_t x4,
++				    void *cookie,
++				    void *handle,
++				    u_register_t flags)
++{
++	ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
++	SMC_RET1(handle, SMC_UNK);
++}
+diff --git a/plat/rockchip/rk3568/platform.mk b/plat/rockchip/rk3568/platform.mk
+new file mode 100644
+index 000000000..1155ff841
+--- /dev/null
++++ b/plat/rockchip/rk3568/platform.mk
+@@ -0,0 +1,96 @@
++#
++# Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++#
++# SPDX-License-Identifier: BSD-3-Clause
++#
++
++RK_PLAT			:=	plat/rockchip
++RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
++RK_PLAT_COMMON		:=	${RK_PLAT}/common
++
++DISABLE_BIN_GENERATION	:=	1
++GICV3_SUPPORT_GIC600	:=	1
++include lib/coreboot/coreboot.mk
++include lib/libfdt/libfdt.mk
++include lib/xlat_tables_v2/xlat_tables.mk
++# GIC-600 configuration
++GICV3_IMPL		:=	GIC600
++# Include GICv3 driver files
++include drivers/arm/gic/v3/gicv3.mk
++
++PLAT_INCLUDES		:=	-Iinclude/bl31					\
++				-Iinclude/common				\
++				-Iinclude/drivers				\
++				-Iinclude/drivers/arm				\
++				-Iinclude/drivers/auth				\
++				-Iinclude/drivers/io				\
++				-Iinclude/drivers/ti/uart			\
++				-Iinclude/lib					\
++				-Iinclude/lib/cpus/${ARCH}			\
++				-Iinclude/lib/el3_runtime			\
++				-Iinclude/lib/pmf				\
++				-Iinclude/lib/psci				\
++				-Iinclude/plat/common				\
++				-Iinclude/services				\
++				-Iinclude/plat/common/				\
++				-Idrivers/arm/gic/v3/				\
++				-I${RK_PLAT_COMMON}/				\
++				-I${RK_PLAT_COMMON}/pmusram/			\
++				-I${RK_PLAT_COMMON}/include/			\
++				-I${RK_PLAT_COMMON}/drivers/pmu/		\
++				-I${RK_PLAT_COMMON}/drivers/parameter/		\
++				-I${RK_PLAT_SOC}/				\
++				-I${RK_PLAT_SOC}/drivers/pmu/			\
++				-I${RK_PLAT_SOC}/drivers/soc/			\
++				-I${RK_PLAT_SOC}/include/
++
++RK_GIC_SOURCES		:=	${GICV3_SOURCES}				\
++				plat/common/plat_gicv3.c			\
++				${RK_PLAT}/common/rockchip_gicv3.c
++
++PLAT_BL_COMMON_SOURCES	:=	${XLAT_TABLES_LIB_SRCS}				\
++				common/desc_image_load.c			\
++				plat/common/aarch64/crash_console_helpers.S	\
++				lib/bl_aux_params/bl_aux_params.c		\
++				plat/common/plat_psci_common.c
++
++ifneq (${ENABLE_STACK_PROTECTOR},0)
++PLAT_BL_COMMON_SOURCES	+=	${RK_PLAT_COMMON}/rockchip_stack_protector.c
++endif
++
++BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
++				drivers/arm/cci/cci.c				\
++				lib/cpus/aarch64/cortex_a55.S			\
++				drivers/ti/uart/aarch64/16550_console.S		\
++				drivers/delay_timer/delay_timer.c		\
++				drivers/delay_timer/generic_delay_timer.c	\
++				$(LIBFDT_SRCS)					\
++				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
++				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
++				${RK_PLAT_COMMON}/params_setup.c		\
++				${RK_PLAT_COMMON}/plat_pm.c			\
++				${RK_PLAT_COMMON}/plat_topology.c		\
++				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
++				${RK_PLAT_COMMON}/pmusram/cpus_on_fixed_addr.S	\
++				${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c	\
++				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
++				${RK_PLAT_SOC}/drivers/soc/soc.c		\
++				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
++				${RK_PLAT_SOC}/plat_sip_calls.c
++
++ENABLE_PLAT_COMPAT	:=	0
++MULTI_CONSOLE_API	:=	1
++# System coherency is managed in hardware
++HW_ASSISTED_COHERENCY	:=	1
++#Enable errata for cortex_a55
++ERRATA_A55_1530923	:=	1
++
++# When building for systems with hardware-assisted coherency, there's no need to
++# use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too.
++USE_COHERENT_MEM	:=	0
++
++$(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER))
++$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
++
++# Do not enable SVE
++ENABLE_SVE_FOR_NS	:=	0
+diff --git a/plat/rockchip/rk3568/rk3568_def.h b/plat/rockchip/rk3568/rk3568_def.h
+new file mode 100644
+index 000000000..0d1e5d1a1
+--- /dev/null
++++ b/plat/rockchip/rk3568/rk3568_def.h
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (c) 2023, ARM Limited and Contributors. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PLAT_DEF_H__
++#define __PLAT_DEF_H__
++
++#define MAJOR_VERSION		(1)
++#define MINOR_VERSION		(0)
++
++#define SIZE_K(n)		((n) * 1024)
++
++/* Special value used to verify platform parameters from BL2 to BL3-1 */
++#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
++
++#define GIC600_BASE		0xfd400000
++#define GIC600_SIZE		SIZE_K(64)
++
++#define PMUSGRF_BASE		0xfdc00000
++#define SYSSGRF_BASE		0xfdc10000
++#define PMUGRF_BASE		0xfdc20000
++#define CPUGRF_BASE		0xfdc30000
++#define DDRGRF_BASE		0xfdc40000
++#define PIPEGRF_BASE		0xfdc50000
++#define GRF_BASE		0xfdc60000
++#define PIPEPHY_GRF0		0xfdc70000
++#define PIPEPHY_GRF1		0xfdc80000
++#define PIPEPHY_GRF2		0xfdc90000
++#define USBPHY_U3_GRF		0xfdca0000
++#define USB2PHY_U2_GRF		0xfdca8000
++#define EDPPHY_GRF		0xfdcb0000
++#define SYSSRAM_BASE		0xfdcc0000
++#define PCIE30PHY_GRF		0xfdcb8000
++#define USBGRF_BASE		0xfdcf0000
++
++#define PMUCRU_BASE		0xfdd00000
++#define SCRU_BASE		0xfdd10000
++#define SGRF_BASE		0xfdd18000
++#define STIME_BASE		0xfdd1c000
++#define CRU_BASE		0xfdd20000
++#define PMUSCRU_BASE		0xfdd30000
++#define I2C0_BASE		0xfdd40000
++
++#define UART0_BASE		0xfdd50000
++#define GPIO0_BASE		0xfdd60000
++#define PMUPVTM_BASE		0xfdd80000
++#define PMU_BASE		0xfdd90000
++#define PMUSRAM_BASE		0xfdcd0000
++#define PMUSRAM_SIZE		SIZE_K(128)
++#define PMUSRAM_RSIZE		SIZE_K(8)
++
++#define DDRSGRF_BASE		0xfe200000
++#define UART1_BASE		0xfe650000
++#define UART2_BASE		0xfe660000
++#define GPIO1_BASE		0xfe740000
++#define GPIO2_BASE		0xfe750000
++#define GPIO3_BASE		0xfe760000
++#define GPIO4_BASE		0xfe770000
++
++#define REMAP_BASE		0xffff0000
++#define REMAP_SIZE		SIZE_K(64)
++/**************************************************************************
++ * UART related constants
++ **************************************************************************/
++#define FPGA_UART_BASE		UART2_BASE
++#define FPGA_BAUDRATE		1500000
++#define FPGA_UART_CLOCK		24000000
++
++/******************************************************************************
++ * System counter frequency related constants
++ ******************************************************************************/
++#define SYS_COUNTER_FREQ_IN_TICKS	24000000
++#define SYS_COUNTER_FREQ_IN_MHZ		24
++
++/******************************************************************************
++ * GIC-600 & interrupt handling related constants
++ ******************************************************************************/
++
++/* Base rk_platform compatible GIC memory map */
++#define PLAT_GICD_BASE		GIC600_BASE
++#define PLAT_GICC_BASE		0
++#define PLAT_GICR_BASE		(GIC600_BASE + 0x60000)
++
++/******************************************************************************
++ * sgi, ppi
++ ******************************************************************************/
++#define RK_IRQ_SEC_PHY_TIMER	29
++
++#define RK_IRQ_SEC_SGI_0	8
++#define RK_IRQ_SEC_SGI_1	9
++#define RK_IRQ_SEC_SGI_2	10
++#define RK_IRQ_SEC_SGI_3	11
++#define RK_IRQ_SEC_SGI_4	12
++#define RK_IRQ_SEC_SGI_5	13
++#define RK_IRQ_SEC_SGI_6	14
++#define RK_IRQ_SEC_SGI_7	15
++
++#define SHARE_MEM_BASE		0x100000/* [1MB, 1MB+60K]*/
++#define SHARE_MEM_PAGE_NUM	15
++#define SHARE_MEM_SIZE		SIZE_K(SHARE_MEM_PAGE_NUM * 4)
++
++#endif /* __PLAT_DEF_H__ */
+-- 
+2.46.0
+
+From bca64f9aff87ed40921997d6fb60f81215e23133 Mon Sep 17 00:00:00 2001
+From: XiaoDong Huang <derrick.huang@rock-chips.com>
+Date: Sun, 25 Jun 2023 15:55:42 +0800
+Subject: [PATCH 2/5] fix(rockchip): xlat: fix compatibility between v1 and v2
+
+Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
+Change-Id: I1194ef232947ba90fa374466773373762a5acdb5
+---
+ plat/rockchip/common/aarch32/platform_common.c | 2 +-
+ plat/rockchip/common/aarch64/platform_common.c | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/plat/rockchip/common/aarch32/platform_common.c b/plat/rockchip/common/aarch32/platform_common.c
+index 9030951e4..25ee964fd 100644
+--- a/plat/rockchip/common/aarch32/platform_common.c
++++ b/plat/rockchip/common/aarch32/platform_common.c
+@@ -12,7 +12,7 @@
+ #include <common/bl_common.h>
+ #include <common/debug.h>
+ #include <lib/utils.h>
+-#include <lib/xlat_tables/xlat_tables.h>
++#include <lib/xlat_tables/xlat_tables_compat.h>
+ 
+ #include <plat_private.h>
+ 
+diff --git a/plat/rockchip/common/aarch64/platform_common.c b/plat/rockchip/common/aarch64/platform_common.c
+index d563dfd8f..df51d895f 100644
+--- a/plat/rockchip/common/aarch64/platform_common.c
++++ b/plat/rockchip/common/aarch64/platform_common.c
+@@ -13,6 +13,8 @@
+ #include <common/debug.h>
+ #include <drivers/arm/cci.h>
+ #include <lib/utils.h>
++#include <lib/xlat_tables/xlat_tables_compat.h>
++
+ #include <plat_private.h>
+ 
+ #ifdef PLAT_RK_CCI_BASE
+-- 
+2.46.0
+
+From db895eb6a1cf6c214b4960c9a94a4d45f72df4e4 Mon Sep 17 00:00:00 2001
+From: XiaoDong Huang <derrick.huang@rock-chips.com>
+Date: Sun, 25 Jun 2023 16:20:08 +0800
+Subject: [PATCH 3/5] fix(rockchip): add parenthesis for BITS_SHIFT macro
+
+Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
+Change-Id: Ideac271469f0753c5b7aaed7bb07a792b64ae01e
+---
+ plat/rockchip/common/include/plat_private.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
+index 465f372e5..44a0c461d 100644
+--- a/plat/rockchip/common/include/plat_private.h
++++ b/plat/rockchip/common/include/plat_private.h
+@@ -49,7 +49,7 @@ extern uint32_t __sram_incbin_real_end;
+ #endif
+ 
+ #ifndef BITS_SHIFT
+-#define BITS_SHIFT(bits, shift)	(bits << (shift))
++#define BITS_SHIFT(bits, shift)	((bits) << (shift))
+ #endif
+ 
+ #ifndef BITS_WITH_WMASK
+-- 
+2.46.0
+
+From 6ff9ec2f85c76efc7c707345de38e04798fcf397 Mon Sep 17 00:00:00 2001
+From: XiaoDong Huang <derrick.huang@rock-chips.com>
+Date: Mon, 26 Jun 2023 16:43:30 +0800
+Subject: [PATCH 4/5] feat(rk3588): support rk3588
+
+rk3588 is an Octa-core soc with Cortex-a55/a76 inside.
+This patch supports the following functions:
+1. basic platform setup
+2. power up/off cpus
+3. suspend/resume cpus
+4. suspend/resume system
+5. reset system
+6. power off system
+
+Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
+Change-Id: I598109f15a2efd5b33aedd176cf708c08cb1dcf4
+---
+ docs/plat/rockchip.rst                        |    1 +
+ .../rockchip/common/include/plat_pm_helpers.h |   51 +
+ plat/rockchip/common/plat_pm_helpers.c        |  213 +++
+ .../rk3588/drivers/pmu/plat_pmu_macros.S      |   21 +
+ plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.c |  555 +++++++
+ plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.h |   23 +
+ plat/rockchip/rk3588/drivers/pmu/pmu.c        | 1436 +++++++++++++++++
+ plat/rockchip/rk3588/drivers/pmu/pmu.h        |  589 +++++++
+ plat/rockchip/rk3588/drivers/secure/secure.c  |  188 +++
+ plat/rockchip/rk3588/drivers/secure/secure.h  |   54 +
+ plat/rockchip/rk3588/drivers/soc/soc.c        |   96 ++
+ plat/rockchip/rk3588/drivers/soc/soc.h        |  198 +++
+ plat/rockchip/rk3588/include/plat.ld.S        |   42 +
+ plat/rockchip/rk3588/include/plat_sip_calls.h |   12 +
+ plat/rockchip/rk3588/include/platform_def.h   |  119 ++
+ plat/rockchip/rk3588/plat_sip_calls.c         |   27 +
+ plat/rockchip/rk3588/platform.mk              |   85 +
+ plat/rockchip/rk3588/rk3588_def.h             |  221 +++
+ 18 files changed, 3931 insertions(+)
+ create mode 100644 plat/rockchip/common/include/plat_pm_helpers.h
+ create mode 100644 plat/rockchip/common/plat_pm_helpers.c
+ create mode 100644 plat/rockchip/rk3588/drivers/pmu/plat_pmu_macros.S
+ create mode 100644 plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.c
+ create mode 100644 plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.h
+ create mode 100644 plat/rockchip/rk3588/drivers/pmu/pmu.c
+ create mode 100644 plat/rockchip/rk3588/drivers/pmu/pmu.h
+ create mode 100644 plat/rockchip/rk3588/drivers/secure/secure.c
+ create mode 100644 plat/rockchip/rk3588/drivers/secure/secure.h
+ create mode 100644 plat/rockchip/rk3588/drivers/soc/soc.c
+ create mode 100644 plat/rockchip/rk3588/drivers/soc/soc.h
+ create mode 100644 plat/rockchip/rk3588/include/plat.ld.S
+ create mode 100644 plat/rockchip/rk3588/include/plat_sip_calls.h
+ create mode 100644 plat/rockchip/rk3588/include/platform_def.h
+ create mode 100644 plat/rockchip/rk3588/plat_sip_calls.c
+ create mode 100644 plat/rockchip/rk3588/platform.mk
+ create mode 100644 plat/rockchip/rk3588/rk3588_def.h
+
+diff --git a/docs/plat/rockchip.rst b/docs/plat/rockchip.rst
+index 53f63b59f..384cd73d8 100644
+--- a/docs/plat/rockchip.rst
++++ b/docs/plat/rockchip.rst
+@@ -11,6 +11,7 @@ This includes right now:
+ -  rk3368: Octa-Core Cortex-A53
+ -  rk3399: Hexa-Core Cortex-A53/A72
+ -  rk3566/rk3568: Quad-Core Cortex-A55
++-  rk3588: Octa-Core Cortex-A55/A76
+ 
+ 
+ Boot Sequence
+diff --git a/plat/rockchip/common/include/plat_pm_helpers.h b/plat/rockchip/common/include/plat_pm_helpers.h
+new file mode 100644
+index 000000000..2204a65de
+--- /dev/null
++++ b/plat/rockchip/common/include/plat_pm_helpers.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef PLAT_PM_HELPERS_H
++#define PLAT_PM_HELPERS_H
++
++#include <stdint.h>
++
++/**
++ * Use this macro to define a register region.
++ * start: start offset from the base address.
++ * end: end offset from the base address.
++ * stride: stride of registers in region.
++ * base: base address of registers in region.
++ * wmsk: write mask of registers in region.
++ */
++#define REG_REGION(_start, _end, _stride, _base, _wmsk)	\
++{							\
++	.start = (_base) + (_start),			\
++	.end   = (_base) + (_end),			\
++	.stride   = _stride,				\
++	.wmsk  = _wmsk					\
++}
++
++struct reg_region {
++	/* Start address of region */
++	uint32_t start;
++	/* End address of region */
++	uint32_t end;
++	/* Stride of registers in region */
++	uint32_t stride;
++	/* Write mask of registers in region */
++	uint32_t wmsk;
++	/* Buffer to save/restore registers in region */
++	uint32_t *buf;
++};
++
++void rockchip_alloc_region_mem(struct reg_region *rgns, uint32_t rgn_num);
++void rockchip_reg_rgn_save(struct reg_region *rgns, uint32_t rgn_num);
++void rockchip_reg_rgn_restore(struct reg_region *rgns, uint32_t rgn_num);
++void rockchip_reg_rgn_restore_reverse(struct reg_region *rgns, uint32_t rgn_num);
++void rockchip_regs_dump(uint32_t base,
++			uint32_t start_offset,
++			uint32_t end_offset,
++			uint32_t stride);
++void rockchip_dump_reg_rgns(struct reg_region *rgns, uint32_t rgn_num);
++
++#endif /* PLAT_PM_HELPERS_H */
+diff --git a/plat/rockchip/common/plat_pm_helpers.c b/plat/rockchip/common/plat_pm_helpers.c
+new file mode 100644
+index 000000000..191b0cae0
+--- /dev/null
++++ b/plat/rockchip/common/plat_pm_helpers.c
+@@ -0,0 +1,213 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <arch_helpers.h>
++#include <bl31/bl31.h>
++#include <common/debug.h>
++#include <drivers/console.h>
++#include <drivers/delay_timer.h>
++#include <lib/mmio.h>
++#include <plat/common/platform.h>
++#include <platform_def.h>
++
++#include <plat_pm_helpers.h>
++
++#define ROCKCHIP_PM_REG_REGION_MEM_LEN	(ROCKCHIP_PM_REG_REGION_MEM_SIZE / sizeof(uint32_t))
++
++/* REG region */
++#define RGN_LEN(_rgn)		(((_rgn)->end - (_rgn)->start) / (_rgn)->stride + 1)
++
++#ifndef ROCKCHIP_PM_REG_REGION_MEM_SIZE
++#define ROCKCHIP_PM_REG_REGION_MEM_SIZE		0
++#endif
++
++#ifdef ROCKCHIP_REG_RGN_MEM_BASE
++static uint32_t *region_mem = (uint32_t *)ROCKCHIP_REG_RGN_MEM_BASE;
++#else
++static uint32_t region_mem[ROCKCHIP_PM_REG_REGION_MEM_LEN];
++#endif
++
++static int region_mem_idx;
++
++static int alloc_region_mem(uint32_t *buf, int max_len,
++			    struct reg_region *rgns, uint32_t rgn_num)
++{
++	int i;
++	int total_len = 0, len = 0;
++	struct reg_region *r = rgns;
++
++	assert(buf && rgns && rgn_num);
++
++	for (i = 0; i < rgn_num; i++, r++) {
++		if (total_len < max_len)
++			r->buf = &buf[total_len];
++
++		len = RGN_LEN(r);
++		total_len += len;
++	}
++
++	if (total_len > max_len) {
++		ERROR("%s The buffer remain length:%d is too small for region:0x%x, at least %d\n",
++		      __func__, max_len, rgns[0].start, total_len);
++		panic();
++	}
++
++	return total_len;
++}
++
++/**
++ * Alloc memory to reg_region->buf from region_mem.
++ * @rgns - struct reg_region array.
++ * @rgn_num - struct reg_region array length.
++ */
++void rockchip_alloc_region_mem(struct reg_region *rgns, uint32_t rgn_num)
++{
++	int max_len = 0, len;
++
++	assert(rgns && rgn_num);
++
++	max_len = ROCKCHIP_PM_REG_REGION_MEM_LEN - region_mem_idx;
++
++	len = alloc_region_mem(region_mem + region_mem_idx, max_len,
++			       rgns, rgn_num);
++
++	region_mem_idx += len;
++}
++
++/**
++ * Save (reg_region->start ~ reg_region->end) to reg_region->buf.
++ * @rgns - struct reg_region array.
++ * @rgn_num - struct reg_region array length.
++ */
++void rockchip_reg_rgn_save(struct reg_region *rgns, uint32_t rgn_num)
++{
++	struct reg_region *r;
++	uint32_t addr;
++	int i, j;
++
++	assert(rgns && rgn_num);
++
++	for (i = 0; i < rgn_num; i++) {
++		r = &rgns[i];
++		for (j = 0, addr = r->start; addr <= r->end; addr += r->stride, j++)
++			r->buf[j] = mmio_read_32(addr);
++	}
++}
++
++/**
++ * Restore reg_region->buf to (reg_region->start ~ reg_region->end).
++ * @rgns - struct reg_region array.
++ * @rgn_num - struct reg_region array length.
++ */
++void rockchip_reg_rgn_restore(struct reg_region *rgns, uint32_t rgn_num)
++{
++	struct reg_region *r;
++	uint32_t addr;
++	int i, j;
++
++	assert(rgns && rgn_num);
++
++	for (i = 0; i < rgn_num; i++) {
++		r = &rgns[i];
++		for (j = 0, addr = r->start; addr <= r->end; addr += r->stride, j++)
++			mmio_write_32(addr, r->buf[j] | r->wmsk);
++
++		dsb();
++	}
++}
++
++/**
++ * Restore reg_region->buf to (reg_region->start ~ reg_region->end) reversely.
++ * @rgns - struct reg_region array.
++ * @rgn_num - struct reg_region array length.
++ */
++void rockchip_reg_rgn_restore_reverse(struct reg_region *rgns, uint32_t rgn_num)
++{
++	struct reg_region *r;
++	uint32_t addr;
++	int i, j;
++
++	assert(rgns && rgn_num);
++
++	for (i = rgn_num - 1; i >= 0; i--) {
++		r = &rgns[i];
++		j = RGN_LEN(r) - 1;
++		for (addr = r->end; addr >= r->start; addr -= r->stride, j--)
++			mmio_write_32(addr, r->buf[j] | r->wmsk);
++
++		dsb();
++	}
++}
++
++static void rockchip_print_hex(uint32_t val)
++{
++	int i;
++	unsigned char tmp;
++
++	putchar('0');
++	putchar('x');
++	for (i = 0; i < 8; val <<= 4, ++i) {
++		tmp = (val & 0xf0000000) >> 28;
++		if (tmp < 10)
++			putchar('0' + tmp);
++		else
++			putchar('a' + tmp - 10);
++	}
++}
++
++/**
++ * Dump registers (base + start_offset ~ base + end_offset)
++ * @base - the base addr of the register.
++ * @start_offset - the start offset to dump.
++ * @end_offset - the end offset to dump.
++ * @stride - the stride of the registers.
++ */
++void rockchip_regs_dump(uint32_t base,
++			uint32_t start_offset,
++			uint32_t end_offset,
++			uint32_t stride)
++{
++	uint32_t i;
++
++	for (i = start_offset; i <= end_offset; i += stride) {
++		if ((i - start_offset) % 16 == 0) {
++			putchar('\n');
++			rockchip_print_hex(base + i);
++			putchar(':');
++			putchar(' ');
++			putchar(' ');
++			putchar(' ');
++			putchar(' ');
++		}
++		rockchip_print_hex(mmio_read_32(base + i));
++		putchar(' ');
++		putchar(' ');
++		putchar(' ');
++		putchar(' ');
++	}
++	putchar('\n');
++}
++
++/**
++ * Dump reg regions
++ * @rgns - struct reg_region array.
++ * @rgn_num - struct reg_region array length.
++ */
++void rockchip_dump_reg_rgns(struct reg_region *rgns, uint32_t rgn_num)
++{
++	struct reg_region *r;
++	int i;
++
++	assert(rgns && rgn_num);
++
++	for (i = 0; i < rgn_num; i++) {
++		r = &rgns[i];
++		rockchip_regs_dump(0x0, r->start, r->end, r->stride);
++	}
++}
+diff --git a/plat/rockchip/rk3588/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3588/drivers/pmu/plat_pmu_macros.S
+new file mode 100644
+index 000000000..c27889977
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/pmu/plat_pmu_macros.S
+@@ -0,0 +1,21 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <arch.h>
++#include <asm_macros.S>
++#include <platform_def.h>
++
++.globl	clst_warmboot_data
++
++.macro	func_rockchip_clst_warmboot
++.endm
++
++.macro rockchip_clst_warmboot_data
++clst_warmboot_data:
++	.rept	PLATFORM_CLUSTER_COUNT
++	.word	0
++	.endr
++.endm
+diff --git a/plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.c b/plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.c
+new file mode 100644
+index 000000000..78e85004e
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.c
+@@ -0,0 +1,555 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <arch_helpers.h>
++#include <bl31/bl31.h>
++#include <common/debug.h>
++#include <drivers/console.h>
++#include <drivers/delay_timer.h>
++#include <lib/mmio.h>
++#include <platform.h>
++#include <platform_def.h>
++#include <pmu.h>
++
++#include <plat_pm_helpers.h>
++#include <plat_private.h>
++#include <pm_pd_regs.h>
++#include <soc.h>
++
++#define WMSK_VAL		0xffff0000
++
++static struct reg_region qos_reg_rgns[] = {
++	[QOS_ISP0_MWO] = REG_REGION(0x08, 0x18, 4, 0xfdf40500, 0),
++	[QOS_ISP0_MRO] = REG_REGION(0x08, 0x18, 4, 0xfdf40400, 0),
++	[QOS_ISP1_MWO] = REG_REGION(0x08, 0x18, 4, 0xfdf41000, 0),
++	[QOS_ISP1_MRO] = REG_REGION(0x08, 0x18, 4, 0xfdf41100, 0),
++	[QOS_VICAP_M0] = REG_REGION(0x08, 0x18, 4, 0xfdf40600, 0),
++	[QOS_VICAP_M1] = REG_REGION(0x08, 0x18, 4, 0xfdf40800, 0),
++	[QOS_FISHEYE0] = REG_REGION(0x08, 0x18, 4, 0xfdf40000, 0),
++	[QOS_FISHEYE1] = REG_REGION(0x08, 0x18, 4, 0xfdf40200, 0),
++	[QOS_VOP_M0] = REG_REGION(0x08, 0x18, 4, 0xfdf82000, 0),
++	[QOS_VOP_M1] = REG_REGION(0x08, 0x18, 4, 0xfdf82200, 0),
++	[QOS_RKVDEC0] = REG_REGION(0x08, 0x18, 4, 0xfdf62000, 0),
++	[QOS_RKVDEC1] = REG_REGION(0x08, 0x18, 4, 0xfdf63000, 0),
++	[QOS_AV1] = REG_REGION(0x08, 0x18, 4, 0xfdf64000, 0),
++	[QOS_RKVENC0_M0RO] = REG_REGION(0x08, 0x18, 4, 0xfdf60000, 0),
++	[QOS_RKVENC0_M1RO] = REG_REGION(0x08, 0x18, 4, 0xfdf60200, 0),
++	[QOS_RKVENC0_M2WO] = REG_REGION(0x08, 0x18, 4, 0xfdf60400, 0),
++	[QOS_RKVENC1_M0RO] = REG_REGION(0x08, 0x18, 4, 0xfdf61000, 0),
++	[QOS_RKVENC1_M1RO] = REG_REGION(0x08, 0x18, 4, 0xfdf61200, 0),
++	[QOS_RKVENC1_M2WO] = REG_REGION(0x08, 0x18, 4, 0xfdf61400, 0),
++	[QOS_DSU_M0] = REG_REGION(0x08, 0x18, 4, 0xfe008000, 0),
++	[QOS_DSU_M1] = REG_REGION(0x08, 0x18, 4, 0xfe008800, 0),
++	[QOS_DSU_MP] = REG_REGION(0x08, 0x18, 4, 0xfdf34200, 0),
++	[QOS_DEBUG] = REG_REGION(0x08, 0x18, 4, 0xfdf34400, 0),
++	[QOS_GPU_M0] = REG_REGION(0x08, 0x18, 4, 0xfdf35000, 0),
++	[QOS_GPU_M1] = REG_REGION(0x08, 0x18, 4, 0xfdf35200, 0),
++	[QOS_GPU_M2] = REG_REGION(0x08, 0x18, 4, 0xfdf35400, 0),
++	[QOS_GPU_M3] = REG_REGION(0x08, 0x18, 4, 0xfdf35600, 0),
++	[QOS_NPU1] = REG_REGION(0x08, 0x18, 4, 0xfdf70000, 0),
++	[QOS_NPU0_MRO] = REG_REGION(0x08, 0x18, 4, 0xfdf72200, 0),
++	[QOS_NPU2] = REG_REGION(0x08, 0x18, 4, 0xfdf71000, 0),
++	[QOS_NPU0_MWR] = REG_REGION(0x08, 0x18, 4, 0xfdf72000, 0),
++	[QOS_MCU_NPU] = REG_REGION(0x08, 0x18, 4, 0xfdf72400, 0),
++	[QOS_JPEG_DEC] = REG_REGION(0x08, 0x18, 4, 0xfdf66200, 0),
++	[QOS_JPEG_ENC0] = REG_REGION(0x08, 0x18, 4, 0xfdf66400, 0),
++	[QOS_JPEG_ENC1] = REG_REGION(0x08, 0x18, 4, 0xfdf66600, 0),
++	[QOS_JPEG_ENC2] = REG_REGION(0x08, 0x18, 4, 0xfdf66800, 0),
++	[QOS_JPEG_ENC3] = REG_REGION(0x08, 0x18, 4, 0xfdf66a00, 0),
++	[QOS_RGA2_MRO] = REG_REGION(0x08, 0x18, 4, 0xfdf66c00, 0),
++	[QOS_RGA2_MWO] = REG_REGION(0x08, 0x18, 4, 0xfdf66e00, 0),
++	[QOS_RGA3_0] = REG_REGION(0x08, 0x18, 4, 0xfdf67000, 0),
++	[QOS_RGA3_1] = REG_REGION(0x08, 0x18, 4, 0xfdf36000, 0),
++	[QOS_VDPU] = REG_REGION(0x08, 0x18, 4, 0xfdf67200, 0),
++	[QOS_IEP] = REG_REGION(0x08, 0x18, 4, 0xfdf66000, 0),
++	[QOS_HDCP0] = REG_REGION(0x08, 0x18, 4, 0xfdf80000, 0),
++	[QOS_HDCP1] = REG_REGION(0x08, 0x18, 4, 0xfdf81000, 0),
++	[QOS_HDMIRX] = REG_REGION(0x08, 0x18, 4, 0xfdf81200, 0),
++	[QOS_GIC600_M0] = REG_REGION(0x08, 0x18, 4, 0xfdf3a000, 0),
++	[QOS_GIC600_M1] = REG_REGION(0x08, 0x18, 4, 0xfdf3a200, 0),
++	[QOS_MMU600PCIE_TCU] = REG_REGION(0x08, 0x18, 4, 0xfdf3a400, 0),
++	[QOS_MMU600PHP_TBU] = REG_REGION(0x08, 0x18, 4, 0xfdf3a600, 0),
++	[QOS_MMU600PHP_TCU] = REG_REGION(0x08, 0x18, 4, 0xfdf3a800, 0),
++	[QOS_USB3_0] = REG_REGION(0x08, 0x18, 4, 0xfdf3e200, 0),
++	[QOS_USB3_1] = REG_REGION(0x08, 0x18, 4, 0xfdf3e000, 0),
++	[QOS_USBHOST_0] = REG_REGION(0x08, 0x18, 4, 0xfdf3e400, 0),
++	[QOS_USBHOST_1] = REG_REGION(0x08, 0x18, 4, 0xfdf3e600, 0),
++	[QOS_EMMC] = REG_REGION(0x08, 0x18, 4, 0xfdf38200, 0),
++	[QOS_FSPI] = REG_REGION(0x08, 0x18, 4, 0xfdf38000, 0),
++	[QOS_SDIO] = REG_REGION(0x08, 0x18, 4, 0xfdf39000, 0),
++	[QOS_DECOM] = REG_REGION(0x08, 0x18, 4, 0xfdf32000, 0),
++	[QOS_DMAC0] = REG_REGION(0x08, 0x18, 4, 0xfdf32200, 0),
++	[QOS_DMAC1] = REG_REGION(0x08, 0x18, 4, 0xfdf32400, 0),
++	[QOS_DMAC2] = REG_REGION(0x08, 0x18, 4, 0xfdf32600, 0),
++	[QOS_GIC600M] = REG_REGION(0x08, 0x18, 4, 0xfdf32800, 0),
++	[QOS_DMA2DDR] = REG_REGION(0x08, 0x18, 4, 0xfdf52000, 0),
++	[QOS_MCU_DDR] = REG_REGION(0x08, 0x18, 4, 0xfdf52200, 0),
++	[QOS_VAD] = REG_REGION(0x08, 0x18, 4, 0xfdf3b200, 0),
++	[QOS_MCU_PMU] = REG_REGION(0x08, 0x18, 4, 0xfdf3b000, 0),
++	[QOS_CRYPTOS] = REG_REGION(0x08, 0x18, 4, 0xfdf3d200, 0),
++	[QOS_CRYPTONS] = REG_REGION(0x08, 0x18, 4, 0xfdf3d000, 0),
++	[QOS_DCF] = REG_REGION(0x08, 0x18, 4, 0xfdf3d400, 0),
++	[QOS_SDMMC] = REG_REGION(0x08, 0x18, 4, 0xfdf3d800, 0),
++};
++
++static struct reg_region pd_crypto_reg_rgns[] = {
++	/* SECURE CRU */
++	REG_REGION(0x300, 0x30c, 4, SCRU_BASE, WMSK_VAL),
++	REG_REGION(0x800, 0x80c, 4, SCRU_BASE, WMSK_VAL),
++	REG_REGION(0xa00, 0xa0c, 4, SCRU_BASE, WMSK_VAL),
++	REG_REGION(0xd00, 0xd20, 8, SCRU_BASE, 0),
++	REG_REGION(0xd04, 0xd24, 8, SCRU_BASE, WMSK_VAL),
++
++	/* S TIMER0 6 channel */
++	REG_REGION(0x00, 0x04, 4, STIMER0_BASE + 0x00, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER0_BASE + 0x00, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER0_BASE + 0x20, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER0_BASE + 0x20, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER0_BASE + 0x40, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER0_BASE + 0x40, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER0_BASE + 0x60, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER0_BASE + 0x60, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER0_BASE + 0x80, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER0_BASE + 0x80, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER0_BASE + 0xa0, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER0_BASE + 0xa0, 0),
++
++	/* S TIMER1 6 channel */
++	REG_REGION(0x00, 0x04, 4, STIMER1_BASE + 0x00, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER1_BASE + 0x00, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER1_BASE + 0x20, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER1_BASE + 0x20, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER1_BASE + 0x40, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER1_BASE + 0x40, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER1_BASE + 0x60, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER1_BASE + 0x60, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER1_BASE + 0x80, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER1_BASE + 0x80, 0),
++	REG_REGION(0x00, 0x04, 4, STIMER1_BASE + 0xa0, 0),
++	REG_REGION(0x10, 0x10, 4, STIMER1_BASE + 0xa0, 0),
++
++	/* wdt_s */
++	REG_REGION(0x04, 0x04, 4, WDT_S_BASE, 0),
++	REG_REGION(0x00, 0x00, 4, WDT_S_BASE, 0),
++};
++
++static struct reg_region pd_dsu_reg_rgns[] = {
++	/* dsucru */
++	REG_REGION(0x040, 0x054, 4, DSUCRU_BASE, WMSK_VAL),
++	REG_REGION(0x300, 0x31c, 4, DSUCRU_BASE, WMSK_VAL),
++	REG_REGION(0x800, 0x80c, 4, DSUCRU_BASE, WMSK_VAL),
++	REG_REGION(0xa00, 0xa0c, 4, DSUCRU_BASE, WMSK_VAL),
++	REG_REGION(0xd00, 0xd20, 8, DSUCRU_BASE, 0),
++	REG_REGION(0xd04, 0xd24, 8, DSUCRU_BASE, WMSK_VAL),
++	REG_REGION(0xf00, 0xf00, 4, DSUCRU_BASE, WMSK_VAL),
++	REG_REGION(0xf10, 0xf1c, 4, DSUCRU_BASE, 0),
++
++	/* bcore0cru */
++	REG_REGION(0x000, 0x014, 4, BIGCORE0CRU_BASE, WMSK_VAL),
++	REG_REGION(0x300, 0x304, 4, BIGCORE0CRU_BASE, WMSK_VAL),
++	REG_REGION(0x800, 0x804, 4, BIGCORE0CRU_BASE, WMSK_VAL),
++	REG_REGION(0xa00, 0xa04, 4, BIGCORE0CRU_BASE, WMSK_VAL),
++	REG_REGION(0xcc0, 0xcc4, 4, BIGCORE0CRU_BASE, 0),
++	REG_REGION(0xd00, 0xd00, 4, BIGCORE0CRU_BASE, 0),
++	REG_REGION(0xd04, 0xd04, 4, BIGCORE0CRU_BASE, WMSK_VAL),
++
++	/* bcore1cru */
++	REG_REGION(0x020, 0x034, 4, BIGCORE1CRU_BASE, WMSK_VAL),
++	REG_REGION(0x300, 0x304, 4, BIGCORE1CRU_BASE, WMSK_VAL),
++	REG_REGION(0x800, 0x804, 4, BIGCORE1CRU_BASE, WMSK_VAL),
++	REG_REGION(0xa00, 0xa04, 4, BIGCORE1CRU_BASE, WMSK_VAL),
++	REG_REGION(0xcc0, 0xcc4, 4, BIGCORE1CRU_BASE, 0),
++	REG_REGION(0xd00, 0xd00, 4, BIGCORE1CRU_BASE, 0),
++	REG_REGION(0xd04, 0xd04, 4, BIGCORE1CRU_BASE, WMSK_VAL),
++
++	/* dsugrf */
++	REG_REGION(0x00, 0x18, 4, DSUGRF_BASE, WMSK_VAL),
++	REG_REGION(0x20, 0x20, 4, DSUGRF_BASE, WMSK_VAL),
++	REG_REGION(0x28, 0x30, 4, DSUGRF_BASE, WMSK_VAL),
++	REG_REGION(0x38, 0x38, 4, DSUGRF_BASE, WMSK_VAL),
++
++	/* lcore_grf */
++	REG_REGION(0x20, 0x20, 4, LITCOREGRF_BASE, WMSK_VAL),
++	REG_REGION(0x28, 0x30, 4, LITCOREGRF_BASE, WMSK_VAL),
++
++	/* bcore0_grf */
++	REG_REGION(0x20, 0x20, 4, BIGCORE0GRF_BASE, WMSK_VAL),
++	REG_REGION(0x28, 0x30, 4, BIGCORE0GRF_BASE, WMSK_VAL),
++
++	/* bcore1_grf */
++	REG_REGION(0x20, 0x20, 4, BIGCORE1GRF_BASE, WMSK_VAL),
++	REG_REGION(0x28, 0x28, 4, BIGCORE1GRF_BASE, WMSK_VAL),
++};
++
++static struct reg_region pd_php_reg_rgns[] = {
++	/* php_grf */
++	REG_REGION(0x000, 0x008, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x014, 0x024, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x028, 0x02c, 4, PHPGRF_BASE, 0),
++	REG_REGION(0x030, 0x03c, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x05c, 0x060, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x064, 0x068, 4, PHPGRF_BASE, 0),
++	REG_REGION(0x070, 0x070, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x074, 0x0d0, 4, PHPGRF_BASE, 0),
++	REG_REGION(0x0d4, 0x0d4, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x0e0, 0x0e0, 4, PHPGRF_BASE, 0),
++	REG_REGION(0x0e4, 0x0ec, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x100, 0x104, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x10c, 0x130, 4, PHPGRF_BASE, 0),
++	REG_REGION(0x138, 0x138, 4, PHPGRF_BASE, WMSK_VAL),
++	REG_REGION(0x144, 0x168, 4, PHPGRF_BASE, 0),
++	REG_REGION(0x16c, 0x174, 4, PHPGRF_BASE, WMSK_VAL),
++
++	/* php_cru */
++	REG_REGION(0x200, 0x218, 4, PHP_CRU_BASE, WMSK_VAL),
++	REG_REGION(0x800, 0x800, 4, PHP_CRU_BASE, WMSK_VAL),
++	REG_REGION(0xa00, 0xa00, 4, PHP_CRU_BASE, WMSK_VAL),
++
++	/* pcie3phy_grf_cmn_con0 */
++	REG_REGION(0x00, 0x00, 4, PCIE3PHYGRF_BASE, WMSK_VAL),
++};
++
++void qos_save(void)
++{
++	uint32_t pmu_pd_st0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST(0));
++
++	if ((pmu_pd_st0 & BIT(PD_GPU)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_GPU_M0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_GPU_M1], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_GPU_M2], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_GPU_M3], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_NPU1)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_NPU1], 1);
++	if ((pmu_pd_st0 & BIT(PD_NPU2)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_NPU2], 1);
++	if ((pmu_pd_st0 & BIT(PD_NPUTOP)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_NPU0_MRO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_NPU0_MWR], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_MCU_NPU], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_RKVDEC1)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVDEC1], 1);
++	if ((pmu_pd_st0 & BIT(PD_RKVDEC0)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVDEC0], 1);
++
++	if ((pmu_pd_st0 & BIT(PD_VENC1)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVENC1_M0RO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVENC1_M1RO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVENC1_M2WO], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_VENC0)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVENC0_M0RO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVENC0_M1RO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RKVENC0_M2WO], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_RGA30)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RGA3_0], 1);
++	if ((pmu_pd_st0 & BIT(PD_AV1)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_AV1], 1);
++	if ((pmu_pd_st0 & BIT(PD_VDPU)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_JPEG_DEC], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_JPEG_ENC0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_JPEG_ENC1], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_JPEG_ENC2], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_JPEG_ENC3], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RGA2_MRO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RGA2_MWO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_VDPU], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_IEP], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_VO0)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_HDCP0], 1);
++	if ((pmu_pd_st0 & BIT(PD_VO1)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_HDCP1], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_HDMIRX], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_VOP)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_VOP_M0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_VOP_M1], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_FEC)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_FISHEYE0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_FISHEYE1], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_ISP1)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_ISP1_MWO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_ISP1_MRO], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_VI)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_ISP0_MWO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_ISP0_MRO], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_VICAP_M0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_VICAP_M1], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_RGA31)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_RGA3_1], 1);
++
++	if ((pmu_pd_st0 & BIT(PD_USB)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_USB3_0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_USB3_1], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_USBHOST_0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_USBHOST_1], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_PHP)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_GIC600_M0], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_GIC600_M1], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_MMU600PCIE_TCU], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_MMU600PHP_TBU], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_MMU600PHP_TCU], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_SDIO)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_SDIO], 1);
++	if ((pmu_pd_st0 & BIT(PD_NVM0)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_FSPI], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_EMMC], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_SDMMC)) == 0)
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_SDMMC], 1);
++
++	if ((pmu_pd_st0 & BIT(PD_CRYPTO)) == 0) {
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_CRYPTONS], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_CRYPTOS], 1);
++		rockchip_reg_rgn_save(&qos_reg_rgns[QOS_DCF], 1);
++	}
++
++	/* PD_DSU */
++	rockchip_reg_rgn_save(&qos_reg_rgns[QOS_DSU_M0], 1);
++	rockchip_reg_rgn_save(&qos_reg_rgns[QOS_DSU_M1], 1);
++	rockchip_reg_rgn_save(&qos_reg_rgns[QOS_DSU_MP], 1);
++	rockchip_reg_rgn_save(&qos_reg_rgns[QOS_DEBUG], 1);
++}
++
++void qos_restore(void)
++{
++	uint32_t pmu_pd_st0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST(0));
++
++	if ((pmu_pd_st0 & BIT(PD_GPU)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_GPU_M0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_GPU_M1], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_GPU_M2], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_GPU_M3], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_NPU1)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_NPU1], 1);
++	if ((pmu_pd_st0 & BIT(PD_NPU2)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_NPU2], 1);
++	if ((pmu_pd_st0 & BIT(PD_NPUTOP)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_NPU0_MRO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_NPU0_MWR], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_MCU_NPU], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_RKVDEC1)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVDEC1], 1);
++	if ((pmu_pd_st0 & BIT(PD_RKVDEC0)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVDEC0], 1);
++
++	if ((pmu_pd_st0 & BIT(PD_VENC1)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVENC1_M0RO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVENC1_M1RO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVENC1_M2WO], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_VENC0)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVENC0_M0RO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVENC0_M1RO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RKVENC0_M2WO], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_RGA30)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RGA3_0], 1);
++	if ((pmu_pd_st0 & BIT(PD_AV1)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_AV1], 1);
++	if ((pmu_pd_st0 & BIT(PD_VDPU)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_JPEG_DEC], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_JPEG_ENC0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_JPEG_ENC1], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_JPEG_ENC2], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_JPEG_ENC3], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RGA2_MRO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RGA2_MWO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_VDPU], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_IEP], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_VO0)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_HDCP0], 1);
++	if ((pmu_pd_st0 & BIT(PD_VO1)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_HDCP1], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_HDMIRX], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_VOP)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_VOP_M0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_VOP_M1], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_FEC)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_FISHEYE0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_FISHEYE1], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_ISP1)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_ISP1_MWO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_ISP1_MRO], 1);
++	}
++	if ((pmu_pd_st0 & BIT(PD_VI)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_ISP0_MWO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_ISP0_MRO], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_VICAP_M0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_VICAP_M1], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_RGA31)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_RGA3_1], 1);
++
++	if ((pmu_pd_st0 & BIT(PD_USB)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_USB3_0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_USB3_1], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_USBHOST_0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_USBHOST_1], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_PHP)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_GIC600_M0], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_GIC600_M1], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_MMU600PCIE_TCU], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_MMU600PHP_TBU], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_MMU600PHP_TCU], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_SDIO)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_SDIO], 1);
++	if ((pmu_pd_st0 & BIT(PD_NVM0)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_FSPI], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_EMMC], 1);
++	}
++
++	if ((pmu_pd_st0 & BIT(PD_SDMMC)) == 0)
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_SDMMC], 1);
++
++	if ((pmu_pd_st0 & BIT(PD_CRYPTO)) == 0) {
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_CRYPTONS], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_CRYPTOS], 1);
++		rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_DCF], 1);
++	}
++
++	/* PD_DSU */
++	rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_DSU_M0], 1);
++	rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_DSU_M1], 1);
++	rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_DSU_MP], 1);
++	rockchip_reg_rgn_restore(&qos_reg_rgns[QOS_DEBUG], 1);
++}
++
++void pd_crypto_save(void)
++{
++	rockchip_reg_rgn_save(pd_crypto_reg_rgns, ARRAY_SIZE(pd_crypto_reg_rgns));
++}
++
++void pd_crypto_restore(void)
++{
++	rockchip_reg_rgn_restore(pd_crypto_reg_rgns, ARRAY_SIZE(pd_crypto_reg_rgns));
++}
++
++static uint32_t b0_cru_mode;
++static uint32_t b1_cru_mode;
++static uint32_t dsu_cru_mode;
++static uint32_t bcore0_cru_sel_con2, bcore1_cru_sel_con2;
++
++void pd_dsu_core_save(void)
++{
++	b0_cru_mode = mmio_read_32(BIGCORE0CRU_BASE + 0x280);
++	b1_cru_mode = mmio_read_32(BIGCORE1CRU_BASE + 0x280);
++	dsu_cru_mode = mmio_read_32(DSUCRU_BASE + 0x280);
++	bcore0_cru_sel_con2 = mmio_read_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(2));
++	bcore1_cru_sel_con2 = mmio_read_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(2));
++
++	rockchip_reg_rgn_save(pd_dsu_reg_rgns, ARRAY_SIZE(pd_dsu_reg_rgns));
++}
++
++void pd_dsu_core_restore(void)
++{
++	/* switch bcore0/1 pclk root to 24M */
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(2),
++		      BITS_WITH_WMASK(2, 0x3, 0));
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(2),
++		      BITS_WITH_WMASK(2, 0x3, 0));
++
++	/* slow mode */
++	mmio_write_32(BIGCORE0CRU_BASE + 0x280, 0x00030000);
++	mmio_write_32(BIGCORE1CRU_BASE + 0x280, 0x00030000);
++	mmio_write_32(DSUCRU_BASE + 0x280, 0x00030000);
++
++	rockchip_reg_rgn_restore(pd_dsu_reg_rgns, ARRAY_SIZE(pd_dsu_reg_rgns));
++
++	/* trigger dsu/lcore/bcore mem_cfg */
++	mmio_write_32(DSUGRF_BASE + 0x18, BITS_WITH_WMASK(1, 0x1, 14));
++	mmio_write_32(LITCOREGRF_BASE + 0x30, BITS_WITH_WMASK(1, 0x1, 5));
++	mmio_write_32(BIGCORE0GRF_BASE + 0x30, BITS_WITH_WMASK(1, 0x1, 5));
++	mmio_write_32(BIGCORE1GRF_BASE + 0x30, BITS_WITH_WMASK(1, 0x1, 5));
++	udelay(1);
++	mmio_write_32(DSUGRF_BASE + 0x18, BITS_WITH_WMASK(0, 0x1, 14));
++	mmio_write_32(LITCOREGRF_BASE + 0x30, BITS_WITH_WMASK(0, 0x1, 5));
++	mmio_write_32(BIGCORE0GRF_BASE + 0x30, BITS_WITH_WMASK(0, 0x1, 5));
++	mmio_write_32(BIGCORE1GRF_BASE + 0x30, BITS_WITH_WMASK(0, 0x1, 5));
++
++	/* wait lock */
++	pm_pll_wait_lock(BIGCORE0CRU_BASE + 0x00);
++	pm_pll_wait_lock(BIGCORE1CRU_BASE + 0x20);
++	pm_pll_wait_lock(DSUCRU_BASE + 0x40);
++
++	/* restore mode */
++	mmio_write_32(BIGCORE0CRU_BASE + 0x280, WITH_16BITS_WMSK(b0_cru_mode));
++	mmio_write_32(BIGCORE1CRU_BASE + 0x280, WITH_16BITS_WMSK(b1_cru_mode));
++	mmio_write_32(DSUCRU_BASE + 0x280, WITH_16BITS_WMSK(dsu_cru_mode));
++
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(2),
++		      WITH_16BITS_WMSK(bcore0_cru_sel_con2));
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(2),
++		      WITH_16BITS_WMSK(bcore1_cru_sel_con2));
++}
++
++static uint32_t php_ppll_con0;
++
++void pd_php_save(void)
++{
++	php_ppll_con0 = mmio_read_32(PHP_CRU_BASE + 0x200);
++
++	/* php_ppll bypass */
++	mmio_write_32(PHP_CRU_BASE + 0x200, BITS_WITH_WMASK(1u, 1u, 15));
++	dsb();
++	isb();
++	rockchip_reg_rgn_save(pd_php_reg_rgns, ARRAY_SIZE(pd_php_reg_rgns));
++}
++
++void pd_php_restore(void)
++{
++	rockchip_reg_rgn_restore(pd_php_reg_rgns, ARRAY_SIZE(pd_php_reg_rgns));
++
++	pm_pll_wait_lock(PHP_CRU_BASE + 0x200);
++
++	/* restore php_ppll bypass */
++	mmio_write_32(PHP_CRU_BASE + 0x200, WITH_16BITS_WMSK(php_ppll_con0));
++}
++
++void pm_reg_rgns_init(void)
++{
++	rockchip_alloc_region_mem(qos_reg_rgns, ARRAY_SIZE(qos_reg_rgns));
++	rockchip_alloc_region_mem(pd_crypto_reg_rgns, ARRAY_SIZE(pd_crypto_reg_rgns));
++	rockchip_alloc_region_mem(pd_dsu_reg_rgns, ARRAY_SIZE(pd_dsu_reg_rgns));
++	rockchip_alloc_region_mem(pd_php_reg_rgns, ARRAY_SIZE(pd_php_reg_rgns));
++}
+diff --git a/plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.h b/plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.h
+new file mode 100644
+index 000000000..8baf69a78
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/pmu/pm_pd_regs.h
+@@ -0,0 +1,23 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef PM_PD_REGS_H
++#define PM_PD_REGS_H
++
++#include <stdint.h>
++
++void qos_save(void);
++void qos_restore(void);
++void pd_crypto_save(void);
++void pd_crypto_restore(void);
++void pd_dsu_core_save(void);
++void pd_dsu_core_restore(void);
++void pd_php_save(void);
++void pd_php_restore(void);
++
++void pm_reg_rgns_init(void);
++
++#endif
+diff --git a/plat/rockchip/rk3588/drivers/pmu/pmu.c b/plat/rockchip/rk3588/drivers/pmu/pmu.c
+new file mode 100644
+index 000000000..445cf8d97
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/pmu/pmu.c
+@@ -0,0 +1,1436 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <arch_helpers.h>
++#include <bl31/bl31.h>
++#include <common/debug.h>
++#include <drivers/arm/gicv3.h>
++#include <drivers/console.h>
++#include <drivers/delay_timer.h>
++#include <drivers/ti/uart/uart_16550.h>
++#include <lib/mmio.h>
++#include <plat/common/platform.h>
++#include <platform_def.h>
++#include <pmu.h>
++
++#include <cpus_on_fixed_addr.h>
++#include <plat_pm_helpers.h>
++#include <plat_private.h>
++#include <pm_pd_regs.h>
++#include <rockchip_sip_svc.h>
++#include <secure.h>
++#include <soc.h>
++
++#define PSRAM_SP_TOP	((PMUSRAM_BASE + PMUSRAM_RSIZE) & ~0xf)
++#define NONBOOT_CPUS_OFF_LOOP (500000)
++
++#define DSUGRF_REG_CNT			(0x78 / 4 + 1)
++#define BCORE_GRF_REG_CNT		(0x30 / 4 + 1)
++#define LCORE_GRF_REG_CNT		(0x30 / 4 + 1)
++
++#define CENTER_GRF_REG_CNT		(0x20 / 4 + 1)
++
++static struct psram_data_t *psram_sleep_cfg =
++	(struct psram_data_t *)&sys_sleep_flag_sram;
++
++static int8_t pd_repair_map[] = {
++	[PD_GPU] = PD_RPR_GPU,
++	[PD_NPU] = -1,
++	[PD_VCODEC] = -1,
++	[PD_NPUTOP] = PD_RPR_NPUTOP,
++	[PD_NPU1] = PD_RPR_NPU1,
++	[PD_NPU2] = PD_RPR_NPU2,
++	[PD_VENC0] = PD_RPR_VENC0,
++	[PD_VENC1] = PD_RPR_VENC1,
++	[PD_RKVDEC0] = PD_RPR_RKVDEC0,
++	[PD_RKVDEC1] = PD_RPR_RKVDEC1,
++	[PD_VDPU] = PD_RPR_VDPU,
++	[PD_RGA30] = PD_RPR_RGA30,
++	[PD_AV1] = PD_RPR_AV1,
++	[PD_VI] = PD_RPR_VI,
++	[PD_FEC] = PD_RPR_FEC,
++	[PD_ISP1] = PD_RPR_ISP1,
++	[PD_RGA31] = PD_RPR_RGA31,
++	[PD_VOP] = PD_RPR_VOP,
++	[PD_VO0] = PD_RPR_VO0,
++	[PD_VO1] = PD_RPR_VO1,
++	[PD_AUDIO] = PD_RPR_AUDIO,
++	[PD_PHP] = PD_RPR_PHP,
++	[PD_GMAC] = PD_RPR_GMAC,
++	[PD_PCIE] = PD_RPR_PCIE,
++	[PD_NVM] = -1,
++	[PD_NVM0] = PD_RPR_NVM0,
++	[PD_SDIO] = PD_RPR_SDIO,
++	[PD_USB] = PD_RPR_USB,
++	[PD_SECURE] = -1,
++	[PD_SDMMC] = PD_RPR_SDMMC,
++	[PD_CRYPTO] = PD_RPR_CRYPTO,
++	[PD_CENTER] = PD_RPR_CENTER,
++	[PD_DDR01] = PD_RPR_DDR01,
++	[PD_DDR23] = PD_RPR_DDR23,
++};
++
++struct rk3588_sleep_ddr_data {
++	uint32_t gpio0a_iomux_l, gpio0a_iomux_h, gpio0b_iomux_l;
++	uint32_t pmu_pd_st0, bus_idle_st0, qch_pwr_st;
++	uint32_t pmu2_vol_gate_con[3], pmu2_submem_gate_sft_con0;
++	uint32_t pmu2_bisr_con0;
++	uint32_t cpll_con0;
++	uint32_t cru_mode_con, busscru_mode_con;
++	uint32_t bussgrf_soc_con7;
++	uint32_t pmu0grf_soc_con0, pmu0grf_soc_con1, pmu0grf_soc_con3;
++	uint32_t pmu1grf_soc_con2, pmu1grf_soc_con7, pmu1grf_soc_con8, pmu1grf_soc_con9;
++	uint32_t pmu0sgrf_soc_con1;
++	uint32_t pmu1sgrf_soc_con14;
++	uint32_t ddrgrf_chn_con0[4], ddrgrf_chn_con1[4],
++		ddrgrf_chn_con2[4], pmu1_ddr_pwr_sft_con[4];
++	uint32_t pmu1cru_clksel_con1;
++};
++
++static struct rk3588_sleep_ddr_data ddr_data;
++
++struct rk3588_sleep_pmusram_data {
++	uint32_t dsusgrf_soc_con[DSUSGRF_SOC_CON_CNT],
++		dsusgrf_ddr_hash_con[DSUSGRF_DDR_HASH_CON_CNT];
++	uint32_t dsu_ddr_fw_rgn_reg[FIREWALL_DSU_RGN_CNT],
++		dsu_ddr_fw_mst_reg[FIREWALL_DSU_MST_CNT],
++		dsu_ddr_fw_con_reg[FIREWALL_DSU_CON_CNT];
++	uint32_t busioc_gpio0b_iomux_h;
++};
++
++static __pmusramdata struct rk3588_sleep_pmusram_data pmusram_data;
++
++static __pmusramfunc void dsu_restore_early(void)
++{
++	int i;
++
++	/* dsusgrf */
++	for (i = 0; i < DSUSGRF_SOC_CON_CNT; i++)
++		mmio_write_32(DSUSGRF_BASE + DSUSGRF_SOC_CON(i),
++			      WITH_16BITS_WMSK(pmusram_data.dsusgrf_soc_con[i]));
++
++	for (i = 0; i < DSUSGRF_DDR_HASH_CON_CNT; i++)
++		mmio_write_32(DSUSGRF_BASE + DSUSGRF_DDR_HASH_CON(i),
++			      pmusram_data.dsusgrf_ddr_hash_con[i]);
++
++	/* dsu ddr firewall */
++	for (i = 0; i < FIREWALL_DSU_RGN_CNT; i++)
++		mmio_write_32(FIREWALL_DSU_BASE + FIREWALL_DSU_RGN(i),
++			      pmusram_data.dsu_ddr_fw_rgn_reg[i]);
++
++	for (i = 0; i < FIREWALL_DSU_MST_CNT; i++)
++		mmio_write_32(FIREWALL_DSU_BASE + FIREWALL_DSU_MST(i),
++			      pmusram_data.dsu_ddr_fw_mst_reg[i]);
++
++	for (i = 0; i < FIREWALL_DSU_CON_CNT; i++)
++		mmio_write_32(FIREWALL_DSU_BASE + FIREWALL_DSU_CON(i),
++			      pmusram_data.dsu_ddr_fw_con_reg[i]);
++}
++
++static __pmusramfunc void ddr_resume(void)
++{
++	dsu_restore_early();
++}
++
++static void dsu_core_save(void)
++{
++	int i;
++
++	/* dsusgrf */
++	for (i = 0; i < DSUSGRF_SOC_CON_CNT; i++)
++		pmusram_data.dsusgrf_soc_con[i] =
++			mmio_read_32(DSUSGRF_BASE + DSUSGRF_SOC_CON(i));
++
++	for (i = 0; i < DSUSGRF_DDR_HASH_CON_CNT; i++)
++		pmusram_data.dsusgrf_ddr_hash_con[i] =
++			mmio_read_32(DSUSGRF_BASE + DSUSGRF_DDR_HASH_CON(i));
++
++	/* dsu ddr firewall */
++	for (i = 0; i < FIREWALL_DSU_RGN_CNT; i++)
++		pmusram_data.dsu_ddr_fw_rgn_reg[i] =
++			mmio_read_32(FIREWALL_DSU_BASE + FIREWALL_DSU_RGN(i));
++
++	for (i = 0; i < FIREWALL_DSU_MST_CNT; i++)
++		pmusram_data.dsu_ddr_fw_mst_reg[i] =
++			mmio_read_32(FIREWALL_DSU_BASE + FIREWALL_DSU_MST(i));
++
++	for (i = 0; i < FIREWALL_DSU_CON_CNT; i++)
++		pmusram_data.dsu_ddr_fw_con_reg[i] =
++			mmio_read_32(FIREWALL_DSU_BASE + FIREWALL_DSU_CON(i));
++
++	pd_dsu_core_save();
++}
++
++static void dsu_core_restore(void)
++{
++	pd_dsu_core_restore();
++}
++
++static uint32_t clk_save[CRU_CLKGATE_CON_CNT + PHPCRU_CLKGATE_CON_CNT +
++			 SECURECRU_CLKGATE_CON_CNT + PMU1CRU_CLKGATE_CON_CNT];
++
++void clk_gate_con_save(void)
++{
++	int i, j = 0;
++
++	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
++		clk_save[j] = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i));
++
++	clk_save[j] = mmio_read_32(PHP_CRU_BASE + PHPCRU_CLKGATE_CON);
++
++	for (i = 0; i < SECURECRU_CLKGATE_CON_CNT; i++, j++)
++		clk_save[j] = mmio_read_32(SCRU_BASE + SECURECRU_CLKGATE_CON(i));
++
++	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
++		clk_save[j] = mmio_read_32(PMU1CRU_BASE + CRU_CLKGATE_CON(i));
++}
++
++void clk_gate_con_disable(void)
++{
++	int i;
++
++	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++)
++		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), 0xffff0000);
++
++	 mmio_write_32(PHP_CRU_BASE + PHPCRU_CLKGATE_CON, 0xffff0000);
++
++	for (i = 0; i < SECURECRU_CLKGATE_CON_CNT; i++)
++		mmio_write_32(SCRU_BASE + SECURECRU_CLKGATE_CON(i), 0xffff0000);
++
++	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++)
++		mmio_write_32(PMU1CRU_BASE + CRU_CLKGATE_CON(i), 0xffff0000);
++}
++
++void clk_gate_con_restore(void)
++{
++	int i, j = 0;
++
++	for (i = 0; i < CRU_CLKGATE_CON_CNT; i++, j++)
++		mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i),
++			      WITH_16BITS_WMSK(clk_save[j]));
++
++	mmio_write_32(PHP_CRU_BASE + PHPCRU_CLKGATE_CON,
++		      WITH_16BITS_WMSK(clk_save[j]));
++
++	for (i = 0; i < SECURECRU_CLKGATE_CON_CNT; i++, j++)
++		mmio_write_32(SCRU_BASE + SECURECRU_CLKGATE_CON(i),
++			      WITH_16BITS_WMSK(clk_save[j]));
++
++	for (i = 0; i < PMU1CRU_CLKGATE_CON_CNT; i++, j++)
++		mmio_write_32(PMU1CRU_BASE + CRU_CLKGATE_CON(i),
++			      WITH_16BITS_WMSK(clk_save[j]));
++}
++
++static void pmu_bus_idle_req(uint32_t bus, uint32_t state)
++{
++	uint32_t wait_cnt = 0;
++
++	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_SFTCON(bus / 16),
++		      BITS_WITH_WMASK(state, 0x1, bus % 16));
++
++	while (pmu_bus_idle_st(bus) != state ||
++	       pmu_bus_idle_ack(bus) != state) {
++		if (++wait_cnt > BUS_IDLE_LOOP)
++			break;
++		udelay(1);
++	}
++
++	if (wait_cnt > BUS_IDLE_LOOP)
++		WARN("%s: can't  wait state %d for bus %d (0x%x)\n",
++		     __func__, state, bus,
++		     mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST(bus / 32)));
++}
++
++static void pmu_qch_pwr_ctlr(uint32_t msk, uint32_t state)
++{
++	uint32_t wait_cnt = 0;
++
++	if (state != 0)
++		state = msk;
++
++	mmio_write_32(PMU_BASE + PMU2_QCHANNEL_PWR_SFTCON,
++		      BITS_WITH_WMASK(state, msk, 0));
++
++	while ((mmio_read_32(PMU_BASE + PMU2_QCHANNEL_STATUS) & msk) != state) {
++		if (++wait_cnt > QCH_PWR_LOOP)
++			break;
++		udelay(1);
++	}
++
++	if (wait_cnt > BUS_IDLE_LOOP)
++		WARN("%s: can't wait qch:0x%x to state:0x%x (0x%x)\n",
++		     __func__, msk, state,
++		     mmio_read_32(PMU_BASE + PMU2_QCHANNEL_STATUS));
++}
++
++static inline uint32_t pmu_power_domain_chain_st(uint32_t pd)
++{
++	return mmio_read_32(PMU_BASE + PMU2_PWR_CHAIN1_ST(pd / 32)) & BIT(pd % 32) ?
++	       pmu_pd_on :
++	       pmu_pd_off;
++}
++
++static inline uint32_t pmu_power_domain_mem_st(uint32_t pd)
++{
++	return mmio_read_32(PMU_BASE + PMU2_PWR_MEM_ST(pd / 32)) & BIT(pd % 32) ?
++	       pmu_pd_off :
++	       pmu_pd_on;
++}
++
++static inline uint32_t pmu_power_domain_st(uint32_t pd)
++{
++	int8_t pd_repair = pd_repair_map[pd];
++
++	if (pd_repair >= 0)
++		return mmio_read_32(PMU_BASE + PMU2_BISR_STATUS(4)) & BIT(pd_repair) ?
++		       pmu_pd_on :
++		       pmu_pd_off;
++	else
++		return mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST(pd / 32)) & BIT(pd % 32) ?
++		       pmu_pd_off :
++		       pmu_pd_on;
++}
++
++static int pmu_power_domain_pd_to_mem_st(uint32_t pd, uint32_t *pd_mem_st)
++{
++	uint32_t mem_st;
++
++	switch (pd) {
++	case PD_NPUTOP:
++		mem_st = PD_NPU_TOP_MEM_ST;
++		break;
++	case PD_NPU1:
++		mem_st = PD_NPU1_MEM_ST;
++		break;
++	case PD_NPU2:
++		mem_st = PD_NPU2_MEM_ST;
++		break;
++	case PD_VENC0:
++		mem_st = PD_VENC0_MEM_ST;
++		break;
++	case PD_VENC1:
++		mem_st = PD_VENC1_MEM_ST;
++		break;
++	case PD_RKVDEC0:
++		mem_st = PD_RKVDEC0_MEM_ST;
++		break;
++	case PD_RKVDEC1:
++		mem_st = PD_RKVDEC1_MEM_ST;
++		break;
++	case PD_RGA30:
++		mem_st = PD_RGA30_MEM_ST;
++		break;
++	case PD_AV1:
++		mem_st = PD_AV1_MEM_ST;
++		break;
++	case PD_VI:
++		mem_st = PD_VI_MEM_ST;
++		break;
++	case PD_FEC:
++		mem_st = PD_FEC_MEM_ST;
++		break;
++	case PD_ISP1:
++		mem_st = PD_ISP1_MEM_ST;
++		break;
++	case PD_RGA31:
++		mem_st = PD_RGA31_MEM_ST;
++		break;
++	case PD_VOP:
++		mem_st = PD_VOP_MEM_ST;
++		break;
++	case PD_VO0:
++		mem_st = PD_VO0_MEM_ST;
++		break;
++	case PD_VO1:
++		mem_st = PD_VO1_MEM_ST;
++		break;
++	case PD_AUDIO:
++		mem_st = PD_AUDIO_MEM_ST;
++		break;
++	case PD_PHP:
++		mem_st = PD_PHP_MEM_ST;
++		break;
++	case PD_GMAC:
++		mem_st = PD_GMAC_MEM_ST;
++		break;
++	case PD_PCIE:
++		mem_st = PD_PCIE_MEM_ST;
++		break;
++	case PD_NVM0:
++		mem_st = PD_NVM0_MEM_ST;
++		break;
++	case PD_SDIO:
++		mem_st = PD_SDIO_MEM_ST;
++		break;
++	case PD_USB:
++		mem_st = PD_USB_MEM_ST;
++		break;
++	case PD_SDMMC:
++		mem_st = PD_SDMMC_MEM_ST;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	*pd_mem_st = mem_st;
++
++	return 0;
++}
++
++static int pmu_power_domain_reset_mem(uint32_t pd, uint32_t pd_mem_st)
++{
++	uint32_t loop = 0;
++	int ret = 0;
++
++	while (pmu_power_domain_chain_st(pd_mem_st) != pmu_pd_on) {
++		udelay(1);
++		loop++;
++		if (loop >= PD_CTR_LOOP) {
++			WARN("%s: %d chain up time out\n", __func__, pd);
++			ret = -EINVAL;
++			goto error;
++		}
++	}
++
++	udelay(60);
++
++	mmio_write_32(PMU_BASE + PMU2_MEMPWR_GATE_SFTCON(pd / 16),
++		      BITS_WITH_WMASK(pmu_pd_off, 0x1, pd % 16));
++	dsb();
++
++	loop = 0;
++	while (pmu_power_domain_mem_st(pd_mem_st) != pmu_pd_off) {
++		udelay(1);
++		loop++;
++		if (loop >= PD_CTR_LOOP) {
++			WARN("%s: %d mem down time out\n", __func__, pd);
++			ret = -EINVAL;
++			goto error;
++		}
++	}
++
++	mmio_write_32(PMU_BASE + PMU2_MEMPWR_GATE_SFTCON(pd / 16),
++		      BITS_WITH_WMASK(pmu_pd_on, 0x1, pd % 16));
++	dsb();
++
++	loop = 0;
++	while (pmu_power_domain_mem_st(pd_mem_st) != pmu_pd_on) {
++		udelay(1);
++		loop++;
++		if (loop >= PD_CTR_LOOP) {
++			WARN("%s: %d mem up time out\n", __func__, pd);
++			ret = -EINVAL;
++			goto error;
++		}
++	}
++
++	return 0;
++
++error:
++	return ret;
++}
++
++static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state)
++{
++	uint32_t loop = 0;
++	uint32_t is_mem_on = pmu_pd_off;
++	uint32_t pd_mem_st;
++	int ret = 0;
++
++	if (pd_state == pmu_pd_on) {
++		ret = pmu_power_domain_pd_to_mem_st(pd, &pd_mem_st);
++		if (ret == 0) {
++			is_mem_on = pmu_power_domain_mem_st(pd_mem_st);
++			if (is_mem_on == pmu_pd_on)
++				WARN("%s: %d mem is up\n", __func__, pd);
++		}
++	}
++
++	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_SFTCON(pd / 16),
++		      BITS_WITH_WMASK(pd_state, 0x1, pd % 16));
++	dsb();
++
++	if (is_mem_on == pmu_pd_on) {
++		ret = pmu_power_domain_reset_mem(pd, pd_mem_st);
++		if (ret != 0)
++			goto out;
++		WARN("%s: %d mem reset ok\n", __func__, pd);
++	}
++
++	while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) {
++		udelay(1);
++		loop++;
++	}
++
++	if (pmu_power_domain_st(pd) != pd_state) {
++		WARN("%s: %d, %d, (0x%x, 0x%x) error!\n", __func__, pd, pd_state,
++		     mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST(0)),
++		     mmio_read_32(PMU_BASE + PMU2_BISR_STATUS(4)));
++		ret = -EINVAL;
++	}
++
++out:
++	return ret;
++}
++
++static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state)
++{
++	uint32_t state;
++
++	if (pmu_power_domain_st(pd_id) == pd_state)
++		goto out;
++
++	if (pd_state == pmu_pd_on)
++		pmu_power_domain_ctr(pd_id, pd_state);
++
++	state = (pd_state == pmu_pd_off) ? bus_idle : bus_active;
++
++	switch (pd_id) {
++	case PD_GPU:
++		pmu_bus_idle_req(BUS_ID_GPU, state);
++		break;
++	case PD_NPUTOP:
++		pmu_bus_idle_req(BUS_ID_NPUTOP, state);
++		break;
++	case PD_NPU1:
++		pmu_bus_idle_req(BUS_ID_NPU1, state);
++		break;
++	case PD_NPU2:
++		pmu_bus_idle_req(BUS_ID_NPU2, state);
++		break;
++	case PD_VENC0:
++		pmu_bus_idle_req(BUS_ID_RKVENC0, state);
++		break;
++	case PD_VENC1:
++		pmu_bus_idle_req(BUS_ID_RKVENC1, state);
++		break;
++	case PD_RKVDEC0:
++		pmu_bus_idle_req(BUS_ID_RKVDEC0, state);
++		break;
++	case PD_RKVDEC1:
++		pmu_bus_idle_req(BUS_ID_RKVDEC1, state);
++		break;
++	case PD_VDPU:
++		pmu_bus_idle_req(BUS_ID_VDPU, state);
++		break;
++	case PD_AV1:
++		pmu_bus_idle_req(BUS_ID_AV1, state);
++		break;
++	case PD_VI:
++		pmu_bus_idle_req(BUS_ID_VI, state);
++		break;
++	case PD_ISP1:
++		pmu_bus_idle_req(BUS_ID_ISP, state);
++		break;
++	case PD_RGA31:
++		pmu_bus_idle_req(BUS_ID_RGA31, state);
++		break;
++	case PD_VOP:
++		pmu_bus_idle_req(BUS_ID_VOP_CHANNEL, state);
++		pmu_bus_idle_req(BUS_ID_VOP, state);
++		break;
++	case PD_VO0:
++		pmu_bus_idle_req(BUS_ID_VO0, state);
++		break;
++	case PD_VO1:
++		pmu_bus_idle_req(BUS_ID_VO1, state);
++		break;
++	case PD_AUDIO:
++		pmu_bus_idle_req(BUS_ID_AUDIO, state);
++		break;
++	case PD_PHP:
++		pmu_bus_idle_req(BUS_ID_PHP, state);
++		break;
++	case PD_NVM:
++		pmu_bus_idle_req(BUS_ID_NVM, state);
++		break;
++	case PD_SDIO:
++		pmu_bus_idle_req(BUS_ID_SDIO, state);
++		break;
++	case PD_USB:
++		pmu_bus_idle_req(BUS_ID_USB, state);
++		break;
++	case PD_SECURE:
++		pmu_bus_idle_req(BUS_ID_SECURE, state);
++		break;
++	default:
++		break;
++	}
++
++	if (pd_state == pmu_pd_off)
++		pmu_power_domain_ctr(pd_id, pd_state);
++
++out:
++	return 0;
++}
++
++static void pmu_power_domains_suspend(void)
++{
++	ddr_data.qch_pwr_st =
++		mmio_read_32(PMU_BASE + PMU2_QCHANNEL_STATUS) & PMU2_QCH_PWR_MSK;
++	ddr_data.pmu_pd_st0 = mmio_read_32(PMU_BASE + PMU2_PWR_GATE_ST(0));
++	ddr_data.bus_idle_st0 = mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST(0));
++
++	qos_save();
++
++	if ((ddr_data.pmu_pd_st0 & BIT(PD_PHP)) == 0)
++		pd_php_save();
++
++	if ((ddr_data.pmu_pd_st0 & BIT(PD_CRYPTO)) == 0)
++		pd_crypto_save();
++
++	pmu_qch_pwr_ctlr(0x20, 1);
++	pmu_qch_pwr_ctlr(0x40, 1);
++	pmu_qch_pwr_ctlr(0x1, 1);
++	pmu_qch_pwr_ctlr(0x2, 1);
++	pmu_qch_pwr_ctlr(0x4, 1);
++	pmu_qch_pwr_ctlr(0x8, 1);
++	pmu_qch_pwr_ctlr(0x10, 1);
++
++	pmu_bus_idle_req(BUS_ID_VO1USBTOP, bus_idle);
++	pmu_bus_idle_req(BUS_ID_SECURE_VO1USB_CHANNEL, bus_idle);
++
++	pmu_bus_idle_req(BUS_ID_USB, bus_idle);
++
++	pmu_set_power_domain(PD_GPU, pmu_pd_off);
++
++	pmu_set_power_domain(PD_NPU1, pmu_pd_off);
++	pmu_set_power_domain(PD_NPU2, pmu_pd_off);
++	pmu_set_power_domain(PD_NPUTOP, pmu_pd_off);
++	pmu_set_power_domain(PD_NPU, pmu_pd_off);
++
++	pmu_set_power_domain(PD_RKVDEC1, pmu_pd_off);
++	pmu_set_power_domain(PD_RKVDEC0, pmu_pd_off);
++	pmu_set_power_domain(PD_VENC1, pmu_pd_off);
++	pmu_set_power_domain(PD_VENC0, pmu_pd_off);
++	pmu_set_power_domain(PD_VCODEC, pmu_pd_off);
++
++	pmu_set_power_domain(PD_RGA30, pmu_pd_off);
++	pmu_set_power_domain(PD_AV1, pmu_pd_off);
++	pmu_set_power_domain(PD_VDPU, pmu_pd_off);
++
++	pmu_set_power_domain(PD_VO0, pmu_pd_off);
++	pmu_set_power_domain(PD_VO1, pmu_pd_off);
++	pmu_set_power_domain(PD_VOP, pmu_pd_off);
++
++	pmu_set_power_domain(PD_FEC, pmu_pd_off);
++	pmu_set_power_domain(PD_ISP1, pmu_pd_off);
++	pmu_set_power_domain(PD_VI, pmu_pd_off);
++
++	pmu_set_power_domain(PD_RGA31, pmu_pd_off);
++
++	pmu_set_power_domain(PD_AUDIO, pmu_pd_off);
++
++	pmu_set_power_domain(PD_GMAC, pmu_pd_off);
++	pmu_set_power_domain(PD_PCIE, pmu_pd_off);
++	pmu_set_power_domain(PD_PHP, pmu_pd_off);
++
++	pmu_set_power_domain(PD_SDIO, pmu_pd_off);
++
++	pmu_set_power_domain(PD_NVM0, pmu_pd_off);
++	pmu_set_power_domain(PD_NVM, pmu_pd_off);
++
++	pmu_set_power_domain(PD_SDMMC, pmu_pd_off);
++	pmu_set_power_domain(PD_CRYPTO, pmu_pd_off);
++}
++
++static void pmu_power_domains_resume(void)
++{
++	int i;
++
++	pmu_set_power_domain(PD_CRYPTO, !!(ddr_data.pmu_pd_st0 & BIT(PD_CRYPTO)));
++	pmu_set_power_domain(PD_SDMMC, !!(ddr_data.pmu_pd_st0 & BIT(PD_SDMMC)));
++
++	pmu_set_power_domain(PD_NVM, !!(ddr_data.pmu_pd_st0 & BIT(PD_NVM)));
++	pmu_set_power_domain(PD_NVM0, !!(ddr_data.pmu_pd_st0 & BIT(PD_NVM0)));
++
++	pmu_set_power_domain(PD_SDIO, !!(ddr_data.pmu_pd_st0 & BIT(PD_SDIO)));
++
++	pmu_set_power_domain(PD_PHP, !!(ddr_data.pmu_pd_st0 & BIT(PD_PHP)));
++	pmu_set_power_domain(PD_PCIE, !!(ddr_data.pmu_pd_st0 & BIT(PD_PCIE)));
++	pmu_set_power_domain(PD_GMAC, !!(ddr_data.pmu_pd_st0 & BIT(PD_GMAC)));
++
++	pmu_set_power_domain(PD_AUDIO, !!(ddr_data.pmu_pd_st0 & BIT(PD_AUDIO)));
++
++	pmu_set_power_domain(PD_USB, !!(ddr_data.pmu_pd_st0 & BIT(PD_USB)));
++
++	pmu_set_power_domain(PD_RGA31, !!(ddr_data.pmu_pd_st0 & BIT(PD_RGA31)));
++
++	pmu_set_power_domain(PD_VI, !!(ddr_data.pmu_pd_st0 & BIT(PD_VI)));
++	pmu_set_power_domain(PD_ISP1, !!(ddr_data.pmu_pd_st0 & BIT(PD_ISP1)));
++	pmu_set_power_domain(PD_FEC, !!(ddr_data.pmu_pd_st0 & BIT(PD_FEC)));
++
++	pmu_set_power_domain(PD_VOP, !!(ddr_data.pmu_pd_st0 & BIT(PD_VOP)));
++
++	pmu_set_power_domain(PD_VO1, !!(ddr_data.pmu_pd_st0 & BIT(PD_VO1)));
++
++	pmu_set_power_domain(PD_VO0, !!(ddr_data.pmu_pd_st0 & BIT(PD_VO0)));
++
++	pmu_set_power_domain(PD_VDPU, !!(ddr_data.pmu_pd_st0 & BIT(PD_VDPU)));
++	pmu_set_power_domain(PD_AV1, !!(ddr_data.pmu_pd_st0 & BIT(PD_AV1)));
++	pmu_set_power_domain(PD_RGA30, !!(ddr_data.pmu_pd_st0 & BIT(PD_RGA30)));
++
++	pmu_set_power_domain(PD_VCODEC, !!(ddr_data.pmu_pd_st0 & BIT(PD_VCODEC)));
++	pmu_set_power_domain(PD_VENC0, !!(ddr_data.pmu_pd_st0 & BIT(PD_VENC0)));
++	pmu_set_power_domain(PD_VENC1, !!(ddr_data.pmu_pd_st0 & BIT(PD_VENC1)));
++	pmu_set_power_domain(PD_RKVDEC0, !!(ddr_data.pmu_pd_st0 & BIT(PD_RKVDEC0)));
++	pmu_set_power_domain(PD_RKVDEC1, !!(ddr_data.pmu_pd_st0 & BIT(PD_RKVDEC1)));
++
++	pmu_set_power_domain(PD_NPU, !!(ddr_data.pmu_pd_st0 & BIT(PD_NPU)));
++	pmu_set_power_domain(PD_NPUTOP, !!(ddr_data.pmu_pd_st0 & BIT(PD_NPUTOP)));
++	pmu_set_power_domain(PD_NPU2, !!(ddr_data.pmu_pd_st0 & BIT(PD_NPU2)));
++	pmu_set_power_domain(PD_NPU1, !!(ddr_data.pmu_pd_st0 & BIT(PD_NPU1)));
++
++	pmu_set_power_domain(PD_GPU, !!(ddr_data.pmu_pd_st0 & BIT(PD_GPU)));
++
++	for (i = 0; i < 32; i++)
++		pmu_bus_idle_req(i, !!(ddr_data.bus_idle_st0 & BIT(i)));
++
++	pmu_qch_pwr_ctlr(0x10, !!(ddr_data.qch_pwr_st & 0x10));
++	pmu_qch_pwr_ctlr(0x8, !!(ddr_data.qch_pwr_st & 0x8));
++	pmu_qch_pwr_ctlr(0x4, !!(ddr_data.qch_pwr_st & 0x4));
++	pmu_qch_pwr_ctlr(0x2, !!(ddr_data.qch_pwr_st & 0x2));
++	pmu_qch_pwr_ctlr(0x1, !!(ddr_data.qch_pwr_st & 0x1));
++	pmu_qch_pwr_ctlr(0x40, !!(ddr_data.qch_pwr_st & 0x40));
++	pmu_qch_pwr_ctlr(0x20, !!(ddr_data.qch_pwr_st & 0x20));
++
++	if ((ddr_data.pmu_pd_st0 & BIT(PD_CRYPTO)) == 0)
++		pd_crypto_restore();
++
++	if ((ddr_data.pmu_pd_st0 & BIT(PD_PHP)) == 0)
++		pd_php_restore();
++
++	qos_restore();
++}
++
++static int cpus_power_domain_on(uint32_t cpu_id)
++{
++	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
++		      BITS_WITH_WMASK(0, 0x1, core_pm_en));
++	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
++		      BITS_WITH_WMASK(1, 0x1, core_pm_sft_wakeup_en));
++	dsb();
++
++	return 0;
++}
++
++static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg)
++{
++	uint32_t apm_value = BIT(core_pm_en);
++
++	if (pd_cfg == core_pwr_wfi_int)
++		apm_value |= BIT(core_pm_int_wakeup_en);
++
++	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
++		      BITS_WITH_WMASK(apm_value, 0x3, 0));
++	dsb();
++
++	return 0;
++}
++
++static inline void cpus_pd_req_enter_wfi(void)
++{
++	/* CORTEX_A55_CPUACTLR_EL1 */
++	__asm__ volatile ("msr	DBGPRCR_EL1, xzr\n"
++			  "mrs	x0, S3_0_C15_C2_7\n"
++			  "orr	x0, x0, #0x1\n"
++			  "msr	S3_0_C15_C2_7, x0\n"
++			  "wfi_loop:\n"
++			  "isb\n"
++			  "wfi\n"
++			  "b wfi_loop\n");
++}
++
++static void nonboot_cpus_off(void)
++{
++	uint32_t boot_cpu, cpu, tmp;
++	uint32_t exp_st;
++	uint32_t bcore0_rst_msk = 0, bcore1_rst_msk = 0;
++	int wait_cnt;
++
++	bcore0_rst_msk = CRU_BIGCPU02_RST_MSK | CRU_BIGCPU13_RST_MSK;
++	bcore1_rst_msk = CRU_BIGCPU02_RST_MSK | CRU_BIGCPU13_RST_MSK;
++
++	mmio_write_32(BIGCORE0CRU_BASE + 0xa00, BITS_WITH_WMASK(0, bcore0_rst_msk, 0));
++	mmio_write_32(BIGCORE1CRU_BASE + 0xa00, BITS_WITH_WMASK(0, bcore1_rst_msk, 0));
++
++	wait_cnt = NONBOOT_CPUS_OFF_LOOP;
++	exp_st = SYS_GRF_BIG_CPUS_WFE;
++	do {
++		wait_cnt--;
++		tmp = mmio_read_32(SYSGRF_BASE + SYS_GRF_SOC_STATUS(3));
++		tmp &= SYS_GRF_BIG_CPUS_WFE;
++	} while (tmp != exp_st && wait_cnt);
++
++	boot_cpu = plat_my_core_pos();
++
++	/* turn off noboot cpus */
++	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
++		if (cpu == boot_cpu)
++			continue;
++		cpus_power_domain_off(cpu, core_pwr_wfi);
++	}
++
++	mmio_write_32(SRAM_BASE + 0x08, (uintptr_t)&cpus_pd_req_enter_wfi);
++	mmio_write_32(SRAM_BASE + 0x04, 0xdeadbeaf);
++
++	dsb();
++	isb();
++
++	sev();
++
++	wait_cnt = NONBOOT_CPUS_OFF_LOOP;
++	do {
++		wait_cnt--;
++		tmp = mmio_read_32(PMU_BASE + PMU2_CLUSTER_ST);
++		tmp &= CLUSTER_STS_NONBOOT_CPUS_DWN;
++	} while (tmp != CLUSTER_STS_NONBOOT_CPUS_DWN && wait_cnt);
++
++	if (tmp != CLUSTER_STS_NONBOOT_CPUS_DWN)
++		ERROR("nonboot cpus status(%x) error!\n", tmp);
++}
++
++int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr,
++				 uint64_t entrypoint)
++{
++	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
++
++	assert(cpu_id < PLATFORM_CORE_COUNT);
++	assert(cpuson_flags[cpu_id] == 0);
++	cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG;
++	cpuson_entry_point[cpu_id] = entrypoint;
++	dsb();
++
++	flush_dcache_range((uintptr_t)cpuson_flags, sizeof(cpuson_flags));
++	flush_dcache_range((uintptr_t)cpuson_entry_point,
++			   sizeof(cpuson_entry_point));
++	dsb();
++	isb();
++
++	cpus_power_domain_on(cpu_id);
++
++	return PSCI_E_SUCCESS;
++}
++
++int rockchip_soc_cores_pwr_dm_on_finish(void)
++{
++	uint32_t cpu_id = plat_my_core_pos();
++
++	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
++		      BITS_WITH_WMASK(0, 0xf, 0));
++
++	return PSCI_E_SUCCESS;
++}
++
++int rockchip_soc_cores_pwr_dm_off(void)
++{
++	uint32_t cpu_id = plat_my_core_pos();
++
++	cpus_power_domain_off(cpu_id, core_pwr_wfi);
++
++	return PSCI_E_SUCCESS;
++}
++
++int rockchip_soc_cores_pwr_dm_suspend(void)
++{
++	uint32_t cpu_id = plat_my_core_pos();
++
++	assert(cpu_id < PLATFORM_CORE_COUNT);
++
++	cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN;
++	cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint();
++	dsb();
++	flush_dcache_range((uintptr_t)cpuson_flags, sizeof(cpuson_flags));
++	flush_dcache_range((uintptr_t)cpuson_entry_point,
++			   sizeof(cpuson_entry_point));
++	dsb();
++	isb();
++
++	cpus_power_domain_off(cpu_id, core_pwr_wfi_int);
++
++	__asm__ volatile ("msr	DBGPRCR_EL1, xzr\n"
++			  "mrs	x0, S3_0_C15_C2_7\n"
++			  "orr	x0, x0, #0x1\n"
++			  "msr	S3_0_C15_C2_7, x0\n");
++
++	return PSCI_E_SUCCESS;
++}
++
++int rockchip_soc_cores_pwr_dm_resume(void)
++{
++	uint32_t cpu_id = plat_my_core_pos();
++
++	mmio_write_32(PMU_BASE + PMU2_CPU_AUTO_PWR_CON(cpu_id),
++		      BITS_WITH_WMASK(0, 0x3, 0));
++
++	dsb();
++
++	return PSCI_E_SUCCESS;
++}
++
++static void ddr_sleep_config(void)
++{
++	int i;
++
++	if (pmu_power_domain_st(PD_DDR01) == 0) {
++		ddr_data.ddrgrf_chn_con0[0] =
++			mmio_read_32(DDR01GRF_BASE + DDRGRF_CHA_CON(0));
++		ddr_data.ddrgrf_chn_con0[1] =
++			mmio_read_32(DDR01GRF_BASE + DDRGRF_CHB_CON(0));
++		ddr_data.ddrgrf_chn_con1[0] =
++			mmio_read_32(DDR01GRF_BASE + DDRGRF_CHA_CON(1));
++		ddr_data.ddrgrf_chn_con1[1] =
++			mmio_read_32(DDR01GRF_BASE + DDRGRF_CHB_CON(1));
++		ddr_data.ddrgrf_chn_con2[0] =
++			mmio_read_32(DDR01GRF_BASE + DDRGRF_CHA_CON(2));
++		ddr_data.ddrgrf_chn_con2[1] =
++			mmio_read_32(DDR01GRF_BASE + DDRGRF_CHB_CON(2));
++
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHA_CON(2), 0x20002000);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHB_CON(2), 0x20002000);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHA_CON(2), 0x08000000);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHB_CON(2), 0x08000000);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHA_CON(0), 0x00200020);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHB_CON(0), 0x00200020);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHA_CON(1), 0x00400040);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHB_CON(1), 0x00400040);
++	}
++
++	if (pmu_power_domain_st(PD_DDR23) == 0) {
++		ddr_data.ddrgrf_chn_con0[2] =
++			mmio_read_32(DDR23GRF_BASE + DDRGRF_CHA_CON(0));
++		ddr_data.ddrgrf_chn_con0[3] =
++			mmio_read_32(DDR23GRF_BASE + DDRGRF_CHB_CON(0));
++		ddr_data.ddrgrf_chn_con1[2] =
++			mmio_read_32(DDR23GRF_BASE + DDRGRF_CHA_CON(1));
++		ddr_data.ddrgrf_chn_con1[3] =
++			mmio_read_32(DDR23GRF_BASE + DDRGRF_CHB_CON(1));
++		ddr_data.ddrgrf_chn_con2[2] =
++			mmio_read_32(DDR23GRF_BASE + DDRGRF_CHA_CON(2));
++		ddr_data.ddrgrf_chn_con2[3] =
++			mmio_read_32(DDR23GRF_BASE + DDRGRF_CHB_CON(2));
++
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHA_CON(2), 0x20002000);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHB_CON(2), 0x20002000);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHA_CON(2), 0x08000000);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHB_CON(2), 0x08000000);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHA_CON(0), 0x00200020);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHB_CON(0), 0x00200020);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHA_CON(1), 0x00400040);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHB_CON(1), 0x00400040);
++	}
++
++	for (i = 0; i < DDR_CHN_CNT; i++) {
++		ddr_data.pmu1_ddr_pwr_sft_con[i] =
++			mmio_read_32(PMU_BASE + PMU1_DDR_PWR_SFTCON(i));
++		mmio_write_32(PMU_BASE + PMU1_DDR_PWR_SFTCON(i), 0x0fff0900);
++	}
++}
++
++static void ddr_sleep_config_restore(void)
++{
++	int i;
++
++	for (i = 0; i < DDR_CHN_CNT; i++) {
++		mmio_write_32(PMU_BASE + PMU1_DDR_PWR_SFTCON(i),
++			      0x0fff0000 | ddr_data.pmu1_ddr_pwr_sft_con[i]);
++	}
++
++	if (pmu_power_domain_st(PD_DDR01) == 0) {
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHA_CON(1),
++			      0x00400000 | ddr_data.ddrgrf_chn_con1[0]);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHB_CON(1),
++			      0x00400000 | ddr_data.ddrgrf_chn_con1[1]);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHA_CON(0),
++			      0x00200000 | ddr_data.ddrgrf_chn_con0[0]);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHB_CON(0),
++			      0x00200000 | ddr_data.ddrgrf_chn_con0[1]);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHA_CON(2),
++			      0x28000000 | ddr_data.ddrgrf_chn_con2[0]);
++		mmio_write_32(DDR01GRF_BASE + DDRGRF_CHB_CON(2),
++			      0x28000000 | ddr_data.ddrgrf_chn_con2[1]);
++	}
++
++	if (pmu_power_domain_st(PD_DDR23) == 0) {
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHA_CON(1),
++			      0x00400000 | ddr_data.ddrgrf_chn_con1[2]);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHB_CON(1),
++			      0x00400000 | ddr_data.ddrgrf_chn_con1[3]);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHA_CON(0),
++			      0x00200000 | ddr_data.ddrgrf_chn_con0[2]);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHB_CON(0),
++			      0x00200000 | ddr_data.ddrgrf_chn_con0[3]);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHA_CON(2),
++			      0x28000000 | ddr_data.ddrgrf_chn_con2[2]);
++		mmio_write_32(DDR23GRF_BASE + DDRGRF_CHB_CON(2),
++			      0x28000000 | ddr_data.ddrgrf_chn_con2[3]);
++	}
++}
++
++static void pmu_sleep_config(void)
++{
++	uint32_t pmu1_pwr_con, pmu1_wkup_int_con, pmu1_cru_pwr_con;
++	uint32_t pmu1_ddr_pwr_con, pmu1_pll_pd_con[2] = {0};
++	uint32_t pmu2_dsu_pwr_con, pmu2_core_pwr_con, pmu2_clst_idle_con;
++	uint32_t pmu2_bus_idle_con[3] = {0}, pmu2_pwr_gate_con[3] = {0};
++	uint32_t pmu2_vol_gate_con[3] = {0}, pmu2_qch_pwr_con = 0;
++	int i;
++
++	ddr_data.pmu1grf_soc_con7 = mmio_read_32(PMU1GRF_BASE + PMU1_GRF_SOC_CON(7));
++	ddr_data.pmu1grf_soc_con8 = mmio_read_32(PMU1GRF_BASE + PMU1_GRF_SOC_CON(8));
++	ddr_data.pmu1grf_soc_con9 = mmio_read_32(PMU1GRF_BASE + PMU1_GRF_SOC_CON(9));
++	ddr_data.pmu1sgrf_soc_con14 = mmio_read_32(PMU1SGRF_BASE + PMU1_SGRF_SOC_CON(14));
++	ddr_data.pmu0sgrf_soc_con1 = mmio_read_32(PMU0SGRF_BASE + PMU0_SGRF_SOC_CON(1));
++	ddr_data.pmu0grf_soc_con1 = mmio_read_32(PMU0GRF_BASE + PMU0_GRF_SOC_CON(1));
++
++	ddr_data.pmu2_vol_gate_con[0] = mmio_read_32(PMU_BASE + PMU2_VOL_GATE_CON(0));
++	ddr_data.pmu2_vol_gate_con[1] = mmio_read_32(PMU_BASE + PMU2_VOL_GATE_CON(1));
++	ddr_data.pmu2_vol_gate_con[2] = mmio_read_32(PMU_BASE + PMU2_VOL_GATE_CON(2));
++
++	ddr_data.pmu2_submem_gate_sft_con0 =
++		mmio_read_32(PMU_BASE + PMU2_MEMPWR_MD_GATE_SFTCON(0));
++
++	/* save pmic_sleep iomux gpio0_a4 */
++	ddr_data.gpio0a_iomux_l = mmio_read_32(PMU0IOC_BASE + 0);
++	ddr_data.gpio0a_iomux_h = mmio_read_32(PMU0IOC_BASE + 4);
++	ddr_data.pmu0grf_soc_con3 = mmio_read_32(PMU0GRF_BASE + PMU0_GRF_SOC_CON(3));
++
++	/* PMU1 repair disable */
++	mmio_write_32(PMU0GRF_BASE + PMU0_GRF_SOC_CON(0), 0x00010000);
++
++	/* set pmic_sleep iomux */
++	mmio_write_32(PMU0IOC_BASE + 0,
++		      BITS_WITH_WMASK(1, 0xf, 8) |
++		      BITS_WITH_WMASK(1, 0xfu, 12));
++
++	/* set tsadc_shut_m0 pin iomux to gpio */
++	mmio_write_32(PMU0IOC_BASE + 0,
++		      BITS_WITH_WMASK(0, 0xf, 4));
++
++	/* set spi2_cs0/1 pin iomux to gpio */
++	mmio_write_32(PMU0IOC_BASE + 8,
++		      BITS_WITH_WMASK(0, 0xff, 0));
++
++	/* sleep 1~2 src select */
++	mmio_write_32(PMU0GRF_BASE + PMU0_GRF_SOC_CON(3),
++		      BITS_WITH_WMASK(0x8, 0xf, 0) |
++		      BITS_WITH_WMASK(0x8, 0xf, 4) |
++		      BITS_WITH_WMASK(0x0, 0x3, 8));
++
++	pmu1_wkup_int_con = BIT(WAKEUP_GPIO0_INT_EN) |
++			    BIT(WAKEUP_CPU0_INT_EN);
++
++	pmu1_pwr_con = BIT(powermode_en);
++
++	pmu1_cru_pwr_con =
++		BIT(alive_osc_mode_en) |
++		BIT(power_off_en) |
++		BIT(pd_clk_src_gate_en);
++
++	pmu1_ddr_pwr_con = 0;
++
++	pmu2_dsu_pwr_con =
++		BIT(DSU_PWRDN_EN) |
++		BIT(DSU_PWROFF_EN);
++
++	pmu2_core_pwr_con = BIT(CORE_PWRDN_EN);
++
++	pmu2_clst_idle_con =
++		BIT(IDLE_REQ_BIGCORE0_EN) |
++		BIT(IDLE_REQ_BIGCORE1_EN) |
++		BIT(IDLE_REQ_DSU_EN) |
++		BIT(IDLE_REQ_LITDSU_EN) |
++		BIT(IDLE_REQ_ADB400_CORE_QCH_EN);
++
++	pmu1_pll_pd_con[0] =
++		BIT(B0PLL_PD_EN) |
++		BIT(B1PLL_PD_EN) |
++		BIT(LPLL_PD_EN) |
++		BIT(V0PLL_PD_EN) |
++		BIT(AUPLL_PD_EN) |
++		BIT(GPLL_PD_EN) |
++		BIT(CPLL_PD_EN) |
++		BIT(NPLL_PD_EN);
++
++	pmu1_pll_pd_con[1] =
++		BIT(PPLL_PD_EN) |
++		BIT(SPLL_PD_EN);
++
++	pmu2_bus_idle_con[0] = 0;
++
++	pmu2_bus_idle_con[1] =
++		BIT(BUS_ID_SECURE - 16) |
++		BIT(BUS_ID_SECURE_CENTER_CHANNEL - 16) |
++		BIT(BUS_ID_CENTER_CHANNEL - 16);
++
++	pmu2_bus_idle_con[2] =
++		BIT(BUS_ID_MSCH - 32) |
++		BIT(BUS_ID_BUS - 32) |
++		BIT(BUS_ID_TOP - 32);
++
++	pmu2_pwr_gate_con[0] = 0;
++	pmu2_pwr_gate_con[1] = BIT(PD_SECURE - 16);
++	pmu2_pwr_gate_con[2] = 0;
++
++	pmu2_qch_pwr_con = 0;
++
++	pmu2_vol_gate_con[0] = 0x7;
++	pmu2_vol_gate_con[2] = 0;
++
++	mmio_write_32(PMU_BASE + PMU2_CORE_AUTO_PWR_CON(0), 0x00030000);
++	mmio_write_32(PMU_BASE + PMU2_CORE_AUTO_PWR_CON(1), 0x00030000);
++	mmio_write_32(PMU_BASE + PMU2_CORE_PWR_CON(0),
++		      WITH_16BITS_WMSK(pmu2_core_pwr_con));
++	mmio_write_32(PMU_BASE + PMU2_CORE_PWR_CON(1),
++		      WITH_16BITS_WMSK(pmu2_core_pwr_con));
++	mmio_write_32(PMU_BASE + PMU2_CLUSTER_IDLE_CON,
++		      WITH_16BITS_WMSK(pmu2_clst_idle_con));
++	mmio_write_32(PMU_BASE + PMU2_DSU_AUTO_PWR_CON, 0x00030000);
++	mmio_write_32(PMU_BASE + PMU2_DSU_PWR_CON,
++		      WITH_16BITS_WMSK(pmu2_dsu_pwr_con));
++
++	mmio_write_32(PMU_BASE + PMU1_OSC_STABLE_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU1_STABLE_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU1_WAKEUP_RST_CLR_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU1_PLL_LOCK_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU1_PWM_SWITCH_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_CORE0_STABLE_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_CORE0_PWRUP_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_CORE0_PWRDN_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_CORE1_STABLE_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_CORE1_PWRUP_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_CORE1_PWRDN_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_DSU_STABLE_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_DSU_PWRUP_CNT_THRESH, 24000);
++	mmio_write_32(PMU_BASE + PMU2_DSU_PWRDN_CNT_THRESH, 24000);
++
++	/* Config pmu power mode and pmu wakeup source */
++	mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON,
++		      BITS_WITH_WMASK(1, 0x1, 0));
++
++	/* pmu1_pwr_con */
++	mmio_write_32(PMU_BASE + PMU1_PWR_CON,
++		      WITH_16BITS_WMSK(pmu1_pwr_con));
++
++	/* cru_pwr_con */
++	mmio_write_32(PMU_BASE + PMU1_CRU_PWR_CON,
++		      WITH_16BITS_WMSK(pmu1_cru_pwr_con));
++
++	/* wakeup source */
++	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, pmu1_wkup_int_con);
++
++	/* ddr pwr con */
++	for (i = 0; i < DDR_CHN_CNT; i++) {
++		mmio_write_32(PMU_BASE + PMU1_DDR_PWR_CON(i),
++			      WITH_16BITS_WMSK(pmu1_ddr_pwr_con));
++		pmu2_bus_idle_con[1] |=
++			BIT(BUS_ID_MSCH0 - 16 + i);
++	}
++
++	/* pll_pd */
++	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(0),
++		      WITH_16BITS_WMSK(pmu1_pll_pd_con[0]));
++	mmio_write_32(PMU_BASE + PMU1_PLLPD_CON(1),
++		      WITH_16BITS_WMSK(pmu1_pll_pd_con[1]));
++
++	/* bypass cpu1~7*/
++	mmio_write_32(PMU_BASE + PMU2_PWR_CON1, 0x00ff00fe);
++
++	/* bus idle */
++	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(0),
++		      WITH_16BITS_WMSK(pmu2_bus_idle_con[0]));
++	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(1),
++		      WITH_16BITS_WMSK(pmu2_bus_idle_con[1]));
++	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(2),
++		      WITH_16BITS_WMSK(pmu2_bus_idle_con[2]));
++	mmio_write_32(PMU_BASE + PMU2_BUS_IDLE_CON(2),
++		      0xf000f000);
++	/* power gate */
++	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(0),
++		      WITH_16BITS_WMSK(pmu2_pwr_gate_con[0]));
++	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(1),
++		      WITH_16BITS_WMSK(pmu2_pwr_gate_con[1]));
++	mmio_write_32(PMU_BASE + PMU2_PWR_GATE_CON(2),
++		      WITH_16BITS_WMSK(pmu2_pwr_gate_con[2]));
++	/* vol gate */
++	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_CON(0),
++		      BITS_WITH_WMASK(pmu2_vol_gate_con[0], 0x7, 0));
++	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_CON(1), 0);
++	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_CON(2),
++		      BITS_WITH_WMASK(pmu2_vol_gate_con[2], 0x3, 0));
++	/* qch */
++	mmio_write_32(PMU_BASE + PMU2_QCHANNEL_PWR_CON,
++		      BITS_WITH_WMASK(pmu2_qch_pwr_con, 0x7f, 0));
++
++	mmio_write_32(PMU_BASE + PMU2_MEMPWR_MD_GATE_SFTCON(0),
++		      0x000f000f);
++}
++
++static void pmu_sleep_restore(void)
++{
++	mmio_write_32(PMU1GRF_BASE + PMU1_GRF_SOC_CON(7),
++		      WITH_16BITS_WMSK(ddr_data.pmu1grf_soc_con7));
++	mmio_write_32(PMU1GRF_BASE + PMU1_GRF_SOC_CON(8),
++		      WITH_16BITS_WMSK(ddr_data.pmu1grf_soc_con8));
++	mmio_write_32(PMU1GRF_BASE + PMU1_GRF_SOC_CON(9),
++		      WITH_16BITS_WMSK(ddr_data.pmu1grf_soc_con9));
++	mmio_write_32(PMU1SGRF_BASE + PMU1_SGRF_SOC_CON(14),
++		      WITH_16BITS_WMSK(ddr_data.pmu1sgrf_soc_con14));
++
++	mmio_write_32(PMU0SGRF_BASE + PMU0_SGRF_SOC_CON(1),
++		      WITH_16BITS_WMSK(ddr_data.pmu0sgrf_soc_con1));
++	mmio_write_32(PMU0GRF_BASE + PMU0_GRF_SOC_CON(1),
++		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con1));
++
++	mmio_write_32(PMU_BASE + PMU2_CORE_PWR_CON(0), 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU2_CORE_PWR_CON(1), 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU2_CLUSTER_IDLE_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU2_DSU_PWR_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU2_PWR_CON1, 0xffff0000);
++
++	/* Must clear PMU1_WAKEUP_INT_CON because the wakeup source
++	 * in PMU1_WAKEUP_INT_CON will wakeup cpus in cpu_auto_pd state.
++	 */
++	mmio_write_32(PMU_BASE + PMU1_WAKEUP_INT_CON, 0);
++	mmio_write_32(PMU_BASE + PMU1_PWR_CON, 0xffff0000);
++	mmio_write_32(PMU_BASE + PMU1_INT_MASK_CON, 0x00010000);
++	mmio_write_32(PMU_BASE + PMU0_WAKEUP_INT_CON, 0x00010000);
++	mmio_write_32(PMU_BASE + PMU0_PWR_CON, 0xffff0000);
++
++	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_CON(0),
++		      WITH_16BITS_WMSK(ddr_data.pmu2_vol_gate_con[0]));
++	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_CON(1),
++		      WITH_16BITS_WMSK(ddr_data.pmu2_vol_gate_con[1]));
++	mmio_write_32(PMU_BASE + PMU2_VOL_GATE_CON(2),
++		      WITH_16BITS_WMSK(ddr_data.pmu2_vol_gate_con[2]));
++
++	mmio_write_32(PMU_BASE + PMU2_MEMPWR_MD_GATE_SFTCON(0),
++		      WITH_16BITS_WMSK(ddr_data.pmu2_submem_gate_sft_con0));
++
++	mmio_write_32(PMU0GRF_BASE + PMU0_GRF_SOC_CON(3),
++		      WITH_16BITS_WMSK(ddr_data.pmu0grf_soc_con3));
++	mmio_write_32(PMU1GRF_BASE + PMU1_GRF_SOC_CON(2),
++		      WITH_16BITS_WMSK(ddr_data.pmu1grf_soc_con2));
++
++	mmio_write_32(PMU0IOC_BASE + 0x4,
++		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_h));
++	mmio_write_32(PMU0IOC_BASE + 0,
++		      WITH_16BITS_WMSK(ddr_data.gpio0a_iomux_l));
++}
++
++static void soc_sleep_config(void)
++{
++	ddr_data.gpio0b_iomux_l = mmio_read_32(PMU0IOC_BASE + 0x8);
++
++	pmu_sleep_config();
++	ddr_sleep_config();
++}
++
++static void soc_sleep_restore(void)
++{
++	ddr_sleep_config_restore();
++	pmu_sleep_restore();
++
++	mmio_write_32(PMU0IOC_BASE + 0x8, WITH_16BITS_WMSK(ddr_data.gpio0b_iomux_l));
++}
++
++static void pm_pll_suspend(void)
++{
++	ddr_data.cru_mode_con = mmio_read_32(CRU_BASE + 0x280);
++	ddr_data.busscru_mode_con = mmio_read_32(BUSSCRU_BASE + 0x280);
++	ddr_data.pmu2_bisr_con0 = mmio_read_32(PMU_BASE + PMU2_BISR_CON(0));
++	ddr_data.cpll_con0 = mmio_read_32(CRU_BASE + CRU_PLLS_CON(2, 0));
++	ddr_data.pmu1cru_clksel_con1 = mmio_read_32(PMU1CRU_BASE + CRU_CLKSEL_CON(1));
++
++	/* disable bisr_init */
++	mmio_write_32(PMU_BASE + PMU2_BISR_CON(0), BITS_WITH_WMASK(0, 0x1, 0));
++	/* cpll bypass */
++	mmio_write_32(CRU_BASE + CRU_PLLS_CON(2, 0), BITS_WITH_WMASK(1u, 1u, 15));
++}
++
++static void pm_pll_restore(void)
++{
++	pm_pll_wait_lock(CRU_BASE + CRU_PLLS_CON(2, 0));
++
++	mmio_write_32(CRU_BASE + 0x280, WITH_16BITS_WMSK(ddr_data.cru_mode_con));
++	mmio_write_32(BUSSCRU_BASE + 0x280, WITH_16BITS_WMSK(ddr_data.busscru_mode_con));
++	mmio_write_32(CRU_BASE + CRU_PLLS_CON(2, 0), WITH_16BITS_WMSK(ddr_data.cpll_con0));
++	dsb();
++	isb();
++	mmio_write_32(PMU_BASE + PMU2_BISR_CON(0), WITH_16BITS_WMSK(ddr_data.pmu2_bisr_con0));
++}
++
++int rockchip_soc_sys_pwr_dm_suspend(void)
++{
++	clk_gate_con_save();
++	clk_gate_con_disable();
++
++	psram_sleep_cfg->pm_flag &= ~PM_WARM_BOOT_BIT;
++
++	pmu_power_domains_suspend();
++	soc_sleep_config();
++	dsu_core_save();
++	pm_pll_suspend();
++
++	return 0;
++}
++
++int rockchip_soc_sys_pwr_dm_resume(void)
++{
++	pm_pll_restore();
++	dsu_core_restore();
++	soc_sleep_restore();
++	pmu_power_domains_resume();
++	plat_rockchip_gic_cpuif_enable();
++
++	psram_sleep_cfg->pm_flag |= PM_WARM_BOOT_BIT;
++
++	clk_gate_con_restore();
++
++	return 0;
++}
++
++void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(const
++					psci_power_state_t *target_state)
++{
++	psci_power_down_wfi();
++}
++
++void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
++{
++	cpus_pd_req_enter_wfi();
++	psci_power_down_wfi();
++}
++
++void __dead2 rockchip_soc_soft_reset(void)
++{
++	/* pll slow mode */
++	mmio_write_32(CRU_BASE + 0x280, 0x03ff0000);
++	mmio_write_32(BIGCORE0CRU_BASE + 0x280, 0x00030000);
++	mmio_write_32(BIGCORE0CRU_BASE + 0x300, 0x60000000);
++	mmio_write_32(BIGCORE0CRU_BASE + 0x304, 0x00600000);
++	mmio_write_32(BIGCORE1CRU_BASE + 0x280, 0x00030000);
++	mmio_write_32(BIGCORE1CRU_BASE + 0x300, 0x60000000);
++	mmio_write_32(BIGCORE1CRU_BASE + 0x304, 0x00600000);
++	mmio_write_32(DSUCRU_BASE + 0x280, 0x00030000);
++	mmio_write_32(DSUCRU_BASE + 0x318, 0x30600000);
++	mmio_write_32(DSUCRU_BASE + 0x31c, 0x30600000);
++	mmio_write_32(DSUCRU_BASE + 0x304, 0x00010000);
++	mmio_write_32(BUSSCRU_BASE + 0x280, 0x0003000);
++	dsb();
++	isb();
++
++	mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL);
++
++	/*
++	 * Maybe the HW needs some times to reset the system,
++	 * so we do not hope the core to execute valid codes.
++	 */
++	psci_power_down_wfi();
++}
++
++void __dead2 rockchip_soc_system_off(void)
++{
++	/* set pmic_sleep pin(gpio0_a2) to gpio mode */
++	mmio_write_32(PMU0IOC_BASE + 0, BITS_WITH_WMASK(0, 0xf, 8));
++
++	/* config output */
++	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DDR_L,
++		      BITS_WITH_WMASK(1, 0x1, 2));
++
++	/* config output high level */
++	mmio_write_32(GPIO0_BASE + GPIO_SWPORT_DR_L,
++		      BITS_WITH_WMASK(1, 0x1, 2));
++	dsb();
++
++	/*
++	 * Maybe the HW needs some times to reset the system,
++	 * so we do not hope the core to execute valid codes.
++	 */
++	psci_power_down_wfi();
++}
++
++static void rockchip_pmu_pd_init(void)
++{
++	mmio_write_32(PMU_BASE + PMU2_BISR_CON(1), 0xffffffff);
++	mmio_write_32(PMU_BASE + PMU2_BISR_CON(2), 0xffffffff);
++	mmio_write_32(PMU_BASE + PMU2_BISR_CON(3), 0xffffffff);
++
++	pmu_set_power_domain(PD_PHP, pmu_pd_on);
++	pmu_set_power_domain(PD_PCIE, pmu_pd_on);
++	pmu_set_power_domain(PD_GMAC, pmu_pd_on);
++	pmu_set_power_domain(PD_SECURE, pmu_pd_on);
++	pmu_set_power_domain(PD_VOP, pmu_pd_on);
++	pmu_set_power_domain(PD_VO0, pmu_pd_on);
++	pmu_set_power_domain(PD_VO1, pmu_pd_on);
++}
++
++#define PLL_LOCKED_TIMEOUT 600000U
++
++void pm_pll_wait_lock(uint32_t pll_base)
++{
++	int delay = PLL_LOCKED_TIMEOUT;
++
++	if ((mmio_read_32(pll_base + CRU_PLL_CON(1)) & CRU_PLLCON1_PWRDOWN) != 0)
++		return;
++
++	while (delay-- >= 0) {
++		if (mmio_read_32(pll_base + CRU_PLL_CON(6)) &
++		    CRU_PLLCON6_LOCK_STATUS)
++			break;
++		udelay(1);
++	}
++
++	if (delay <= 0)
++		ERROR("Can't wait pll(0x%x) lock\n", pll_base);
++}
++
++void rockchip_plat_mmu_el3(void)
++{
++	/* Nothing todo */
++}
++
++void plat_rockchip_pmu_init(void)
++{
++	int cpu;
++
++	for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++)
++		cpuson_flags[cpu] = 0;
++
++	psram_sleep_cfg->sp = PSRAM_SP_TOP;
++	psram_sleep_cfg->ddr_func = (uint64_t)ddr_resume;
++	psram_sleep_cfg->ddr_data = 0;
++	psram_sleep_cfg->ddr_flag = 0;
++	psram_sleep_cfg->boot_mpidr = read_mpidr_el1() & 0xffff;
++	psram_sleep_cfg->pm_flag = PM_WARM_BOOT_BIT;
++
++	nonboot_cpus_off();
++
++	/*
++	 * When perform idle operation, corresponding clock can be
++	 * opened or gated automatically.
++	 */
++	mmio_write_32(PMU_BASE + PMU2_BIU_AUTO_CON(0), 0xffffffff);
++	mmio_write_32(PMU_BASE + PMU2_BIU_AUTO_CON(1), 0xffffffff);
++	mmio_write_32(PMU_BASE + PMU2_BIU_AUTO_CON(2), 0x00070007);
++
++	rockchip_pmu_pd_init();
++
++	/* grf_con_pmic_sleep_sel
++	 * pmic sleep function selection
++	 * 1'b0: From reset pulse generator, can reset external PMIC
++	 * 1'b1: From pmu block, only support sleep function for external PMIC
++	 */
++	mmio_write_32(PMU0GRF_BASE + PMU0_GRF_SOC_CON(3), 0x03ff0000);
++
++	/* pmusram remap to 0xffff0000 */
++	mmio_write_32(PMU0SGRF_BASE + PMU0_SGRF_SOC_CON(2), 0x00030001);
++
++	pm_reg_rgns_init();
++}
+diff --git a/plat/rockchip/rk3588/drivers/pmu/pmu.h b/plat/rockchip/rk3588/drivers/pmu/pmu.h
+new file mode 100644
+index 000000000..7d8288c59
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/pmu/pmu.h
+@@ -0,0 +1,589 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PMU_H__
++#define __PMU_H__
++
++#include <lib/mmio.h>
++
++#define PMU0_PWR_CON			0x0000
++#define PMU0_WAKEUP_INT_CON		0x0008
++#define PMU0_WAKEUP_INT_ST		0x000c
++#define PMU0_PMIC_STABLE_CNT_THRES	0x0010
++#define PMU0_WAKEUP_RST_CLR_CNT_THRES	0x0014
++#define PMU0_OSC_STABLE_CNT_THRES	0x0018
++#define PMU0_PWR_CHAIN_STABLE_CON	0x001c
++#define PMU0_DDR_RET_CON(i)		(0x0020 + (i) * 4)
++#define PMU0_INFO_TX_CON		0x0030
++
++#define PMU1_VERSION_ID			0x4000
++#define PMU1_PWR_CON			0x4004
++#define PMU1_PWR_FSM			0x4008
++#define PMU1_INT_MASK_CON		0x400c
++#define PMU1_WAKEUP_INT_CON		0x4010
++#define PMU1_WAKEUP_INT_ST		0x4014
++#define PMU1_WAKEUP_EDGE_CON		0x4018
++#define PMU1_WAKEUP_EDGE_ST		0x401c
++#define PMU1_DDR_PWR_CON(i)		(0x4020 + (i) * 4)
++#define PMU1_DDR_PWR_SFTCON(i)		(0x4030 + (i) * 4)
++#define PMU1_DDR_PWR_FSM		0x4040
++#define PMU1_DDR_PWR_ST			0x4044
++#define PMU1_CRU_PWR_CON		0x4050
++#define PMU1_CRU_PWR_SFTCON		0x4054
++#define PMU1_CRU_PWR_FSM		0x4058
++#define PMU1_PLLPD_CON(i)		(0x4060 + (i) * 4)
++#define PMU1_PLLPD_SFTCON(i)		(0x4068 + (i) * 4)
++#define PMU1_STABLE_CNT_THRESH		0x4080
++#define PMU1_OSC_STABLE_CNT_THRESH	0x4084
++#define PMU1_WAKEUP_RST_CLR_CNT_THRESH	0x4088
++#define PMU1_PLL_LOCK_CNT_THRESH	0x408c
++#define PMU1_WAKEUP_TIMEOUT_THRESH	0x4094
++#define PMU1_PWM_SWITCH_CNT_THRESH	0x4098
++#define PMU1_SYS_REG(i)			(0x4100 + (i) * 4)
++
++#define PMU2_PWR_CON1			0x8000
++#define PMU2_DSU_PWR_CON		0x8004
++#define PMU2_DSU_PWR_SFTCON		0x8008
++#define PMU2_DSU_AUTO_PWR_CON		0x800c
++#define PMU2_CPU_AUTO_PWR_CON(i)	(0x8010 + (i) * 4)
++#define PMU2_CPU_PWR_SFTCON(i)		(0x8030 + (i) * 4)
++#define PMU2_CORE_PWR_CON(i)		(0x8050 + (i) * 4)
++#define PMU2_CORE_PWR_SFTCON(i)		(0x8058 + (i) * 4)
++#define PMU2_CORE_AUTO_PWR_CON(i)	(0x8060 + (i) * 4)
++#define PMU2_CLUSTER_NOC_AUTO_CON	0x8068
++#define PMU2_CLUSTER_DBG_PWR_CON	0x806c
++#define PMU2_CLUSTER_IDLE_CON		0x8070
++#define PMU2_CLUSTER_IDLE_SFTCON	0x8074
++#define PMU2_CLUSTER_IDLE_ACK		0x8078
++#define PMU2_CLUSTER_IDLE_ST		0x807c
++#define PMU2_CLUSTER_ST			0x8080
++#define PMU2_SCU_PWR_FSM_STATUS(i)	(0x8084 + (i) * 4)
++#define PMU2_CORE_PCHANNEL_STATUS(i)	(0x808c + (i) * 4)
++#define PMU2_CPU_PWR_CHAIN_STABLE_CON	0x8098
++#define PMU2_CLUSTER_MEMPWR_GATE_SFTCON	0x809c
++#define PMU2_DSU_STABLE_CNT_THRESH	0x80b0
++#define PMU2_DSU_PWRUP_CNT_THRESH	0x80b4
++#define PMU2_DSU_PWRDN_CNT_THRESH	0x80b8
++#define PMU2_CORE0_STABLE_CNT_THRESH	0x80bc
++#define PMU2_CORE0_PWRUP_CNT_THRESH	0x80c0
++#define PMU2_CORE0_PWRDN_CNT_THRESH	0x80c4
++#define PMU2_CORE1_STABLE_CNT_THRESH	0x80c8
++#define PMU2_CORE1_PWRUP_CNT_THRESH	0x80cc
++#define PMU2_CORE1_PWRDN_CNT_THRESH	0x80d0
++#define PMU2_DBG_RST_CNT_THRESH(i)	(0x80d4 + (i) * 4)
++#define PMU2_BUS_IDLE_CON(i)		(0x8100 + (i) * 4)
++#define PMU2_BUS_IDLE_SFTCON(i)		(0x810c + (i) * 4)
++#define PMU2_BUS_IDLE_ACK(i)		(0x8118 + (i) * 4)
++#define PMU2_BUS_IDLE_ST(i)		(0x8120 + (i) * 4)
++#define PMU2_BIU_AUTO_CON(i)		(0x8128 + (i) * 4)
++#define PMU2_PWR_GATE_CON(i)		(0x8140 + (i) * 4)
++#define PMU2_PWR_GATE_SFTCON(i)		(0x814c + (i) * 4)
++#define PMU2_VOL_GATE_CON(i)		(0x8158 + (i) * 4)
++#define PMU2_PWR_UP_CHAIN_STABLE_CON(i)	(0x8164 + (i) * 4)
++#define PMU2_PWR_DWN_CHAIN_STABLE_CON(i)(0x8170 + (i) * 4)
++#define PMU2_PWR_STABLE_CHAIN_CNT_THRES	0x817c
++#define PMU2_PWR_GATE_ST(i)		(0x8180 + (i) * 4)
++#define PMU2_PWR_GATE_FSM		0x8188
++#define PMU2_VOL_GATE_FAST_CON		0x818c
++#define PMU2_GPU_PWRUP_CNT		0x8190
++#define PMU2_GPU_PWRDN_CNT		0x8194
++#define PMU2_NPU_PWRUP_CNT		0x8198
++#define PMU2_NPU_PWRDN_CNT		0x819c
++#define PMU2_MEMPWR_GATE_SFTCON(i)	(0x81a0 + (i) * 4)
++#define PMU2_MEMPWR_MD_GATE_SFTCON(i)	(0x81b0 + (i) * 4)
++#define PMU2_MEMPWR_MD_GATE_STATUS	0x81bc
++#define PMU2_SUBMEM_PWR_ACK_BYPASS(i)	(0x81c0 + (i) * 4)
++#define PMU2_QCHANNEL_PWR_CON		0x81d0
++#define PMU2_QCHANNEL_PWR_SFTCON	0x81d4
++#define PMU2_QCHANNEL_STATUS		0x81d8
++#define PMU2_DEBUG_INFO_SEL		0x81e0
++#define PMU2_VOP_SUBPD_STATE		0x81e4
++#define PMU2_PWR_CHAIN0_ST(i)		(0x81e8 + (i) * 4)
++#define PMU2_PWR_CHAIN1_ST(i)		(0x81f0 + (i) * 4)
++#define PMU2_PWR_MEM_ST(i)		(0x81f8 + (i) * 4)
++#define PMU2_BISR_CON(i)		(0x8200 + (i) * 4)
++#define PMU2_BISR_STATUS(i)		(0x8280 + (i) * 4)
++
++#define PMU2_QCH_PWR_MSK		0x7f
++
++#define PD_CTR_LOOP			500
++#define PD_CHECK_LOOP			500
++#define WFEI_CHECK_LOOP			500
++#define BUS_IDLE_LOOP			1000
++#define QCH_PWR_LOOP			5000
++
++/* PMU1SCRU */
++#define PMU1SCRU_GATE_CON(i)		(0x800 + (i) * 4)
++
++/* PMU_GRF */
++#define PMU0_GRF_SOC_CON(i)		((i) * 4)
++#define PMU0_GRF_OS_REGS(i)		(0x80 + ((i) - 8) * 4)
++#define PMU1_GRF_SOC_CON(i)		((i) * 4)
++#define PMU0_GRF_IO_RET_CON(i)		(0x20 + (i) * 4)
++
++/* PMU_SGRF */
++#define PMU0_SGRF_SOC_CON(i)		((i) * 4)
++#define PMU1_SGRF_SOC_CON(i)		((i) * 4)
++
++/* sys grf */
++#define GRF_CPU_STATUS0			0x0420
++
++#define CORES_PM_DISABLE		0x0
++#define PD_CHECK_LOOP			500
++#define WFEI_CHECK_LOOP			500
++
++/* The ways of cores power domain contorlling */
++enum cores_pm_ctr_mode {
++	core_pwr_pd = 0,
++	core_pwr_wfi = 1,
++	core_pwr_wfi_int = 2
++};
++
++/* PMU0_PWR_CON */
++enum pmu0_pwr_con {
++	pmu0_powermode_en = 0,
++	pmu0_pmu1_pwr_bypass = 1,
++	pmu0_pmu1_bus_bypass = 2,
++	pmu0_wkup_bypass = 3,
++	pmu0_pmic_bypass = 4,
++	pmu0_reset_bypass = 5,
++	pmu0_freq_sw_bypass = 6,
++	pmu0_osc_dis_bypass = 7,
++	pmu0_pmu1_pwr_gt_en = 8,
++	pmu0_pmu1_pwr_gt_sft_en = 9,
++	pmu0_pmu1_mem_gt_sft_en = 10,
++	pmu0_pmu1_bus_idle_en = 11,
++	pmu0_pmu1_bus_idle_sft_en = 12,
++	pmu0_pmu1_biu_auto_en = 13,
++	pmu0_pwr_off_io_en = 14,
++};
++
++/* PMU1_PWR_CON */
++enum pmu1_pwr_con {
++	powermode_en = 0,
++	dsu_bypass = 1,
++	bus_bypass = 4,
++	ddr_bypass = 5,
++	pwrdn_bypass = 6,
++	cru_bypass = 7,
++	qch_bypass = 8,
++	core_bypass = 9,
++	cpu_sleep_wfi_dis = 12,
++};
++
++/* PMU1_DDR_PWR_CON */
++enum pmu1_ddr_pwr_con {
++	ddr_sref_en = 0,
++	ddr_sref_a_en = 1,
++	ddrio_ret_en = 2,
++	ddrio_ret_exit_en = 5,
++	ddrio_rstiov_en = 6,
++	ddrio_rstiov_exit_en = 7,
++	ddr_gating_a_en = 8,
++	ddr_gating_c_en = 9,
++	ddr_gating_p_en = 10,
++};
++
++/* PMU_CRU_PWR_CON */
++enum pmu1_cru_pwr_con {
++	alive_32k_en = 0,
++	osc_dis_en = 1,
++	wakeup_rst_en = 2,
++	input_clamp_en = 3,
++	alive_osc_mode_en = 4,
++	power_off_en = 5,
++	pwm_switch_en = 6,
++	pwm_gpio_ioe_en = 7,
++	pwm_switch_io = 8,
++	pd_clk_src_gate_en = 9,
++};
++
++/* PMU_PLLPD_CON */
++enum pmu1_pllpd_con {
++	B0PLL_PD_EN,
++	B1PLL_PD_EN,
++	LPLL_PD_EN,
++	D0APLL_PD_EN,
++	D0BPLL_PD_EN,
++	D1APLL_PD_EN,
++	D1BPLL_PD_EN,
++	D2APLL_PD_EN,
++	D2BPLL_PD_EN,
++	D3APLL_PD_EN,
++	D3BPLL_PD_EN,
++	V0PLL_PD_EN,
++	AUPLL_PD_EN,
++	GPLL_PD_EN,
++	CPLL_PD_EN,
++	NPLL_PD_EN,
++	PPLL_PD_EN = 0,
++	SPLL_PD_EN = 1,
++};
++
++enum pmu1_wakeup_int {
++	WAKEUP_CPU0_INT_EN,
++	WAKEUP_CPU1_INT_EN,
++	WAKEUP_CPU2_INT_EN,
++	WAKEUP_CPU3_INT_EN,
++	WAKEUP_CPU4_INT_EN,
++	WAKEUP_CPU5_INT_EN,
++	WAKEUP_CPU6_INT_EN,
++	WAKEUP_CPU7_INT_EN,
++	WAKEUP_GPIO0_INT_EN,
++	WAKEUP_SDMMC_EN,
++	WAKEUP_SDIO_EN,
++	WAKEUP_USBDEV_EN,
++	WAKEUP_UART0_EN,
++	WAKEUP_VAD_EN,
++	WAKEUP_TIMER_EN,
++	WAKEUP_SOC_INT_EN,
++	WAKEUP_TIMEROUT_EN,
++	WAKEUP_PMUMCU_CEC_EN = 20,
++};
++
++enum pmu2_dsu_auto_pwr_con {
++	dsu_pm_en = 0,
++	dsu_pm_int_wakeup_en = 1,
++	dsu_pm_sft_wakeup_en = 3,
++};
++
++enum pmu2_cpu_auto_pwr_con {
++	cpu_pm_en = 0,
++	cpu_pm_int_wakeup_en = 1,
++	cpu_pm_sft_wakeup_en = 3,
++};
++
++enum pmu2_core_auto_pwr_con {
++	core_pm_en = 0,
++	core_pm_int_wakeup_en = 1,
++	core_pm_int_wakeup_glb_msk = 2,
++	core_pm_sft_wakeup_en = 3,
++};
++
++enum pmu2_dsu_power_con {
++	DSU_PWRDN_EN,
++	DSU_PWROFF_EN,
++	BIT_FULL_EN,
++	DSU_RET_EN,
++	CLUSTER_CLK_SRC_GT_EN,
++};
++
++enum pmu2_core_power_con {
++	CORE_PWRDN_EN,
++	CORE_PWROFF_EN,
++	CORE_CPU_PWRDN_EN,
++	CORE_PWR_CNT_EN,
++};
++
++enum pmu2_cluster_idle_con {
++	IDLE_REQ_BIGCORE0_EN = 0,
++	IDLE_REQ_BIGCORE1_EN = 2,
++	IDLE_REQ_DSU_EN = 4,
++	IDLE_REQ_LITDSU_EN = 5,
++	IDLE_REQ_ADB400_CORE_QCH_EN = 6,
++};
++
++enum qos_id {
++	QOS_ISP0_MWO = 0,
++	QOS_ISP0_MRO = 1,
++	QOS_ISP1_MWO = 2,
++	QOS_ISP1_MRO = 3,
++	QOS_VICAP_M0 = 4,
++	QOS_VICAP_M1 = 5,
++	QOS_FISHEYE0 = 6,
++	QOS_FISHEYE1 = 7,
++	QOS_VOP_M0 = 8,
++	QOS_VOP_M1 = 9,
++	QOS_RKVDEC0 = 10,
++	QOS_RKVDEC1 = 11,
++	QOS_AV1 = 12,
++	QOS_RKVENC0_M0RO = 13,
++	QOS_RKVENC0_M1RO = 14,
++	QOS_RKVENC0_M2WO = 15,
++	QOS_RKVENC1_M0RO = 16,
++	QOS_RKVENC1_M1RO = 17,
++	QOS_RKVENC1_M2WO = 18,
++	QOS_DSU_M0 = 19,
++	QOS_DSU_M1 = 20,
++	QOS_DSU_MP = 21,
++	QOS_DEBUG = 22,
++	QOS_GPU_M0 = 23,
++	QOS_GPU_M1 = 24,
++	QOS_GPU_M2 = 25,
++	QOS_GPU_M3 = 26,
++	QOS_NPU1 = 27,
++	QOS_NPU0_MRO = 28,
++	QOS_NPU2 = 29,
++	QOS_NPU0_MWR = 30,
++	QOS_MCU_NPU = 31,
++	QOS_JPEG_DEC = 32,
++	QOS_JPEG_ENC0 = 33,
++	QOS_JPEG_ENC1 = 34,
++	QOS_JPEG_ENC2 = 35,
++	QOS_JPEG_ENC3 = 36,
++	QOS_RGA2_MRO = 37,
++	QOS_RGA2_MWO = 38,
++	QOS_RGA3_0 = 39,
++	QOS_RGA3_1 = 40,
++	QOS_VDPU = 41,
++	QOS_IEP = 42,
++	QOS_HDCP0 = 43,
++	QOS_HDCP1 = 44,
++	QOS_HDMIRX = 45,
++	QOS_GIC600_M0 = 46,
++	QOS_GIC600_M1 = 47,
++	QOS_MMU600PCIE_TCU = 48,
++	QOS_MMU600PHP_TBU = 49,
++	QOS_MMU600PHP_TCU = 50,
++	QOS_USB3_0 = 51,
++	QOS_USB3_1 = 52,
++	QOS_USBHOST_0 = 53,
++	QOS_USBHOST_1 = 54,
++	QOS_EMMC = 55,
++	QOS_FSPI = 56,
++	QOS_SDIO = 57,
++	QOS_DECOM = 58,
++	QOS_DMAC0 = 59,
++	QOS_DMAC1 = 60,
++	QOS_DMAC2 = 61,
++	QOS_GIC600M = 62,
++	QOS_DMA2DDR = 63,
++	QOS_MCU_DDR = 64,
++	QOS_VAD = 65,
++	QOS_MCU_PMU = 66,
++	QOS_CRYPTOS = 67,
++	QOS_CRYPTONS = 68,
++	QOS_DCF = 69,
++	QOS_SDMMC = 70,
++};
++
++enum pmu2_pdid {
++	PD_GPU = 0,
++	PD_NPU = 1,
++	PD_VCODEC = 2,
++	PD_NPUTOP = 3,
++	PD_NPU1 = 4,
++	PD_NPU2 = 5,
++	PD_VENC0 = 6,
++	PD_VENC1 = 7,
++	PD_RKVDEC0 = 8,
++	PD_RKVDEC1 = 9,
++	PD_VDPU = 10,
++	PD_RGA30 = 11,
++	PD_AV1 = 12,
++	PD_VI = 13,
++	PD_FEC = 14,
++	PD_ISP1 = 15,
++	PD_RGA31 = 16,
++	PD_VOP = 17,
++	PD_VO0 = 18,
++	PD_VO1 = 19,
++	PD_AUDIO = 20,
++	PD_PHP = 21,
++	PD_GMAC = 22,
++	PD_PCIE = 23,
++	PD_NVM = 24,
++	PD_NVM0 = 25,
++	PD_SDIO = 26,
++	PD_USB = 27,
++	PD_SECURE = 28,
++	PD_SDMMC = 29,
++	PD_CRYPTO = 30,
++	PD_CENTER = 31,
++	PD_DDR01 = 32,
++	PD_DDR23 = 33,
++};
++
++enum pmu2_pd_repair_id {
++	PD_RPR_PMU = 0,
++	PD_RPR_GPU = 1,
++	PD_RPR_NPUTOP = 2,
++	PD_RPR_NPU1 = 3,
++	PD_RPR_NPU2 = 4,
++	PD_RPR_VENC0 = 5,
++	PD_RPR_VENC1 = 6,
++	PD_RPR_RKVDEC0 = 7,
++	PD_RPR_RKVDEC1 = 8,
++	PD_RPR_VDPU = 9,
++	PD_RPR_RGA30 = 10,
++	PD_RPR_AV1 = 11,
++	PD_RPR_VI = 12,
++	PD_RPR_FEC = 13,
++	PD_RPR_ISP1 = 14,
++	PD_RPR_RGA31 = 15,
++	PD_RPR_VOP = 16,
++	PD_RPR_VO0 = 17,
++	PD_RPR_VO1 = 18,
++	PD_RPR_AUDIO = 19,
++	PD_RPR_PHP = 20,
++	PD_RPR_GMAC = 21,
++	PD_RPR_PCIE = 22,
++	PD_RPR_NVM0 = 23,
++	PD_RPR_SDIO = 24,
++	PD_RPR_USB = 25,
++	PD_RPR_SDMMC = 26,
++	PD_RPR_CRYPTO = 27,
++	PD_RPR_CENTER = 28,
++	PD_RPR_DDR01 = 29,
++	PD_RPR_DDR23 = 30,
++	PD_RPR_BUS = 31,
++};
++
++enum pmu2_bus_id {
++	BUS_ID_GPU = 0,
++	BUS_ID_NPUTOP = 1,
++	BUS_ID_NPU1 = 2,
++	BUS_ID_NPU2 = 3,
++	BUS_ID_RKVENC0 = 4,
++	BUS_ID_RKVENC1 = 5,
++	BUS_ID_RKVDEC0 = 6,
++	BUS_ID_RKVDEC1 = 7,
++	BUS_ID_VDPU = 8,
++	BUS_ID_AV1 = 9,
++	BUS_ID_VI = 10,
++	BUS_ID_ISP = 11,
++	BUS_ID_RGA31 = 12,
++	BUS_ID_VOP = 13,
++	BUS_ID_VOP_CHANNEL = 14,
++	BUS_ID_VO0 = 15,
++	BUS_ID_VO1 = 16,
++	BUS_ID_AUDIO = 17,
++	BUS_ID_NVM = 18,
++	BUS_ID_SDIO = 19,
++	BUS_ID_USB = 20,
++	BUS_ID_PHP = 21,
++	BUS_ID_VO1USBTOP = 22,
++	BUS_ID_SECURE = 23,
++	BUS_ID_SECURE_CENTER_CHANNEL = 24,
++	BUS_ID_SECURE_VO1USB_CHANNEL = 25,
++	BUS_ID_CENTER = 26,
++	BUS_ID_CENTER_CHANNEL = 27,
++	BUS_ID_MSCH0 = 28,
++	BUS_ID_MSCH1 = 29,
++	BUS_ID_MSCH2 = 30,
++	BUS_ID_MSCH3 = 31,
++	BUS_ID_MSCH = 32,
++	BUS_ID_BUS = 33,
++	BUS_ID_TOP = 34,
++};
++
++enum pmu2_mem_st {
++	PD_NPU_TOP_MEM_ST = 11,
++	PD_NPU1_MEM_ST = 12,
++	PD_NPU2_MEM_ST = 13,
++	PD_VENC0_MEM_ST = 14,
++	PD_VENC1_MEM_ST = 15,
++	PD_RKVDEC0_MEM_ST = 16,
++	PD_RKVDEC1_MEM_ST = 17,
++	PD_RGA30_MEM_ST = 19,
++	PD_AV1_MEM_ST = 20,
++	PD_VI_MEM_ST = 21,
++	PD_FEC_MEM_ST = 22,
++	PD_ISP1_MEM_ST = 23,
++	PD_RGA31_MEM_ST = 24,
++	PD_VOP_MEM_ST = 25,
++	PD_VO0_MEM_ST = 26,
++	PD_VO1_MEM_ST = 27,
++	PD_AUDIO_MEM_ST = 28,
++	PD_PHP_MEM_ST = 29,
++	PD_GMAC_MEM_ST = 30,
++	PD_PCIE_MEM_ST = 31,
++	PD_NVM0_MEM_ST = 33,
++	PD_SDIO_MEM_ST = 34,
++	PD_USB_MEM_ST = 35,
++	PD_SDMMC_MEM_ST = 37,
++};
++
++enum pmu2_qid {
++	QID_PHPMMU_TBU = 0,
++	QID_PHPMMU_TCU = 1,
++	QID_PCIEMMU_TBU0 = 2,
++	QID_PCIEMU_TCU = 3,
++	QID_PHP_GICITS = 4,
++	QID_BUS_GICITS0 = 5,
++	QID_BUS_GICITS1 = 6,
++};
++
++/* PMU_DSU_PWR_CON */
++enum pmu_dsu_pwr_con {
++	DSU_PWRDN_ENA = 2,
++	DSU_PWROFF_ENA,
++	DSU_RET_ENA = 6,
++	CLUSTER_CLK_SRC_GATE_ENA,
++	DSU_PWR_CON_END
++};
++
++enum cpu_power_state {
++	CPU_POWER_ON,
++	CPU_POWER_OFF,
++	CPU_EMULATION_OFF,
++	CPU_RETENTION,
++	CPU_DEBUG
++};
++
++enum dsu_power_state {
++	DSU_POWER_ON,
++	CLUSTER_TRANSFER_IDLE,
++	DSU_POWER_DOWN,
++	DSU_OFF,
++	DSU_WAKEUP,
++	DSU_POWER_UP,
++	CLUSTER_TRANSFER_RESUME,
++	DSU_FUNCTION_RETENTION
++};
++
++/* PMU2_CLUSTER_STS 0x8080 */
++enum pmu2_cluster_sts_bits {
++	pd_cpu0_dwn = 0,
++	pd_cpu1_dwn,
++	pd_cpu2_dwn,
++	pd_cpu3_dwn,
++	pd_cpu4_dwn,
++	pd_cpu5_dwn,
++	pd_cpu6_dwn,
++	pd_cpu7_dwn,
++	pd_core0_dwn,
++	pd_core1_dwn
++};
++
++#define CLUSTER_STS_NONBOOT_CPUS_DWN	0xfe
++
++enum cpu_off_trigger {
++	CPU_OFF_TRIGGER_WFE = 0,
++	CPU_OFF_TRIGGER_REQ_EML,
++	CPU_OFF_TRIGGER_REQ_WFI,
++	CPU_OFF_TRIGGER_REQ_WFI_NBT_CPU,
++	CPU_OFF_TRIGGER_REQ_WFI_NBT_CPU_SRAM
++};
++
++/*****************************************************************************
++ * power domain on or off
++ *****************************************************************************/
++enum pmu_pd_state {
++	pmu_pd_on = 0,
++	pmu_pd_off = 1
++};
++
++enum bus_state {
++	bus_active,
++	bus_idle,
++};
++
++#define RK_CPU_STATUS_OFF		0
++#define RK_CPU_STATUS_ON		1
++#define RK_CPU_STATUS_BUSY		-1
++
++#define PD_CTR_LOOP			500
++#define MAX_WAIT_COUNT			500
++
++#define pmu_bus_idle_st(id)	\
++	(!!(mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ST((id) / 32)) & BIT((id) % 32)))
++
++#define pmu_bus_idle_ack(id)	\
++	(!!(mmio_read_32(PMU_BASE + PMU2_BUS_IDLE_ACK((id) / 32)) & BIT((id) % 32)))
++
++void pm_pll_wait_lock(uint32_t pll_base);
++#endif /* __PMU_H__ */
+diff --git a/plat/rockchip/rk3588/drivers/secure/secure.c b/plat/rockchip/rk3588/drivers/secure/secure.c
+new file mode 100644
+index 000000000..fc9f2114d
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/secure/secure.c
+@@ -0,0 +1,188 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <lib/mmio.h>
++
++#include <platform_def.h>
++
++#include <secure.h>
++#include <soc.h>
++
++static void secure_fw_master_init(void)
++{
++	uint32_t i;
++
++	/* ddr_mcu can access all ddr-regions */
++	mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_MST(1), 0x0000ffff);
++	/* dcf/crypto_s can access all ddr-regions */
++	mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_MST(14), 0x00000000);
++	/* dsu_mp_sec can access all ddr-regions.
++	 * DSU access memory [f000_0000~ff00_0000] through MP in firewall_ddr.
++	 */
++	mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_MST(36), 0xffff0000);
++
++	/* all other ns-master can't access all ddr-regions */
++	for (i = 0; i < FIREWALL_DDR_MST_CNT; i++) {
++		if (i == 1 || i == 14 || i == 36)
++			continue;
++
++		mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_MST(i), 0xffffffff);
++	}
++
++	/* mcu_pmu can access all sram-regions */
++	mmio_write_32(FIREWALL_SYSMEM_BASE + FIREWALL_SYSMEM_MST(19), 0x000000ff);
++	/* dsu mp-sec can access all sram-regions */
++	mmio_write_32(FIREWALL_SYSMEM_BASE + FIREWALL_SYSMEM_MST(38), 0x000000ff);
++	/* nsp_dsu2main_sec can access all sram-regions */
++	mmio_write_32(FIREWALL_SYSMEM_BASE + FIREWALL_SYSMEM_MST(41), 0x00000000);
++
++	/* all ns-master can't access all sram-regions */
++	for (i = 0; i < FIREWALL_SYSMEM_MST_CNT; i++) {
++		if (i == 19 || i == 38 || i == 41)
++			continue;
++
++		mmio_write_32(FIREWALL_SYSMEM_BASE + FIREWALL_SYSMEM_MST(i),
++			      0x00ff00ff);
++	}
++
++	/* dsu-ns can't access all ddr-regions, dsu-s can access all ddr-regions */
++	mmio_write_32(FIREWALL_DSU_BASE + FIREWALL_DSU_MST(0), 0xffffffff);
++	mmio_write_32(FIREWALL_DSU_BASE + FIREWALL_DSU_MST(1), 0x00000000);
++	dsb();
++	isb();
++}
++
++/* unit: Mb */
++static void dsu_fw_rgn_config(uint64_t base_mb, uint64_t top_mb, int rgn_id)
++{
++	int i;
++
++	if (rgn_id >= FIREWALL_DSU_RGN_CNT || rgn_id < 0) {
++		ERROR("%s regions-id:%d is invalid!\n", __func__, rgn_id);
++		panic();
++	}
++
++	mmio_write_32(FIREWALL_DSU_BASE + FIREWALL_DSU_RGN(rgn_id),
++		      RG_MAP_SECURE(top_mb, base_mb));
++
++	for (i = 0; i < DDR_CHN_CNT; i++)
++		mmio_setbits_32(FIREWALL_DSU_BASE + FIREWALL_DSU_CON(i),
++				BIT(rgn_id));
++}
++
++/* unit: Mb */
++static void ddr_fw_rgn_config(uint64_t base_mb, uint64_t top_mb, int rgn_id)
++{
++	if (rgn_id >= FIREWALL_DDR_RGN_CNT || rgn_id < 0) {
++		ERROR("%s regions-id:%d is invalid!\n", __func__, rgn_id);
++		panic();
++	}
++
++	mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_RGN(rgn_id),
++		      RG_MAP_SECURE(top_mb, base_mb));
++
++	/* enable region */
++	mmio_setbits_32(FIREWALL_DDR_BASE + FIREWALL_DDR_CON,
++			BIT(rgn_id));
++}
++
++/* Unit: Kb */
++static void sram_fw_rgn_config(uint64_t base_kb, uint64_t top_kb, int rgn_id)
++{
++	if (rgn_id >= FIREWALL_SYSMEM_RGN_CNT || rgn_id < 0) {
++		ERROR("%s regions-id:%d is invalid!\n", __func__, rgn_id);
++		panic();
++	}
++
++	mmio_write_32(FIREWALL_SYSMEM_BASE + FIREWALL_SYSMEM_RGN(rgn_id),
++		      RG_MAP_SRAM_SECURE(top_kb, base_kb));
++
++	/* enable region */
++	mmio_setbits_32(FIREWALL_SYSMEM_BASE + FIREWALL_SYSMEM_CON, BIT(rgn_id));
++}
++
++static void secure_region_init(void)
++{
++	uint32_t i;
++
++	/* disable all region first except region0 */
++	mmio_clrbits_32(FIREWALL_DDR_BASE + FIREWALL_DDR_CON, 0xfffe);
++	for (i = 0; i < FIREWALL_DSU_CON_CNT; i++)
++		mmio_clrbits_32(FIREWALL_DSU_BASE + FIREWALL_DSU_CON(i), 0xfffe);
++	mmio_clrbits_32(FIREWALL_SYSMEM_BASE + FIREWALL_SYSMEM_CON, 0xfe);
++
++	secure_fw_master_init();
++
++	/* Use FW_DDR_RGN0_REG to config 0~1M space to secure */
++	dsu_fw_rgn_config(0, 1, 0);
++	ddr_fw_rgn_config(0, 1, 0);
++
++	/* Use FIREWALL_SYSMEM_RGN0 to config SRAM_ENTRY code(0~4k of sram) to secure */
++	sram_fw_rgn_config(0, 4, 0);
++	/* For 0xffff0000~0xffffffff, use FIREWALL_SYSMEM_RGN7 to config
++	 * 960~1024k of sram to secure.
++	 */
++	sram_fw_rgn_config(960, 1024, 7);
++}
++
++void secure_timer_init(void)
++{
++	/* gpu's cntvalue comes from stimer1 channel_5 */
++	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
++		      TIMER_DIS);
++
++	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_LOAD_COUNT0, 0xffffffff);
++	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_LOAD_COUNT1, 0xffffffff);
++
++	/* auto reload & enable the timer */
++	mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG,
++		      TIMER_EN | TIMER_FMODE);
++}
++
++void sgrf_init(void)
++{
++	uint32_t i;
++
++	secure_region_init();
++
++	/* config master ddr_mcu_prot|dcf_wr|dcf_rd as secure */
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(14), 0x001f0011);
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(15), 0xffffffff);
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(16), 0x03ff03ff);
++
++	/* config slave mailbox_mcu_ddr as secure */
++	mmio_write_32(BUSSGRF_BASE + SGRF_FIREWALL_CON(4), 0xffff2000);
++	/* config slave int256mux4_mcu_ddr|int256mux4_mcu_pmu as secure */
++	mmio_write_32(BUSSGRF_BASE + SGRF_FIREWALL_CON(5), 0xffff0060);
++	/* config slave ddrgrf*|dma2ddr|ddrphy*_cru|umctl* as secure */
++	mmio_write_32(BUSSGRF_BASE + SGRF_FIREWALL_CON(24), 0xffff0fbf);
++	/* config slave ddrphy*|ddr_stanby*|ddr_mcu_timer|ddr_mcu_wdt as secure */
++	mmio_write_32(BUSSGRF_BASE + SGRF_FIREWALL_CON(25), 0xffff03ff);
++
++	/* config all other slave as ns */
++	for (i = 0; i < SGRF_FIREWALL_CON_CNT; i++) {
++		if (i == 4 || i == 5 || i == 24 || i == 25)
++			continue;
++
++		mmio_write_32(BUSSGRF_BASE + SGRF_FIREWALL_CON(i), 0xffff0000);
++	}
++
++	/* config vad_hprot non-secure, pmu_mcu_hprot as secure */
++	mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00180010);
++	/* config pmu1, pmu0, pmu_sram as secure */
++	mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(1), 0xefbe6020);
++	/* config remap_pmu_mem, h_pmu_mem as secure */
++	mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(2), 0x01f900c0);
++
++	/* disable dp encryption */
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(13), 0x00180018);
++
++	/* select grf config for pcie ats */
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(17), 0x11111111);
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(18), 0x11111111);
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(19), 0x00110011);
++}
+diff --git a/plat/rockchip/rk3588/drivers/secure/secure.h b/plat/rockchip/rk3588/drivers/secure/secure.h
+new file mode 100644
+index 000000000..d9c234fd5
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/secure/secure.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef SECURE_H
++#define SECURE_H
++
++/* DSUSGRF */
++#define DSU_SGRF_SOC_CON(i)		((i) * 4)
++#define DSUSGRF_SOC_CON(i)		((i) * 4)
++#define DSUSGRF_SOC_CON_CNT		13
++#define DSUSGRF_DDR_HASH_CON(i)		(0x240 + (i) * 4)
++#define DSUSGRF_DDR_HASH_CON_CNT	8
++
++/* PMUSGRF */
++#define PMU1SGRF_SOC_CON(n)		((n) * 4)
++
++/* SGRF */
++#define SGRF_SOC_CON(i)			((i) * 4)
++#define SGRF_FIREWALL_CON(i)		(0x240 + (i) * 4)
++#define SGRF_FIREWALL_CON_CNT		32
++
++/* ddr firewall */
++#define FIREWALL_DDR_RGN(i)		((i) * 0x4)
++#define FIREWALL_DDR_RGN_CNT		16
++#define FIREWALL_DDR_MST(i)		(0x40 + (i) * 0x4)
++#define FIREWALL_DDR_MST_CNT		42
++#define FIREWALL_DDR_CON		0xf0
++
++#define FIREWALL_SYSMEM_RGN(i)		((i) * 0x4)
++#define FIREWALL_SYSMEM_RGN_CNT		8
++#define FIREWALL_SYSMEM_MST(i)		(0x40 + (i) * 0x4)
++#define FIREWALL_SYSMEM_MST_CNT		43
++#define FIREWALL_SYSMEM_CON		0xf0
++
++#define FIREWALL_DSU_RGN(i)		((i) * 0x4)
++#define FIREWALL_DSU_RGN_CNT		16
++#define FIREWALL_DSU_MST(i)		(0x40 + (i) * 0x4)
++#define FIREWALL_DSU_MST_CNT		2
++#define FIREWALL_DSU_CON(i)		(0xf0 + (i) * 4)
++#define FIREWALL_DSU_CON_CNT		4
++
++#define PLAT_MAX_DDR_CAPACITY_MB	0x8000	/* for 32Gb */
++#define RG_MAP_SECURE(top, base)	\
++	(((((top) - 1) & 0x7fff) << 16) | ((base) & 0x7fff))
++#define RG_MAP_SRAM_SECURE(top_kb, base_kb)	\
++	(((((top_kb) / 4 - 1) & 0xff) << 16) | ((base_kb) / 4 & 0xff))
++
++void secure_timer_init(void);
++void sgrf_init(void);
++
++#endif /* SECURE_H */
+diff --git a/plat/rockchip/rk3588/drivers/soc/soc.c b/plat/rockchip/rk3588/drivers/soc/soc.c
+new file mode 100644
+index 000000000..a2768594c
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/soc/soc.c
+@@ -0,0 +1,96 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <arch_helpers.h>
++#include <bl31/bl31.h>
++#include <common/debug.h>
++#include <drivers/console.h>
++#include <drivers/delay_timer.h>
++#include <lib/mmio.h>
++#include <lib/xlat_tables/xlat_tables_compat.h>
++#include <platform.h>
++#include <platform_def.h>
++#include <pmu.h>
++
++#include <plat_private.h>
++#include <secure.h>
++#include <soc.h>
++
++#define RK3588_DEV_RNG0_BASE	0xf0000000
++#define RK3588_DEV_RNG0_SIZE	0x0ffff000
++
++const mmap_region_t plat_rk_mmap[] = {
++	MAP_REGION_FLAT(RK3588_DEV_RNG0_BASE, RK3588_DEV_RNG0_SIZE,
++			MT_DEVICE | MT_RW | MT_SECURE),
++	MAP_REGION_FLAT(DDR_SHARE_MEM, DDR_SHARE_SIZE,
++			MT_DEVICE | MT_RW | MT_NS),
++	{ 0 }
++};
++
++/* The RockChip power domain tree descriptor */
++const unsigned char rockchip_power_domain_tree_desc[] = {
++	/* No of root nodes */
++	PLATFORM_SYSTEM_COUNT,
++	/* No of children for the root node */
++	PLATFORM_CLUSTER_COUNT,
++	/* No of children for the first cluster node */
++	PLATFORM_CLUSTER0_CORE_COUNT,
++	/* No of children for the second cluster node */
++	PLATFORM_CLUSTER1_CORE_COUNT
++};
++
++void timer_hp_init(void)
++{
++	if ((mmio_read_32(TIMER_HP_BASE + TIMER_HP_CTRL) & 0x1) != 0)
++		return;
++
++	mmio_write_32(TIMER_HP_BASE + TIMER_HP_CTRL, 0x0);
++	dsb();
++	mmio_write_32(TIMER_HP_BASE + TIMER_HP_LOAD_COUNT0, 0xffffffff);
++	mmio_write_32(TIMER_HP_BASE + TIMER_HP_LOAD_COUNT1, 0xffffffff);
++	mmio_write_32(TIMER_HP_BASE + TIMER_HP_INT_EN, 0);
++	dsb();
++	mmio_write_32(TIMER_HP_BASE + TIMER_HP_CTRL, 0x1);
++}
++
++static void system_reset_init(void)
++{
++	/* enable wdt_ns0~4 trigger global reset and select first reset.
++	 * enable tsadc trigger global reset and select first reset.
++	 * enable global reset and wdt trigger pmu reset.
++	 * select first reset trigger pmu reset.s
++	 */
++	mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, 0xffdf);
++
++	/* enable wdt_s, wdt_ns reset */
++	mmio_write_32(BUSSGRF_BASE + SGRF_SOC_CON(2), 0x0c000c00);
++
++	/* reset width = 0xffff */
++	mmio_write_32(PMU1GRF_BASE + PMU1GRF_SOC_CON(1), 0xffffffff);
++
++	/* enable first/tsadc/wdt reset output */
++	mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(0), 0x00070007);
++
++	/* pmu1_grf pmu1_ioc hold */
++	mmio_write_32(PMU1GRF_BASE + PMU1GRF_SOC_CON(7), 0x30003000);
++
++	/* pmu1sgrf hold */
++	mmio_write_32(PMU1SGRF_BASE + PMU1SGRF_SOC_CON(14), 0x00200020);
++
++	/* select tsadc_shut_m0 ionmux*/
++	mmio_write_32(PMU0IOC_BASE + 0x0, 0x00f00020);
++}
++
++void plat_rockchip_soc_init(void)
++{
++	secure_timer_init();
++	timer_hp_init();
++	system_reset_init();
++	sgrf_init();
++}
+diff --git a/plat/rockchip/rk3588/drivers/soc/soc.h b/plat/rockchip/rk3588/drivers/soc/soc.h
+new file mode 100644
+index 000000000..9af179a4b
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/soc/soc.h
+@@ -0,0 +1,198 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __SOC_H__
++#define __SOC_H__
++
++enum pll_id {
++	APLL_ID,
++	DPLL_ID,
++	GPLL_ID,
++	CPLL_ID,
++	NPLL_ID,
++	VPLL_ID,
++};
++
++enum pmu_pll_id {
++	PPLL_ID = 0,
++	HPLL_ID
++};
++
++enum cru_mode_con00 {
++	CLK_APLL,
++	CLK_DPLL,
++	CLK_CPLL,
++	CLK_GPLL,
++	CLK_REVSERVED,
++	CLK_NPLL,
++	CLK_VPLL,
++	CLK_USBPLL,
++};
++
++#define KHz				1000
++#define MHz				(1000 * KHz)
++#define OSC_HZ				(24 * MHz)
++
++/* CRU */
++#define GLB_SRST_FST_CFG_VAL		0xfdb9
++
++#define CRU_PLLS_CON(pll_id, i)		(0x160 + (pll_id) * 0x20 + (i) * 0x4)
++#define CRU_PLL_CON(i)			((i) * 0x4)
++#define CRU_MODE_CON0			0x280
++#define CRU_CLKSEL_CON(i)		((i) * 0x4 + 0x300)
++#define CRU_CLKGATE_CON(i)		((i) * 0x4 + 0x800)
++#define CRU_CLKGATE_CON_CNT		78
++#define CRU_SOFTRST_CON(i)		((i) * 0x4 + 0xa00)
++#define CRU_GLB_CNT_TH			0xc00
++#define CRU_GLB_SRST_FST		0xc08
++#define CRU_GLB_SRST_SND		0xc0c
++#define CRU_GLB_RST_CON			0xc10
++#define CRU_GLB_RST_ST			0xc04
++#define CRU_SDIO_CON0			0xc24
++#define CRU_SDIO_CON1			0xc28
++#define CRU_SDMMC_CON0			0xc30
++#define CRU_SDMMC_CON1			0xc34
++#define CRU_AUTOCS_CON0(id)		(0xd00 + (id) * 8)
++#define CRU_AUTOCS_CON1(id)		(0xd04 + (id) * 8)
++
++#define CRU_AUTOCS_ID_CNT		74
++
++#define CRU_PLLCON0_M_MASK		0x3ff
++#define CRU_PLLCON0_M_SHIFT		0
++#define CRU_PLLCON1_P_MASK		0x3f
++#define CRU_PLLCON1_P_SHIFT		0
++#define CRU_PLLCON1_S_MASK		0x7
++#define CRU_PLLCON1_S_SHIFT		6
++#define CRU_PLLCON2_K_MASK		0xffff
++#define CRU_PLLCON2_K_SHIFT		0
++#define CRU_PLLCON1_PWRDOWN		BIT(13)
++#define CRU_PLLCON6_LOCK_STATUS		BIT(15)
++
++#define CRU_BIGCPU02_RST_MSK		0x30
++#define CRU_BIGCPU13_RST_MSK		0x300
++
++#define PHPCRU_CLKGATE_CON		0x800
++#define PHPCRU_CLKGATE_CON_CNT		1
++
++#define SECURECRU_CLKGATE_CON(i)	((i) * 0x4 + 0x800)
++#define SECURECRU_CLKGATE_CON_CNT	4
++
++#define PMU1CRU_CLKGATE_CON_CNT		6
++
++/* CENTER GRF */
++#define CENTER_GRF_CON(i)		((i) * 4)
++
++/* PMU1GRF */
++#define PMU1GRF_SOC_CON(n)		((n) * 4)
++#define PMU1GRF_SOC_ST			0x60
++#define PMU1GRF_OS_REG(n)		(0x200 + ((n) * 4))
++
++#define PMU_MCU_HALT			BIT(7)
++#define PMU_MCU_SLEEP			BIT(9)
++#define PMU_MCU_DEEPSLEEP		BIT(10)
++#define PMU_MCU_STOP_MSK		\
++	(PMU_MCU_HALT | PMU_MCU_SLEEP | PMU_MCU_DEEPSLEEP)
++
++/* SYSGRF */
++#define SYS_GRF_NOC_CON(n)		(0x100 + (n) * 4)
++#define SYS_GRF_SOC_CON(n)		(0x300 + (n) * 4)
++#define SYS_GRF_SOC_STATUS(n)		(0x380 + (n) * 4)
++
++#define SYS_GRF_LITTLE_CPUS_WFE		0xf
++#define SYS_GRF_CORE0_CPUS_WFE		0x30
++#define SYS_GRF_CORE1_CPUS_WFE		0xc0
++#define SYS_GRF_BIG_CPUS_WFE		0xf0
++#define SYS_GRF_LITTLE_CPUS_WFI		0xf00
++#define SYS_GRF_CORE0_CPUS_WFI		0x3000
++#define SYS_GRF_CORE1_CPUS_WFI		0xc000
++
++/* pvtm */
++#define PVTM_CON(i)			(0x4 + (i) * 4)
++#define PVTM_INTEN			0x70
++#define PVTM_INTSTS			0x74
++#define PVTM_STATUS(i)			(0x80 + (i) * 4)
++#define PVTM_CALC_CNT			0x200
++
++enum pvtm_con0 {
++	pvtm_start = 0,
++	pvtm_osc_en = 1,
++	pvtm_osc_sel = 2,
++	pvtm_rnd_seed_en = 5,
++};
++
++/* timer */
++#define TIMER_LOAD_COUNT0		0x00
++#define TIMER_LOAD_COUNT1		0x04
++#define TIMER_CURRENT_VALUE0		0x08
++#define TIMER_CURRENT_VALUE1		0x0c
++#define TIMER_CONTROL_REG		0x10
++#define TIMER_INTSTATUS			0x18
++
++#define TIMER_DIS			0x0
++#define TIMER_EN			0x1
++
++#define TIMER_FMODE			(0x0 << 1)
++#define TIMER_RMODE			(0x1 << 1)
++
++#define STIMER0_CHN_BASE(n)		(STIMER0_BASE + 0x20 * (n))
++#define STIMER1_CHN_BASE(n)		(STIMER1_BASE + 0x20 * (n))
++
++/* cpu timer */
++#define TIMER_HP_REVISION		0x0
++#define TIMER_HP_CTRL			0x4
++#define TIMER_HP_INT_EN			0x8
++#define TIMER_HP_T24_GCD		0xc
++#define TIMER_HP_T32_GCD		0x10
++#define TIMER_HP_LOAD_COUNT0		0x14
++#define TIMER_HP_LOAD_COUNT1		0x18
++#define TIMER_HP_T24_DELAT_COUNT0	0x1c
++#define TIMER_HP_T24_DELAT_COUNT1	0x20
++#define TIMER_HP_CURR_32K_VALUE0	0x24
++#define TIMER_HP_CURR_32K_VALUE1	0x28
++#define TIMER_HP_CURR_TIMER_VALUE0	0x2c
++#define TIMER_HP_CURR_TIMER_VALUE1	0x30
++#define TIMER_HP_T24_32BEGIN0		0x34
++#define TIMER_HP_T24_32BEGIN1		0x38
++#define TIMER_HP_T32_24END0		0x3c
++#define TIMER_HP_T32_24END1		0x40
++#define TIMER_HP_BEGIN_END_VALID	0x44
++#define TIMER_HP_SYNC_REQ		0x48
++#define TIMER_HP_INTR_STATUS		0x4c
++
++ /* GPIO */
++#define GPIO_SWPORT_DR_L		0x0000
++#define GPIO_SWPORT_DR_H		0x0004
++#define GPIO_SWPORT_DDR_L		0x0008
++#define GPIO_SWPORT_DDR_H		0x000c
++#define GPIO_INT_EN_L			0x0010
++#define GPIO_INT_EN_H			0x0014
++#define GPIO_INT_MASK_L			0x0018
++#define GPIO_INT_MASK_H			0x001c
++#define GPIO_INT_TYPE_L			0x0020
++#define GPIO_INT_TYPE_H			0x0024
++#define GPIO_INT_POLARITY_L		0x0028
++#define GPIO_INT_POLARITY_H		0x002c
++#define GPIO_INT_BOTHEDGE_L		0x0030
++#define GPIO_INT_BOTHEDGE_H		0x0034
++#define GPIO_DEBOUNCE_L			0x0038
++#define GPIO_DEBOUNCE_H			0x003c
++#define GPIO_DBCLK_DIV_EN_L		0x0040
++#define GPIO_DBCLK_DIV_EN_H		0x0044
++#define GPIO_DBCLK_DIV_CON		0x0048
++#define GPIO_INT_STATUS			0x0050
++#define GPIO_INT_RAWSTATUS		0x0058
++#define GPIO_PORT_EOI_L			0x0060
++#define GPIO_PORT_EOI_H			0x0064
++#define GPIO_EXT_PORT			0x0070
++#define GPIO_VER_ID			0x0078
++
++/* DDRGRF */
++#define DDRGRF_CHA_CON(i)		((i) * 4)
++#define DDRGRF_CHB_CON(i)		(0x30 + (i) * 4)
++
++#define DDR_CHN_CNT			4
++
++#endif /* __SOC_H__ */
+diff --git a/plat/rockchip/rk3588/include/plat.ld.S b/plat/rockchip/rk3588/include/plat.ld.S
+new file mode 100644
+index 000000000..e3ea9ccf8
+--- /dev/null
++++ b/plat/rockchip/rk3588/include/plat.ld.S
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef ROCKCHIP_PLAT_LD_S
++#define ROCKCHIP_PLAT_LD_S
++
++MEMORY {
++        PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE
++}
++
++SECTIONS
++{
++	. = PMUSRAM_BASE;
++
++	/*
++	 * pmu_cpuson_entrypoint request address
++	 * align 64K when resume, so put it in the
++	 * start of pmusram
++	 */
++	.text_pmusram : {
++		ASSERT(. == ALIGN(64 * 1024),
++			".pmusram.entry request 64K aligned.");
++		 KEEP(*(.pmusram.entry))
++		__bl31_pmusram_text_start = .;
++		*(.pmusram.text)
++		*(.pmusram.rodata)
++		. = ALIGN(PAGE_SIZE);
++		__bl31_pmusram_text_end = .;
++		__bl31_pmusram_data_start = .;
++		*(.pmusram.data)
++		. = ALIGN(PAGE_SIZE);
++		__bl31_pmusram_data_end = .;
++
++		ASSERT(__bl31_pmusram_data_end <= PMUSRAM_BASE + PMUSRAM_RSIZE,
++			".pmusram has exceeded its limit.");
++	} >PMUSRAM
++}
++
++#endif /* ROCKCHIP_PLAT_LD_S */
+diff --git a/plat/rockchip/rk3588/include/plat_sip_calls.h b/plat/rockchip/rk3588/include/plat_sip_calls.h
+new file mode 100644
+index 000000000..bc4455f99
+--- /dev/null
++++ b/plat/rockchip/rk3588/include/plat_sip_calls.h
+@@ -0,0 +1,12 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PLAT_SIP_CALLS_H__
++#define __PLAT_SIP_CALLS_H__
++
++#define RK_PLAT_SIP_NUM_CALLS	0
++
++#endif /* __PLAT_SIP_CALLS_H__ */
+diff --git a/plat/rockchip/rk3588/include/platform_def.h b/plat/rockchip/rk3588/include/platform_def.h
+new file mode 100644
+index 000000000..5946af0b5
+--- /dev/null
++++ b/plat/rockchip/rk3588/include/platform_def.h
+@@ -0,0 +1,119 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PLATFORM_DEF_H__
++#define __PLATFORM_DEF_H__
++
++#include <arch.h>
++#include <plat/common/common_def.h>
++
++#include <rk3588_def.h>
++
++#define DEBUG_XLAT_TABLE 0
++
++/*******************************************************************************
++ * Platform binary types for linking
++ ******************************************************************************/
++#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
++#define PLATFORM_LINKER_ARCH		aarch64
++
++/*******************************************************************************
++ * Generic platform constants
++ ******************************************************************************/
++
++/* Size of cacheable stacks */
++#if DEBUG_XLAT_TABLE
++#define PLATFORM_STACK_SIZE 0x800
++#elif IMAGE_BL1
++#define PLATFORM_STACK_SIZE 0x440
++#elif IMAGE_BL2
++#define PLATFORM_STACK_SIZE 0x400
++#elif IMAGE_BL31
++#define PLATFORM_STACK_SIZE 0x800
++#elif IMAGE_BL32
++#define PLATFORM_STACK_SIZE 0x440
++#endif
++
++#define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
++
++#define PLATFORM_SYSTEM_COUNT		1
++#define PLATFORM_CLUSTER_COUNT		1
++#define PLATFORM_CLUSTER0_CORE_COUNT	8
++#define PLATFORM_CLUSTER1_CORE_COUNT	0
++#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER1_CORE_COUNT +	\
++					 PLATFORM_CLUSTER0_CORE_COUNT)
++
++#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT +	\
++					 PLATFORM_CLUSTER_COUNT +	\
++					 PLATFORM_CORE_COUNT)
++
++#define PLAT_MAX_PWR_LVL		MPIDR_AFFLVL2
++
++#define PLAT_RK_CLST_TO_CPUID_SHIFT	8
++
++/*
++ * This macro defines the deepest retention state possible. A higher state
++ * id will represent an invalid or a power down state.
++ */
++#define PLAT_MAX_RET_STATE		1
++
++/*
++ * This macro defines the deepest power down states possible. Any state ID
++ * higher than this is invalid.
++ */
++#define PLAT_MAX_OFF_STATE		2
++/*******************************************************************************
++ * Platform memory map related constants
++ ******************************************************************************/
++/* TF txet, ro, rw, Size: 512KB */
++#define TZRAM_BASE		(0x0)
++#define TZRAM_SIZE		(0x100000)
++
++/*******************************************************************************
++ * BL31 specific defines.
++ ******************************************************************************/
++/*
++ * Put BL3-1 at the top of the Trusted RAM
++ */
++#define BL31_BASE		(TZRAM_BASE + 0x40000)
++#define BL31_LIMIT		(TZRAM_BASE + TZRAM_SIZE)
++
++/*******************************************************************************
++ * Platform specific page table and MMU setup constants
++ ******************************************************************************/
++#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32)
++#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
++
++#define ADDR_SPACE_SIZE			(1ULL << 32)
++#define MAX_XLAT_TABLES			18
++#define MAX_MMAP_REGIONS		27
++
++/*******************************************************************************
++ * Declarations and constants to access the mailboxes safely. Each mailbox is
++ * aligned on the biggest cache line size in the platform. This is known only
++ * to the platform as it might have a combination of integrated and external
++ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
++ * line at any cache level. They could belong to different cpus/clusters &
++ * get written while being protected by different locks causing corruption of
++ * a valid mailbox address.
++ ******************************************************************************/
++#define CACHE_WRITEBACK_SHIFT	6
++#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
++
++/*
++ * Define GICD and GICC and GICR base
++ */
++#define PLAT_RK_GICD_BASE	PLAT_GICD_BASE
++#define PLAT_RK_GICC_BASE	PLAT_GICC_BASE
++#define PLAT_RK_GICR_BASE	PLAT_GICR_BASE
++
++#define PLAT_RK_UART_BASE	RK_DBG_UART_BASE
++#define PLAT_RK_UART_CLOCK	RK_DBG_UART_CLOCK
++#define PLAT_RK_UART_BAUDRATE	RK_DBG_UART_BAUDRATE
++
++#define PLAT_RK_PRIMARY_CPU	0x0
++
++#endif /* __PLATFORM_DEF_H__ */
+diff --git a/plat/rockchip/rk3588/plat_sip_calls.c b/plat/rockchip/rk3588/plat_sip_calls.c
+new file mode 100644
+index 000000000..57f5de507
+--- /dev/null
++++ b/plat/rockchip/rk3588/plat_sip_calls.c
+@@ -0,0 +1,27 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <common/debug.h>
++#include <common/runtime_svc.h>
++
++#include <plat_sip_calls.h>
++#include <rockchip_sip_svc.h>
++
++uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
++				    u_register_t x1,
++				    u_register_t x2,
++				    u_register_t x3,
++				    u_register_t x4,
++				    void *cookie,
++				    void *handle,
++				    u_register_t flags)
++{
++	switch (smc_fid) {
++	default:
++		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
++		SMC_RET1(handle, SMC_UNK);
++	}
++}
+diff --git a/plat/rockchip/rk3588/platform.mk b/plat/rockchip/rk3588/platform.mk
+new file mode 100644
+index 000000000..f98781530
+--- /dev/null
++++ b/plat/rockchip/rk3588/platform.mk
+@@ -0,0 +1,85 @@
++#
++# Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++#
++# SPDX-License-Identifier: BSD-3-Clause
++#
++
++RK_PLAT			:=	plat/rockchip
++RK_PLAT_SOC		:=	${RK_PLAT}/${PLAT}
++RK_PLAT_COMMON		:=	${RK_PLAT}/common
++
++DISABLE_BIN_GENERATION	:=	1
++include lib/libfdt/libfdt.mk
++include lib/xlat_tables_v2/xlat_tables.mk
++
++# GIC-600 configuration
++GICV3_IMPL		:=	GIC600
++GICV3_SUPPORT_GIC600   	:=      1
++
++# Include GICv3 driver files
++include drivers/arm/gic/v3/gicv3.mk
++
++PLAT_INCLUDES		:=	-Iinclude/plat/common				\
++				-Idrivers/arm/gic/v3/				\
++				-I${RK_PLAT_COMMON}/				\
++				-I${RK_PLAT_COMMON}/drivers/pmu/		\
++				-I${RK_PLAT_COMMON}/drivers/parameter/		\
++				-I${RK_PLAT_COMMON}/include/			\
++				-I${RK_PLAT_COMMON}/pmusram/			\
++				-I${RK_PLAT_SOC}/				\
++				-I${RK_PLAT_SOC}/drivers/pmu/			\
++				-I${RK_PLAT_SOC}/drivers/secure/		\
++				-I${RK_PLAT_SOC}/drivers/soc/			\
++				-I${RK_PLAT_SOC}/include/
++
++RK_GIC_SOURCES		:=	${GICV3_SOURCES}				\
++				plat/common/plat_gicv3.c			\
++				${RK_PLAT}/common/rockchip_gicv3.c
++
++PLAT_BL_COMMON_SOURCES	:=	${XLAT_TABLES_LIB_SRCS}				\
++				common/desc_image_load.c			\
++				plat/common/aarch64/crash_console_helpers.S	\
++				lib/bl_aux_params/bl_aux_params.c		\
++				plat/common/plat_psci_common.c
++
++ifneq (${ENABLE_STACK_PROTECTOR},0)
++PLAT_BL_COMMON_SOURCES	+=	${RK_PLAT_COMMON}/rockchip_stack_protector.c
++endif
++
++BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
++				drivers/ti/uart/aarch64/16550_console.S		\
++				drivers/delay_timer/delay_timer.c		\
++				drivers/delay_timer/generic_delay_timer.c	\
++				lib/cpus/aarch64/cortex_a55.S			\
++				lib/cpus/aarch64/cortex_a76.S			\
++				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
++				${RK_PLAT_COMMON}/aarch64/platform_common.c	\
++				${RK_PLAT_COMMON}/bl31_plat_setup.c		\
++				${RK_PLAT_COMMON}/plat_pm.c			\
++				${RK_PLAT_COMMON}/plat_pm_helpers.c		\
++				${RK_PLAT_COMMON}/plat_topology.c		\
++				${RK_PLAT_COMMON}/params_setup.c                \
++				${RK_PLAT_COMMON}/pmusram/cpus_on_fixed_addr.S	\
++				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
++				${RK_PLAT_SOC}/plat_sip_calls.c         	\
++				${RK_PLAT_SOC}/drivers/secure/secure.c		\
++				${RK_PLAT_SOC}/drivers/soc/soc.c		\
++				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
++				${RK_PLAT_SOC}/drivers/pmu/pm_pd_regs.c
++
++CTX_INCLUDE_AARCH32_REGS :=     0
++ENABLE_PLAT_COMPAT	:=	0
++MULTI_CONSOLE_API	:=	1
++ERRATA_A55_1530923	:=	1
++
++# System coherency is managed in hardware
++HW_ASSISTED_COHERENCY	:=	1
++
++# When building for systems with hardware-assisted coherency, there's no need to
++# use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too.
++USE_COHERENT_MEM	:=	0
++
++ENABLE_SPE_FOR_LOWER_ELS	:= 0
++
++$(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT))
++$(eval $(call add_define,PLAT_SKIP_DFS_TLB_DCACHE_MAINTENANCE))
+diff --git a/plat/rockchip/rk3588/rk3588_def.h b/plat/rockchip/rk3588/rk3588_def.h
+new file mode 100644
+index 000000000..75b685a0a
+--- /dev/null
++++ b/plat/rockchip/rk3588/rk3588_def.h
+@@ -0,0 +1,221 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __PLAT_DEF_H__
++#define __PLAT_DEF_H__
++
++#define SIZE_K(n)		((n) * 1024)
++
++#define WITH_16BITS_WMSK(bits)	(0xffff0000 | (bits))
++
++/* Special value used to verify platform parameters from BL2 to BL3-1 */
++#define RK_BL31_PLAT_PARAM_VAL	0x0f1e2d3c4b5a6978ULL
++
++#define UMCTL0_BASE		0xf7000000
++#define UMCTL1_BASE		0xf8000000
++#define UMCTL2_BASE		0xf9000000
++#define UMCTL3_BASE		0xfa000000
++
++#define GIC600_BASE		0xfe600000
++#define GIC600_SIZE		SIZE_K(64)
++
++#define DAPLITE_BASE		0xfd100000
++#define PMU0SGRF_BASE		0xfd580000
++#define PMU1SGRF_BASE		0xfd582000
++#define BUSSGRF_BASE		0xfd586000
++#define DSUSGRF_BASE		0xfd587000
++#define PMU0GRF_BASE		0xfd588000
++#define PMU1GRF_BASE		0xfd58a000
++
++#define SYSGRF_BASE		0xfd58c000
++#define BIGCORE0GRF_BASE	0xfd590000
++#define BIGCORE1GRF_BASE	0xfd592000
++#define LITCOREGRF_BASE		0xfd594000
++#define DSUGRF_BASE		0xfd598000
++#define DDR01GRF_BASE		0xfd59c000
++#define DDR23GRF_BASE		0xfd59d000
++#define CENTERGRF_BASE		0xfd59e000
++#define GPUGRF_BASE		0xfd5a0000
++#define NPUGRF_BASE		0xfd5a2000
++#define USBGRF_BASE		0xfd5ac000
++#define PHPGRF_BASE		0xfd5b0000
++#define PCIE3PHYGRF_BASE	0xfd5b8000
++#define USB2PHY0_GRF_BASE	0xfd5d0000
++#define USB2PHY1_GRF_BASE	0xfd5d4000
++#define USB2PHY2_GRF_BASE	0xfd5d8000
++#define USB2PHY3_GRF_BASE	0xfd5dc000
++
++#define PMU0IOC_BASE		0xfd5f0000
++#define PMU1IOC_BASE		0xfd5f4000
++#define BUSIOC_BASE		0xfd5f8000
++#define VCCIO1_4_IOC_BASE	0xfd5f9000
++#define VCCIO3_5_IOC_BASE	0xfd5fa000
++#define VCCIO2_IOC_BASE		0xfd5fb000
++#define VCCIO6_IOC_BASE		0xfd5fc000
++
++#define SRAM_BASE		0xff000000
++#define PMUSRAM_BASE		0xff100000
++#define PMUSRAM_SIZE		SIZE_K(128)
++#define PMUSRAM_RSIZE		SIZE_K(64)
++
++#define CRU_BASE		0xfd7c0000
++#define PHP_CRU_BASE		0xfd7c8000
++#define SCRU_BASE		0xfd7d0000
++#define BUSSCRU_BASE		0xfd7d8000
++#define PMU1SCRU_BASE		0xfd7e0000
++#define PMU1CRU_BASE		0xfd7f0000
++
++#define DDR0CRU_BASE		0xfd800000
++#define DDR1CRU_BASE		0xfd804000
++#define DDR2CRU_BASE		0xfd808000
++#define DDR3CRU_BASE		0xfd80c000
++
++#define BIGCORE0CRU_BASE	0xfd810000
++#define BIGCORE1CRU_BASE	0xfd812000
++#define LITCRU_BASE		0xfd814000
++#define DSUCRU_BASE		0xfd818000
++
++#define I2C0_BASE		0xfd880000
++#define UART0_BASE		0xfd890000
++#define GPIO0_BASE		0xfd8a0000
++#define PWM0_BASE		0xfd8b0000
++#define PMUPVTM_BASE		0xfd8c0000
++#define TIMER_HP_BASE		0xfd8c8000
++#define PMU0_BASE		0xfd8d0000
++#define PMU1_BASE		0xfd8d4000
++#define PMU2_BASE		0xfd8d8000
++#define PMU_BASE		PMU0_BASE
++#define PMUWDT_BASE		0xfd8e0000
++#define PMUTIMER_BASE		0xfd8f0000
++#define OSC_CHK_BASE		0xfd9b0000
++#define VOP_BASE		0xfdd90000
++#define HDMIRX_BASE		0xfdee0000
++
++#define MSCH0_BASE		0xfe000000
++#define MSCH1_BASE		0xfe002000
++#define MSCH2_BASE		0xfe004000
++#define MSCH3_BASE		0xfe006000
++#define FIREWALL_DSU_BASE	0xfe010000
++#define FIREWALL_DDR_BASE	0xfe030000
++#define FIREWALL_SYSMEM_BASE	0xfe038000
++#define DDRPHY0_BASE		0xfe0c0000
++#define DDRPHY1_BASE		0xfe0d0000
++#define DDRPHY2_BASE		0xfe0e0000
++#define DDRPHY3_BASE		0xfe0f0000
++#define TIMER_DDR_BASE		0xfe118000
++#define KEYLADDER_BASE		0xfe380000
++#define CRYPTO_S_BASE		0xfe390000
++#define OTP_S_BASE		0xfe3a0000
++#define DCF_BASE		0xfe3c0000
++#define STIMER0_BASE		0xfe3d0000
++#define WDT_S_BASE		0xfe3e0000
++#define CRYPTO_S_BY_KEYLAD_BASE	0xfe420000
++#define NSTIMER0_BASE		0xfeae0000
++#define NSTIMER1_BASE		0xfeae8000
++#define WDT_NS_BASE		0xfeaf0000
++
++#define UART1_BASE		0xfeb40000
++#define UART2_BASE		0xfeb50000
++#define UART3_BASE		0xfeb60000
++#define UART4_BASE		0xfeb70000
++#define UART5_BASE		0xfeb80000
++#define UART6_BASE		0xfeb90000
++#define UART7_BASE		0xfeba0000
++#define UART8_BASE		0xfebb0000
++#define UART9_BASE		0xfebc0000
++
++#define GPIO1_BASE		0xfec20000
++#define GPIO2_BASE		0xfec30000
++#define GPIO3_BASE		0xfec40000
++#define GPIO4_BASE		0xfec50000
++
++#define MAILBOX1_BASE		0xfec70000
++#define OTP_NS_BASE		0xfecc0000
++#define INTMUX0_DDR_BASE	0Xfecf8000
++#define INTMUX1_DDR_BASE	0Xfecfc000
++#define STIMER1_BASE		0xfed30000
++
++/**************************************************************************
++ * sys sram allocation
++ **************************************************************************/
++#define SRAM_ENTRY_BASE		SRAM_BASE
++#define SRAM_PMUM0_SHMEM_BASE	(SRAM_ENTRY_BASE + SIZE_K(3))
++#define SRAM_LD_BASE		(SRAM_ENTRY_BASE + SIZE_K(4))
++#define SRAM_LD_SIZE		SIZE_K(64)
++
++#define SRAM_LD_SP		(SRAM_LD_BASE + SRAM_LD_SIZE -\
++				 128)
++
++/**************************************************************************
++ * share mem region allocation: 1M~2M
++ **************************************************************************/
++#define DDR_SHARE_MEM		SIZE_K(1024)
++#define DDR_SHARE_SIZE		SIZE_K(64)
++
++#define SHARE_MEM_BASE		DDR_SHARE_MEM
++#define SHARE_MEM_PAGE_NUM	15
++#define SHARE_MEM_SIZE		SIZE_K(SHARE_MEM_PAGE_NUM * 4)
++
++#define	SCMI_SHARE_MEM_BASE	(SHARE_MEM_BASE + SHARE_MEM_SIZE)
++#define	SCMI_SHARE_MEM_SIZE	SIZE_K(4)
++
++/**************************************************************************
++ * UART related constants
++ **************************************************************************/
++#define RK_DBG_UART_BASE		UART2_BASE
++#define RK_DBG_UART_BAUDRATE		1500000
++#define RK_DBG_UART_CLOCK		24000000
++
++/******************************************************************************
++ * System counter frequency related constants
++ ******************************************************************************/
++#define SYS_COUNTER_FREQ_IN_TICKS	24000000
++#define SYS_COUNTER_FREQ_IN_MHZ		24
++
++/******************************************************************************
++ * GIC-600 & interrupt handling related constants
++ ******************************************************************************/
++
++/* Base rk_platform compatible GIC memory map */
++#define PLAT_GICD_BASE			GIC600_BASE
++#define PLAT_GICC_BASE			0
++#define PLAT_GICR_BASE			(GIC600_BASE + 0x80000)
++#define PLAT_GICITS0_BASE		0xfe640000
++#define PLAT_GICITS1_BASE		0xfe660000
++
++/******************************************************************************
++ * sgi, ppi
++ ******************************************************************************/
++#define RK_IRQ_SEC_SGI_0		8
++#define RK_IRQ_SEC_SGI_1		9
++#define RK_IRQ_SEC_SGI_2		10
++#define RK_IRQ_SEC_SGI_3		11
++#define RK_IRQ_SEC_SGI_4		12
++#define RK_IRQ_SEC_SGI_5		13
++#define RK_IRQ_SEC_SGI_6		14
++#define RK_IRQ_SEC_SGI_7		15
++#define RK_IRQ_SEC_PHY_TIMER		29
++
++/*
++ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
++ * terminology. On a GICv2 system or mode, the lists will be merged and treated
++ * as Group 0 interrupts.
++ */
++
++#define PLAT_RK_GICV3_G1S_IRQS						\
++	INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY,	\
++		       INTR_GROUP1S, GIC_INTR_CFG_LEVEL)
++
++#define PLAT_RK_GICV3_G0_IRQS						\
++	INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY,	\
++		       INTR_GROUP0, GIC_INTR_CFG_LEVEL)
++
++/******************************************************************************
++ * pm reg region memory
++ ******************************************************************************/
++#define ROCKCHIP_PM_REG_REGION_MEM_SIZE		SIZE_K(4)
++
++#endif /* __PLAT_DEF_H__ */
+-- 
+2.46.0
+
+From 68515882dd7bb2c716ed9d385d0c755437bea176 Mon Sep 17 00:00:00 2001
+From: XiaoDong Huang <derrick.huang@rock-chips.com>
+Date: Sun, 25 Jun 2023 17:38:13 +0800
+Subject: [PATCH 5/5] feat(rk3588): support SCMI for clock/reset domain
+
+rockchip scmi clock controls clocks which only available in secure mode.
+
+Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
+Change-Id: I5b983877a5b4e8acababbf7e0a3e2725e6479e08
+---
+ plat/rockchip/common/include/plat_private.h   |    1 +
+ .../common/include/rockchip_sip_svc.h         |    1 +
+ plat/rockchip/common/scmi/scmi.c              |   89 +
+ plat/rockchip/common/scmi/scmi_clock.c        |  157 ++
+ plat/rockchip/common/scmi/scmi_clock.h        |   50 +
+ plat/rockchip/common/scmi/scmi_rstd.c         |   74 +
+ plat/rockchip/common/scmi/scmi_rstd.h         |   45 +
+ plat/rockchip/rk3588/drivers/pmu/pmu.c        |    3 +
+ .../rockchip/rk3588/drivers/scmi/rk3588_clk.c | 2463 +++++++++++++++++
+ .../rockchip/rk3588/drivers/scmi/rk3588_clk.h |  104 +
+ .../rk3588/drivers/scmi/rk3588_rstd.c         |   96 +
+ plat/rockchip/rk3588/drivers/soc/soc.c        |    3 +
+ plat/rockchip/rk3588/plat_sip_calls.c         |    5 +
+ plat/rockchip/rk3588/platform.mk              |   15 +-
+ plat/rockchip/rk3588/rk3588_def.h             |    3 +
+ 15 files changed, 3108 insertions(+), 1 deletion(-)
+ create mode 100644 plat/rockchip/common/scmi/scmi.c
+ create mode 100644 plat/rockchip/common/scmi/scmi_clock.c
+ create mode 100644 plat/rockchip/common/scmi/scmi_clock.h
+ create mode 100644 plat/rockchip/common/scmi/scmi_rstd.c
+ create mode 100644 plat/rockchip/common/scmi/scmi_rstd.h
+ create mode 100644 plat/rockchip/rk3588/drivers/scmi/rk3588_clk.c
+ create mode 100644 plat/rockchip/rk3588/drivers/scmi/rk3588_clk.h
+ create mode 100644 plat/rockchip/rk3588/drivers/scmi/rk3588_rstd.c
+
+diff --git a/plat/rockchip/common/include/plat_private.h b/plat/rockchip/common/include/plat_private.h
+index 44a0c461d..1e13a9e8c 100644
+--- a/plat/rockchip/common/include/plat_private.h
++++ b/plat/rockchip/common/include/plat_private.h
+@@ -141,6 +141,7 @@ uint32_t rockchip_get_uart_base(void);
+ uint32_t rockchip_get_uart_baudrate(void);
+ uint32_t rockchip_get_uart_clock(void);
+ 
++void rockchip_init_scmi_server(void);
+ #endif /* __ASSEMBLER__ */
+ 
+ /******************************************************************************
+diff --git a/plat/rockchip/common/include/rockchip_sip_svc.h b/plat/rockchip/common/include/rockchip_sip_svc.h
+index 340d65388..8836f9b58 100644
+--- a/plat/rockchip/common/include/rockchip_sip_svc.h
++++ b/plat/rockchip/common/include/rockchip_sip_svc.h
+@@ -11,6 +11,7 @@
+ #define SIP_SVC_CALL_COUNT		0x8200ff00
+ #define SIP_SVC_UID			0x8200ff01
+ #define SIP_SVC_VERSION			0x8200ff03
++#define RK_SIP_SCMI_AGENT0		0x82000010
+ 
+ /* rockchip SiP Service Calls version numbers */
+ #define RK_SIP_SVC_VERSION_MAJOR	0x0
+diff --git a/plat/rockchip/common/scmi/scmi.c b/plat/rockchip/common/scmi/scmi.c
+new file mode 100644
+index 000000000..5c43c511f
+--- /dev/null
++++ b/plat/rockchip/common/scmi/scmi.c
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <string.h>
++
++#include <platform_def.h>
++
++#include <drivers/scmi-msg.h>
++#include <drivers/scmi.h>
++#include <lib/utils.h>
++#include <lib/utils_def.h>
++
++#define MAX_PROTOCOL_IN_LIST		8U
++
++static const char vendor[] = "rockchip";
++static const char sub_vendor[] = "";
++
++#pragma weak rockchip_scmi_protocol_table
++
++const uint8_t rockchip_scmi_protocol_table[1][MAX_PROTOCOL_IN_LIST] = {
++	{
++		SCMI_PROTOCOL_ID_CLOCK,
++		SCMI_PROTOCOL_ID_RESET_DOMAIN,
++		0
++	}
++};
++
++const char *plat_scmi_vendor_name(void)
++{
++	return vendor;
++}
++
++const char *plat_scmi_sub_vendor_name(void)
++{
++	return sub_vendor;
++}
++
++size_t plat_scmi_protocol_count(void)
++{
++	unsigned int count = 0U;
++	const uint8_t *protocol_list = rockchip_scmi_protocol_table[0];
++
++	while (protocol_list[count])
++		count++;
++
++	return count;
++}
++
++const uint8_t *plat_scmi_protocol_list(unsigned int agent_id)
++{
++	assert(agent_id < ARRAY_SIZE(rockchip_scmi_protocol_table));
++
++	return rockchip_scmi_protocol_table[agent_id];
++}
++
++static struct scmi_msg_channel scmi_channel[] = {
++	[0] = {
++		.shm_addr = SMT_BUFFER0_BASE,
++		.shm_size = SMT_BUF_SLOT_SIZE,
++	},
++
++#ifdef SMT_BUFFER1_BASE
++	[1] = {
++		.shm_addr = SMT_BUFFER1_BASE,
++		.shm_size = SMT_BUF_SLOT_SIZE,
++	},
++#endif
++};
++
++struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
++{
++	assert(agent_id < ARRAY_SIZE(scmi_channel));
++
++	return &scmi_channel[agent_id];
++}
++
++#pragma weak rockchip_init_scmi_server
++
++void rockchip_init_scmi_server(void)
++{
++	size_t i;
++
++	for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++)
++		scmi_smt_init_agent_channel(&scmi_channel[i]);
++}
+diff --git a/plat/rockchip/common/scmi/scmi_clock.c b/plat/rockchip/common/scmi/scmi_clock.c
+new file mode 100644
+index 000000000..d6d4b3751
+--- /dev/null
++++ b/plat/rockchip/common/scmi/scmi_clock.c
+@@ -0,0 +1,157 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <drivers/scmi-msg.h>
++#include <drivers/scmi.h>
++
++#include "scmi_clock.h"
++
++#pragma weak rockchip_scmi_clock_count
++#pragma weak rockchip_scmi_get_clock
++
++size_t rockchip_scmi_clock_count(unsigned int agent_id __unused)
++{
++	return 0;
++}
++
++rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id __unused,
++					 uint32_t scmi_id __unused)
++{
++	return NULL;
++}
++
++size_t plat_scmi_clock_count(unsigned int agent_id)
++{
++	return rockchip_scmi_clock_count(agent_id);
++}
++
++const char *plat_scmi_clock_get_name(unsigned int agent_id,
++				     unsigned int scmi_id)
++{
++	rk_scmi_clock_t *clock;
++
++	clock = rockchip_scmi_get_clock(agent_id, scmi_id);
++	if (clock == NULL)
++		return NULL;
++
++	return clock->name;
++}
++
++int32_t plat_scmi_clock_rates_array(unsigned int agent_id,
++				    unsigned int scmi_id,
++				    unsigned long *rates,
++				    size_t *nb_elts,
++				    uint32_t start_idx)
++{
++	uint32_t i;
++	unsigned long *rate_table;
++	rk_scmi_clock_t *clock;
++
++	clock = rockchip_scmi_get_clock(agent_id, scmi_id);
++	if (clock == NULL)
++		return SCMI_NOT_FOUND;
++
++	rate_table = clock->rate_table;
++	if (rate_table == NULL)
++		return SCMI_NOT_SUPPORTED;
++
++	if (rates == 0) {
++		*nb_elts = clock->rate_cnt;
++		goto out;
++	}
++
++	if (start_idx + *nb_elts > clock->rate_cnt)
++		return SCMI_OUT_OF_RANGE;
++
++	for (i = 0; i < *nb_elts; i++)
++		rates[i] = rate_table[start_idx + i];
++
++out:
++	return SCMI_SUCCESS;
++}
++
++int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id __unused,
++				      unsigned int scmi_id __unused,
++				      unsigned long *steps __unused)
++{
++	return SCMI_NOT_SUPPORTED;
++}
++
++unsigned long plat_scmi_clock_get_rate(unsigned int agent_id,
++				       unsigned int scmi_id)
++{
++	rk_scmi_clock_t *clock;
++	unsigned long rate = 0;
++
++	clock = rockchip_scmi_get_clock(agent_id, scmi_id);
++	if (clock == NULL)
++		return 0;
++
++	if (clock->clk_ops && clock->clk_ops->get_rate)
++		rate = clock->clk_ops->get_rate(clock);
++
++	/* return cur_rate if no get_rate ops or get_rate return 0 */
++	if (rate == 0)
++		rate = clock->cur_rate;
++
++	return rate;
++}
++
++int32_t plat_scmi_clock_set_rate(unsigned int agent_id,
++				 unsigned int scmi_id,
++				 unsigned long rate)
++{
++	rk_scmi_clock_t *clock;
++	int32_t status = 0;
++
++	clock = rockchip_scmi_get_clock(agent_id, scmi_id);
++	if (clock == NULL)
++		return SCMI_NOT_FOUND;
++
++	if (clock->clk_ops && clock->clk_ops->set_rate) {
++		status = clock->clk_ops->set_rate(clock, rate);
++		if (status == SCMI_SUCCESS)
++			clock->cur_rate = rate;
++	} else {
++		status = SCMI_NOT_SUPPORTED;
++	}
++
++	return status;
++}
++
++int32_t plat_scmi_clock_get_state(unsigned int agent_id,
++				  unsigned int scmi_id)
++{
++	rk_scmi_clock_t *clock;
++
++	clock = rockchip_scmi_get_clock(agent_id, scmi_id);
++	if (clock == NULL)
++		return 0;
++
++	return clock->enable;
++}
++
++int32_t plat_scmi_clock_set_state(unsigned int agent_id,
++				  unsigned int scmi_id,
++				  bool enable_not_disable)
++{
++	rk_scmi_clock_t *clock;
++	int32_t status = 0;
++
++	clock = rockchip_scmi_get_clock(agent_id, scmi_id);
++	if (clock == NULL)
++		return SCMI_NOT_FOUND;
++
++	if (clock->clk_ops && clock->clk_ops->set_status) {
++		status = clock->clk_ops->set_status(clock, enable_not_disable);
++		if (status == SCMI_SUCCESS)
++			clock->enable = enable_not_disable;
++	} else {
++		status = SCMI_NOT_SUPPORTED;
++	}
++
++	return status;
++}
+diff --git a/plat/rockchip/common/scmi/scmi_clock.h b/plat/rockchip/common/scmi/scmi_clock.h
+new file mode 100644
+index 000000000..e640fe196
+--- /dev/null
++++ b/plat/rockchip/common/scmi/scmi_clock.h
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef RK_SCMI_CLOCK_H
++#define RK_SCMI_CLOCK_H
++
++#include <stdint.h>
++
++#include <common.h>
++
++struct rk_scmi_clock;
++
++struct rk_clk_ops {
++	unsigned long (*get_rate)(struct rk_scmi_clock *clock);
++	int (*set_rate)(struct rk_scmi_clock *clock, unsigned long rate);
++	int (*set_status)(struct rk_scmi_clock *clock, bool status);
++};
++
++typedef struct rk_scmi_clock {
++	char name[SCMI_CLOCK_NAME_LENGTH_MAX];
++	uint8_t enable;
++	int8_t is_security;
++	uint32_t id;
++	uint32_t rate_cnt;
++	uint64_t cur_rate;
++	uint32_t enable_count;
++	const struct rk_clk_ops *clk_ops;
++	unsigned long *rate_table;
++} rk_scmi_clock_t;
++
++/*
++ * Return number of clock controllers for an agent
++ * @agent_id: SCMI agent ID
++ * Return number of clock controllers
++ */
++size_t rockchip_scmi_clock_count(unsigned int agent_id);
++
++/*
++ * Get rk_scmi_clock_t point
++ * @agent_id: SCMI agent ID
++ * @scmi_id: SCMI clock ID
++ * Return a rk_scmi_clock_t point
++ */
++rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id,
++					 uint32_t scmi_id);
++
++#endif /* RK_SCMI_CLOCK_H */
+diff --git a/plat/rockchip/common/scmi/scmi_rstd.c b/plat/rockchip/common/scmi/scmi_rstd.c
+new file mode 100644
+index 000000000..35c5e0b24
+--- /dev/null
++++ b/plat/rockchip/common/scmi/scmi_rstd.c
+@@ -0,0 +1,74 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <drivers/scmi-msg.h>
++#include <drivers/scmi.h>
++
++#include "scmi_rstd.h"
++
++#pragma weak rockchip_scmi_rstd_count
++#pragma weak rockchip_scmi_get_rstd
++
++size_t rockchip_scmi_rstd_count(unsigned int agent_id __unused)
++{
++	return 0U;
++}
++
++rk_scmi_rstd_t *rockchip_scmi_get_rstd(unsigned int agent_id __unused,
++				       unsigned int scmi_id __unused)
++{
++	return NULL;
++}
++
++size_t plat_scmi_rstd_count(unsigned int agent_id)
++{
++	return rockchip_scmi_rstd_count(agent_id);
++}
++
++const char *plat_scmi_rstd_get_name(unsigned int agent_id,
++				    unsigned int scmi_id)
++{
++	rk_scmi_rstd_t *rstd;
++
++	rstd = rockchip_scmi_get_rstd(agent_id, scmi_id);
++	if (rstd == NULL)
++		return NULL;
++
++	return rstd->name;
++}
++
++int32_t plat_scmi_rstd_autonomous(unsigned int agent_id,
++				  unsigned int scmi_id,
++				  unsigned int state)
++{
++	rk_scmi_rstd_t *rstd;
++
++	rstd = rockchip_scmi_get_rstd(agent_id, scmi_id);
++	if (rstd == NULL)
++		return SCMI_NOT_FOUND;
++
++	if ((rstd->rstd_ops && rstd->rstd_ops->reset_auto) != 0)
++		return rstd->rstd_ops->reset_auto(rstd, state);
++	else
++		return SCMI_NOT_SUPPORTED;
++}
++
++int32_t plat_scmi_rstd_set_state(unsigned int agent_id,
++				 unsigned int scmi_id,
++				 bool assert_not_deassert)
++{
++	rk_scmi_rstd_t *rstd;
++
++	rstd = rockchip_scmi_get_rstd(agent_id, scmi_id);
++	if (rstd == NULL)
++		return SCMI_NOT_FOUND;
++
++	if ((rstd->rstd_ops && rstd->rstd_ops->reset_explicit) != 0)
++		return rstd->rstd_ops->reset_explicit(rstd,
++						      assert_not_deassert);
++	else
++		return SCMI_NOT_SUPPORTED;
++}
+diff --git a/plat/rockchip/common/scmi/scmi_rstd.h b/plat/rockchip/common/scmi/scmi_rstd.h
+new file mode 100644
+index 000000000..1af588139
+--- /dev/null
++++ b/plat/rockchip/common/scmi/scmi_rstd.h
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef RK_SCMI_RESET_DOMAIN_H
++#define RK_SCMI_RESET_DOMAIN_H
++
++#include <stdint.h>
++
++#include <common.h>
++
++struct rk_scmi_rstd;
++
++struct rk_scmi_rstd_ops {
++	int (*reset_auto)(struct rk_scmi_rstd *rstd, uint32_t state);
++	int (*reset_explicit)(struct rk_scmi_rstd *rstd, bool assert_not_deassert);
++};
++
++typedef struct rk_scmi_rstd {
++	char name[SCMI_RESET_DOMAIN_ATTR_NAME_SZ];
++	uint32_t id;
++	uint32_t attribute;
++	uint32_t latency;
++	struct rk_scmi_rstd_ops *rstd_ops;
++} rk_scmi_rstd_t;
++
++/*
++ * Return number of reset domain for an agent
++ * @agent_id: SCMI agent ID
++ * Return number of reset domain
++ */
++size_t rockchip_scmi_rstd_count(unsigned int agent_id);
++
++/*
++ * Get rk_scmi_rstd_t point
++ * @agent_id: SCMI agent ID
++ * @scmi_id: SCMI rstd ID
++ * Return a rk_scmi_rstd_t point
++ */
++rk_scmi_rstd_t *rockchip_scmi_get_rstd(unsigned int agent_id,
++				       unsigned int scmi_id);
++
++#endif /* RK_SCMI_RESET_DOMAIN_H */
+diff --git a/plat/rockchip/rk3588/drivers/pmu/pmu.c b/plat/rockchip/rk3588/drivers/pmu/pmu.c
+index 445cf8d97..83d6cad97 100644
+--- a/plat/rockchip/rk3588/drivers/pmu/pmu.c
++++ b/plat/rockchip/rk3588/drivers/pmu/pmu.c
+@@ -23,6 +23,7 @@
+ #include <plat_pm_helpers.h>
+ #include <plat_private.h>
+ #include <pm_pd_regs.h>
++#include <rk3588_clk.h>
+ #include <rockchip_sip_svc.h>
+ #include <secure.h>
+ #include <soc.h>
+@@ -164,12 +165,14 @@ static void dsu_core_save(void)
+ 		pmusram_data.dsu_ddr_fw_con_reg[i] =
+ 			mmio_read_32(FIREWALL_DSU_BASE + FIREWALL_DSU_CON(i));
+ 
++	pvtplls_suspend();
+ 	pd_dsu_core_save();
+ }
+ 
+ static void dsu_core_restore(void)
+ {
+ 	pd_dsu_core_restore();
++	pvtplls_resume();
+ }
+ 
+ static uint32_t clk_save[CRU_CLKGATE_CON_CNT + PHPCRU_CLKGATE_CON_CNT +
+diff --git a/plat/rockchip/rk3588/drivers/scmi/rk3588_clk.c b/plat/rockchip/rk3588/drivers/scmi/rk3588_clk.c
+new file mode 100644
+index 000000000..ab3af5f39
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/scmi/rk3588_clk.c
+@@ -0,0 +1,2463 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <drivers/delay_timer.h>
++#include <drivers/scmi.h>
++#include <lib/mmio.h>
++#include <platform_def.h>
++
++#include <plat_private.h>
++#include "rk3588_clk.h"
++#include <rockchip_sip_svc.h>
++#include <scmi_clock.h>
++#include <soc.h>
++
++enum pll_type_sel {
++	PLL_SEL_AUTO, /* all plls (normal pll or pvtpll) */
++	PLL_SEL_PVT,
++	PLL_SEL_NOR,
++	PLL_SEL_AUTO_NOR /* all normal plls (apll/gpll/npll) */
++};
++
++#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
++
++#define RK3588_CPUL_PVTPLL_CON0_L	0x40
++#define RK3588_CPUL_PVTPLL_CON0_H	0x44
++#define RK3588_CPUL_PVTPLL_CON1		0x48
++#define RK3588_CPUL_PVTPLL_CON2		0x4c
++#define RK3588_CPUB_PVTPLL_CON0_L	0x00
++#define RK3588_CPUB_PVTPLL_CON0_H	0x04
++#define RK3588_CPUB_PVTPLL_CON1		0x08
++#define RK3588_CPUB_PVTPLL_CON2		0x0c
++#define RK3588_DSU_PVTPLL_CON0_L	0x60
++#define RK3588_DSU_PVTPLL_CON0_H	0x64
++#define RK3588_DSU_PVTPLL_CON1		0x70
++#define RK3588_DSU_PVTPLL_CON2		0x74
++#define RK3588_GPU_PVTPLL_CON0_L	0x00
++#define RK3588_GPU_PVTPLL_CON0_H	0x04
++#define RK3588_GPU_PVTPLL_CON1		0x08
++#define RK3588_GPU_PVTPLL_CON2		0x0c
++#define RK3588_NPU_PVTPLL_CON0_L	0x0c
++#define RK3588_NPU_PVTPLL_CON0_H	0x10
++#define RK3588_NPU_PVTPLL_CON1		0x14
++#define RK3588_NPU_PVTPLL_CON2		0x18
++#define RK3588_PVTPLL_MAX_LENGTH	0x3f
++
++#define GPLL_RATE			1188000000
++#define CPLL_RATE			1500000000
++#define SPLL_RATE			702000000
++#define AUPLL_RATE			786431952
++#define NPLL_RATE			850000000
++
++#define MAX_RATE_TABLE			16
++
++#define CLKDIV_6BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x3fU, shift)
++#define CLKDIV_5BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x1fU, shift)
++#define CLKDIV_4BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0xfU, shift)
++#define CLKDIV_3BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x7U, shift)
++#define CLKDIV_2BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x3U, shift)
++#define CLKDIV_1BITS_SHF(div, shift)	BITS_WITH_WMASK(div, 0x1U, shift)
++
++#define CPU_PLL_PATH_SLOWMODE		BITS_WITH_WMASK(0U, 0x3U, 0)
++#define CPU_PLL_PATH_NORMAL		BITS_WITH_WMASK(1U, 0x3U, 0)
++#define CPU_PLL_PATH_DEEP_SLOW		BITS_WITH_WMASK(2U, 0x3U, 0)
++
++#define CRU_PLL_POWER_DOWN		BIT_WITH_WMSK(13)
++#define CRU_PLL_POWER_UP		WMSK_BIT(13)
++
++/* core_i: from gpll or apll */
++#define CLK_CORE_I_SEL_APLL		WMSK_BIT(6)
++#define CLK_CORE_I_SEL_GPLL		BIT_WITH_WMSK(6)
++
++/* clk_core:
++ * from normal pll(core_i: gpll or apll) path or direct pass from apll
++ */
++
++/* cpul clk path */
++#define CPUL_CLK_PATH_NOR_XIN		BITS_WITH_WMASK(0U, 0x3U, 14)
++#define CPUL_CLK_PATH_NOR_GPLL		BITS_WITH_WMASK(1U, 0x3U, 14)
++#define CPUL_CLK_PATH_NOR_LPLL		BITS_WITH_WMASK(2U, 0x3U, 14)
++
++#define CPUL_CLK_PATH_LPLL		(BITS_WITH_WMASK(0U, 0x3U, 5) | \
++					BITS_WITH_WMASK(0U, 0x3U, 12))
++#define CPUL_CLK_PATH_DIR_LPLL		(BITS_WITH_WMASK(0x1, 0x3U, 5) | \
++					BITS_WITH_WMASK(1U, 0x3U, 12))
++#define CPUL_CLK_PATH_PVTPLL		(BITS_WITH_WMASK(0x2, 0x3U, 5) | \
++					BITS_WITH_WMASK(2U, 0x3U, 12))
++
++#define CPUL_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 14)
++#define CPUL_PVTPLL_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x1U, 14)
++
++/* cpub01 clk path */
++#define CPUB01_CLK_PATH_NOR_XIN		BITS_WITH_WMASK(0U, 0x3U, 6)
++#define CPUB01_CLK_PATH_NOR_GPLL	BITS_WITH_WMASK(1U, 0x3U, 6)
++#define CPUB01_CLK_PATH_NOR_B0PLL	BITS_WITH_WMASK(2U, 0x3U, 6)
++
++#define CPUB01_CLK_PATH_B0PLL		BITS_WITH_WMASK(0U, 0x3U, 13)
++#define CPUB01_CLK_PATH_DIR_B0PLL	BITS_WITH_WMASK(1U, 0x3U, 13)
++#define CPUB01_CLK_PATH_B0_PVTPLL	BITS_WITH_WMASK(2U, 0x3U, 13)
++
++#define CPUB01_CLK_PATH_B1PLL		BITS_WITH_WMASK(0U, 0x3U, 5)
++#define CPUB01_CLK_PATH_DIR_B1PLL	BITS_WITH_WMASK(1U, 0x3U, 5)
++#define CPUB01_CLK_PATH_B1_PVTPLL	BITS_WITH_WMASK(2U, 0x3U, 5)
++
++#define CPUB01_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 2)
++#define CPUB01_PVTPLL_PATH_PVTPLL	BITS_WITH_WMASK(1U, 0x1U, 2)
++
++#define CPUB_PCLK_PATH_100M		BITS_WITH_WMASK(0U, 0x3U, 0)
++#define CPUB_PCLK_PATH_50M		BITS_WITH_WMASK(1U, 0x3U, 0)
++#define CPUB_PCLK_PATH_24M		BITS_WITH_WMASK(2U, 0x3U, 0)
++
++/* dsu clk path */
++#define SCLK_DSU_PATH_NOR_B0PLL		BITS_WITH_WMASK(0U, 0x3U, 12)
++#define SCLK_DSU_PATH_NOR_B1PLL		BITS_WITH_WMASK(1U, 0x3U, 12)
++#define SCLK_DSU_PATH_NOR_LPLL		BITS_WITH_WMASK(2U, 0x3U, 12)
++#define SCLK_DSU_PATH_NOR_GPLL		BITS_WITH_WMASK(3U, 0x3U, 12)
++
++#define DSU_PVTPLL_PATH_DEEP_SLOW	BITS_WITH_WMASK(0U, 0x1U, 15)
++#define DSU_PVTPLL_PATH_PVTPLL		BITS_WITH_WMASK(1U, 0x1U, 15)
++
++#define SCLK_DSU_PATH_NOR_PLL		WMSK_BIT(0)
++#define SCLK_DSU_PATH_PVTPLL		BIT_WITH_WMSK(0)
++
++/* npu clk path */
++#define NPU_CLK_PATH_NOR_GPLL		BITS_WITH_WMASK(0U, 0x7U, 7)
++#define NPU_CLK_PATH_NOR_CPLL		BITS_WITH_WMASK(1U, 0x7U, 7)
++#define NPU_CLK_PATH_NOR_AUPLL		BITS_WITH_WMASK(2U, 0x7U, 7)
++#define NPU_CLK_PATH_NOR_NPLL		BITS_WITH_WMASK(3U, 0x7U, 7)
++#define NPU_CLK_PATH_NOR_SPLL		BITS_WITH_WMASK(4U, 0x7U, 7)
++
++#define NPU_CLK_PATH_NOR_PLL		WMSK_BIT(0)
++#define NPU_CLK_PATH_PVTPLL		BIT_WITH_WMSK(0)
++
++/* gpu clk path */
++#define GPU_CLK_PATH_NOR_GPLL		BITS_WITH_WMASK(0U, 0x7U, 5)
++#define GPU_CLK_PATH_NOR_CPLL		BITS_WITH_WMASK(1U, 0x7U, 5)
++#define GPU_CLK_PATH_NOR_AUPLL		BITS_WITH_WMASK(2U, 0x7U, 5)
++#define GPU_CLK_PATH_NOR_NPLL		BITS_WITH_WMASK(3U, 0x7U, 5)
++#define GPU_CLK_PATH_NOR_SPLL		BITS_WITH_WMASK(4U, 0x7U, 5)
++#define GPU_CLK_PATH_NOR_PLL		WMSK_BIT(14)
++#define GPU_CLK_PATH_PVTPLL		BIT_WITH_WMSK(14)
++
++#define PVTPLL_NEED(type, length)	(((type) == PLL_SEL_PVT || \
++					  (type) == PLL_SEL_AUTO) && \
++					 (length))
++
++struct pvtpll_table {
++	unsigned int rate;
++	uint32_t length;
++	uint32_t ring_sel;
++};
++
++struct sys_clk_info_t {
++	struct pvtpll_table *cpul_table;
++	struct pvtpll_table *cpub01_table;
++	struct pvtpll_table *cpub23_table;
++	struct pvtpll_table *gpu_table;
++	struct pvtpll_table *npu_table;
++	unsigned int cpul_rate_count;
++	unsigned int cpub01_rate_count;
++	unsigned int cpub23_rate_count;
++	unsigned int gpu_rate_count;
++	unsigned int npu_rate_count;
++	unsigned long cpul_rate;
++	unsigned long dsu_rate;
++	unsigned long cpub01_rate;
++	unsigned long cpub23_rate;
++	unsigned long gpu_rate;
++	unsigned long npu_rate;
++};
++
++#define RK3588_SCMI_CLOCK(_id, _name, _data, _table, _cnt, _is_s)	\
++{									\
++	.id	= _id,							\
++	.name = _name,							\
++	.clk_ops = _data,						\
++	.rate_table = _table,						\
++	.rate_cnt = _cnt,						\
++	.is_security = _is_s,						\
++}
++
++#define ROCKCHIP_PVTPLL(_rate, _sel, _len)				\
++{									\
++	.rate = _rate##U,						\
++	.ring_sel = _sel,						\
++	.length = _len,							\
++}
++
++static struct pvtpll_table rk3588_cpul_pvtpll_table[] = {
++	/* rate_hz, ring_sel, length */
++	ROCKCHIP_PVTPLL(1800000000, 1, 15),
++	ROCKCHIP_PVTPLL(1704000000, 1, 15),
++	ROCKCHIP_PVTPLL(1608000000, 1, 15),
++	ROCKCHIP_PVTPLL(1416000000, 1, 15),
++	ROCKCHIP_PVTPLL(1200000000, 1, 17),
++	ROCKCHIP_PVTPLL(1008000000, 1, 22),
++	ROCKCHIP_PVTPLL(816000000, 1, 32),
++	ROCKCHIP_PVTPLL(600000000, 0, 0),
++	ROCKCHIP_PVTPLL(408000000, 0, 0),
++	{ /* sentinel */ },
++};
++
++static struct pvtpll_table rk3588_cpub0_pvtpll_table[] = {
++	/* rate_hz, ring_sel, length */
++	ROCKCHIP_PVTPLL(2400000000, 1, 11),
++	ROCKCHIP_PVTPLL(2352000000, 1, 11),
++	ROCKCHIP_PVTPLL(2304000000, 1, 11),
++	ROCKCHIP_PVTPLL(2256000000, 1, 11),
++	ROCKCHIP_PVTPLL(2208000000, 1, 11),
++	ROCKCHIP_PVTPLL(2112000000, 1, 11),
++	ROCKCHIP_PVTPLL(2016000000, 1, 11),
++	ROCKCHIP_PVTPLL(1800000000, 1, 11),
++	ROCKCHIP_PVTPLL(1608000000, 1, 11),
++	ROCKCHIP_PVTPLL(1416000000, 1, 13),
++	ROCKCHIP_PVTPLL(1200000000, 1, 17),
++	ROCKCHIP_PVTPLL(1008000000, 1, 23),
++	ROCKCHIP_PVTPLL(816000000, 1, 33),
++	ROCKCHIP_PVTPLL(600000000, 0, 0),
++	ROCKCHIP_PVTPLL(408000000, 0, 0),
++	{ /* sentinel */ },
++};
++
++static struct
++pvtpll_table rk3588_cpub1_pvtpll_table[ARRAY_SIZE(rk3588_cpub0_pvtpll_table)] = { 0 };
++
++static struct pvtpll_table rk3588_gpu_pvtpll_table[] = {
++	/* rate_hz, ring_sel, length */
++	ROCKCHIP_PVTPLL(1000000000, 1, 12),
++	ROCKCHIP_PVTPLL(900000000, 1, 12),
++	ROCKCHIP_PVTPLL(800000000, 1, 12),
++	ROCKCHIP_PVTPLL(700000000, 1, 13),
++	ROCKCHIP_PVTPLL(600000000, 1, 17),
++	ROCKCHIP_PVTPLL(500000000, 1, 25),
++	ROCKCHIP_PVTPLL(400000000, 1, 38),
++	ROCKCHIP_PVTPLL(300000000, 1, 55),
++	ROCKCHIP_PVTPLL(200000000, 0, 0),
++	{ /* sentinel */ },
++};
++
++static struct pvtpll_table rk3588_npu_pvtpll_table[] = {
++	/* rate_hz, ring_sel, length */
++	ROCKCHIP_PVTPLL(1000000000, 1, 12),
++	ROCKCHIP_PVTPLL(900000000, 1, 12),
++	ROCKCHIP_PVTPLL(800000000, 1, 12),
++	ROCKCHIP_PVTPLL(700000000, 1, 13),
++	ROCKCHIP_PVTPLL(600000000, 1, 17),
++	ROCKCHIP_PVTPLL(500000000, 1, 25),
++	ROCKCHIP_PVTPLL(400000000, 1, 38),
++	ROCKCHIP_PVTPLL(300000000, 1, 55),
++	ROCKCHIP_PVTPLL(200000000, 0, 0),
++	{ /* sentinel */ },
++};
++
++static unsigned long rk3588_cpul_rates[] = {
++	408000000, 600000000, 816000000, 1008000000,
++	1200000000, 1416000000, 1608000000, 1800000063,
++};
++
++static unsigned long rk3588_cpub_rates[] = {
++	408000000, 816000000, 1008000000, 1200000000,
++	1416000000, 1608000000, 1800000000, 2016000000,
++	2208000000, 2304000000, 2400000063
++};
++
++static unsigned long rk3588_gpu_rates[] = {
++	200000000, 300000000, 400000000, 500000000,
++	600000000, 700000000, 800000000, 900000000,
++	1000000063
++};
++
++static unsigned long rk3588_sbus_rates[] = {
++	24000000, 50000000, 100000000, 150000000, 200000000,
++	250000000, 350000000, 700000000
++};
++
++static unsigned long rk3588_sdmmc_rates[] = {
++	400000, 24000000, 50000000, 100000000, 150000000, 200000000,
++	300000000, 400000000, 600000000, 700000000
++};
++
++static struct sys_clk_info_t sys_clk_info;
++static int clk_scmi_dsu_set_rate(rk_scmi_clock_t *clock, unsigned long rate);
++
++static struct pvtpll_table *rkclk_get_pvtpll_config(struct pvtpll_table *table,
++						    unsigned int count,
++						    unsigned int freq_hz)
++{
++	int i;
++
++	for (i = 0; i < count; i++) {
++		if (freq_hz == table[i].rate)
++			return &table[i];
++	}
++	return NULL;
++}
++
++static int clk_cpul_set_rate(unsigned long rate, enum pll_type_sel type)
++{
++	struct pvtpll_table *pvtpll;
++	int div;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpul_table,
++					 sys_clk_info.cpul_rate_count, rate);
++	if (pvtpll == NULL)
++		return SCMI_INVALID_PARAMETERS;
++
++	/* set lpll */
++	if (PVTPLL_NEED(type, pvtpll->length) != 0) {
++		/* set clock gating interval */
++		mmio_write_32(LITCOREGRF_BASE + RK3588_CPUL_PVTPLL_CON2,
++			      0x00040000);
++		/* set ring sel */
++		mmio_write_32(LITCOREGRF_BASE + RK3588_CPUL_PVTPLL_CON0_L,
++			      0x07000000 | (pvtpll->ring_sel << 8));
++		/* set length */
++		mmio_write_32(LITCOREGRF_BASE + RK3588_CPUL_PVTPLL_CON0_H,
++			      0x003f0000 | pvtpll->length);
++		/* set cal cnt = 24, T = 1us */
++		mmio_write_32(LITCOREGRF_BASE + RK3588_CPUL_PVTPLL_CON1,
++			      0x18);
++		/* enable pvtpll */
++		mmio_write_32(LITCOREGRF_BASE + RK3588_CPUL_PVTPLL_CON0_L,
++			      0x00020002);
++		/* start monitor */
++		mmio_write_32(LITCOREGRF_BASE + RK3588_CPUL_PVTPLL_CON0_L,
++			      0x00010001);
++		/* set corel mux pvtpll */
++		mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(7),
++			      CPUL_PVTPLL_PATH_PVTPLL);
++		mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(6),
++			      CPUL_CLK_PATH_PVTPLL);
++		mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(7),
++			      CPUL_CLK_PATH_PVTPLL);
++		return 0;
++	}
++
++	/* set clk corel div */
++	div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(6),
++		      CLKDIV_5BITS_SHF(div, 0) | CLKDIV_5BITS_SHF(div, 7));
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(7),
++		      CLKDIV_5BITS_SHF(div, 0) | CLKDIV_5BITS_SHF(div, 7));
++	/* set corel mux gpll */
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(5),
++		      CPUL_CLK_PATH_NOR_GPLL);
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(6),
++		      CPUL_CLK_PATH_LPLL);
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(7),
++		      CPUL_CLK_PATH_LPLL);
++
++	return 0;
++}
++
++static int clk_scmi_cpul_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int ret;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	ret = clk_cpul_set_rate(rate, PLL_SEL_AUTO);
++	if (ret == 0) {
++		sys_clk_info.cpul_rate = rate;
++		ret = clk_scmi_dsu_set_rate(clock, rate);
++	}
++
++	return ret;
++}
++
++static unsigned long rk3588_lpll_get_rate(void)
++{
++	unsigned int m, p, s, k;
++	uint64_t rate64 = 24000000, postdiv;
++	int mode;
++
++	mode = (mmio_read_32(DSUCRU_BASE + CRU_CLKSEL_CON(5)) >> 14) &
++	       0x3;
++
++	if (mode == 0)
++		return rate64;
++
++	m = (mmio_read_32(DSUCRU_BASE + CRU_PLL_CON(16)) >>
++		 CRU_PLLCON0_M_SHIFT) &
++		CRU_PLLCON0_M_MASK;
++	p = (mmio_read_32(DSUCRU_BASE + CRU_PLL_CON(17)) >>
++		    CRU_PLLCON1_P_SHIFT) &
++		   CRU_PLLCON1_P_MASK;
++	s = (mmio_read_32(DSUCRU_BASE + CRU_PLL_CON(17)) >>
++		  CRU_PLLCON1_S_SHIFT) &
++		 CRU_PLLCON1_S_MASK;
++	k = (mmio_read_32(DSUCRU_BASE + CRU_PLL_CON(18)) >>
++		    CRU_PLLCON2_K_SHIFT) &
++		   CRU_PLLCON2_K_MASK;
++
++	rate64 *= m;
++	rate64 = rate64 / p;
++
++	if (k != 0) {
++		/* fractional mode */
++		uint64_t frac_rate64 = 24000000 * k;
++
++		postdiv = p * 65535;
++		frac_rate64 = frac_rate64 / postdiv;
++		rate64 += frac_rate64;
++	}
++	rate64 = rate64 >> s;
++
++	return (unsigned long)rate64;
++}
++
++static unsigned long clk_scmi_cpul_get_rate(rk_scmi_clock_t *clock)
++{
++	int src, div;
++
++	src = mmio_read_32(DSUCRU_BASE + CRU_CLKSEL_CON(6)) & 0x0060;
++	src = src >> 5;
++	if (src == 2) {
++		return sys_clk_info.cpul_rate;
++	} else {
++		src = mmio_read_32(DSUCRU_BASE + CRU_CLKSEL_CON(5)) & 0xc000;
++		src = src >> 14;
++		div = mmio_read_32(DSUCRU_BASE + CRU_CLKSEL_CON(6)) & 0x1f;
++		switch (src) {
++		case 0:
++			return 24000000;
++		case 1:
++			/* Make the return rate is equal to the set rate */
++			if (sys_clk_info.cpul_rate)
++				return sys_clk_info.cpul_rate;
++			else
++				return GPLL_RATE / (div + 1);
++		case 2:
++			return rk3588_lpll_get_rate();
++		default:
++			return 0;
++		}
++	}
++}
++
++static int clk_scmi_cpul_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static void clk_scmi_b0pll_disable(void)
++{
++	static bool is_b0pll_disabled;
++
++	if (is_b0pll_disabled != 0)
++		return;
++
++	/* set coreb01 mux gpll */
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0),
++		      CPUB01_CLK_PATH_NOR_GPLL);
++	 /* pll enter slow mode */
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_MODE_CON0, CPU_PLL_PATH_SLOWMODE);
++	/* set pll power down */
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_PLL_CON(1), CRU_PLL_POWER_DOWN);
++
++	is_b0pll_disabled = true;
++}
++
++static int clk_cpub01_set_rate(unsigned long rate, enum pll_type_sel type)
++{
++	struct pvtpll_table *pvtpll;
++	int div;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpub01_table,
++					 sys_clk_info.cpub01_rate_count, rate);
++	if (pvtpll == NULL)
++		return SCMI_INVALID_PARAMETERS;
++
++	/* set b0pll */
++	if (PVTPLL_NEED(type, pvtpll->length)) {
++		/* set clock gating interval */
++		mmio_write_32(BIGCORE0GRF_BASE + RK3588_CPUB_PVTPLL_CON2,
++			      0x00040000);
++		/* set ring sel */
++		mmio_write_32(BIGCORE0GRF_BASE + RK3588_CPUB_PVTPLL_CON0_L,
++			      0x07000000 | (pvtpll->ring_sel << 8));
++		/* set length */
++		mmio_write_32(BIGCORE0GRF_BASE + RK3588_CPUB_PVTPLL_CON0_H,
++			      0x003f0000 | pvtpll->length);
++		/* set cal cnt = 24, T = 1us */
++		mmio_write_32(BIGCORE0GRF_BASE + RK3588_CPUB_PVTPLL_CON1,
++			      0x18);
++		/* enable pvtpll */
++		mmio_write_32(BIGCORE0GRF_BASE + RK3588_CPUB_PVTPLL_CON0_L,
++			      0x00020002);
++		/* start monitor */
++		mmio_write_32(BIGCORE0GRF_BASE + RK3588_CPUB_PVTPLL_CON0_L,
++			      0x00010001);
++		/* set core mux pvtpll */
++		mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(2),
++			      CPUB01_PVTPLL_PATH_PVTPLL);
++		mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0),
++			      CPUB01_CLK_PATH_B0_PVTPLL);
++		mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(1),
++			      CPUB01_CLK_PATH_B1_PVTPLL);
++		goto out;
++	}
++
++	/* set clk coreb01 div */
++	div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0),
++		      CLKDIV_5BITS_SHF(div, 8));
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(1),
++		      CLKDIV_5BITS_SHF(div, 0));
++	/* set coreb01 mux gpll */
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0),
++		      CPUB01_CLK_PATH_NOR_GPLL);
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0),
++		      CPUB01_CLK_PATH_B0PLL);
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(1),
++		      CPUB01_CLK_PATH_B1PLL);
++
++out:
++	clk_scmi_b0pll_disable();
++
++	return 0;
++}
++
++static int clk_scmi_cpub01_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int ret;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	ret = clk_cpub01_set_rate(rate, PLL_SEL_AUTO);
++	if (ret == 0)
++		sys_clk_info.cpub01_rate = rate;
++
++	return ret;
++}
++
++static unsigned long rk3588_b0pll_get_rate(void)
++{
++	unsigned int m, p, s, k;
++	uint64_t rate64 = 24000000, postdiv;
++	int mode;
++
++	mode = (mmio_read_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0)) >> 6) &
++	       0x3;
++
++	if (mode == 0)
++		return rate64;
++
++	m = (mmio_read_32(BIGCORE0CRU_BASE + CRU_PLL_CON(0)) >>
++		 CRU_PLLCON0_M_SHIFT) &
++		CRU_PLLCON0_M_MASK;
++	p = (mmio_read_32(BIGCORE0CRU_BASE + CRU_PLL_CON(1)) >>
++		    CRU_PLLCON1_P_SHIFT) &
++		   CRU_PLLCON1_P_MASK;
++	s = (mmio_read_32(BIGCORE0CRU_BASE + CRU_PLL_CON(1)) >>
++		  CRU_PLLCON1_S_SHIFT) &
++		 CRU_PLLCON1_S_MASK;
++	k = (mmio_read_32(BIGCORE0CRU_BASE + CRU_PLL_CON(2)) >>
++		    CRU_PLLCON2_K_SHIFT) &
++		   CRU_PLLCON2_K_MASK;
++
++	rate64 *= m;
++	rate64 = rate64 / p;
++
++	if (k != 0) {
++		/* fractional mode */
++		uint64_t frac_rate64 = 24000000 * k;
++
++		postdiv = p * 65535;
++		frac_rate64 = frac_rate64 / postdiv;
++		rate64 += frac_rate64;
++	}
++	rate64 = rate64 >> s;
++
++	return (unsigned long)rate64;
++}
++
++static unsigned long clk_scmi_cpub01_get_rate(rk_scmi_clock_t *clock)
++{
++	int value, src, div;
++
++	value = mmio_read_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0));
++	src = (value & 0x6000) >> 13;
++	if (src == 2) {
++		return sys_clk_info.cpub01_rate;
++	} else {
++		src = (value & 0x00c0) >> 6;
++		div = (value & 0x1f00) >> 8;
++		switch (src) {
++		case 0:
++			return 24000000;
++		case 1:
++			/* Make the return rate is equal to the set rate */
++			if (sys_clk_info.cpub01_rate)
++				return sys_clk_info.cpub01_rate;
++			else
++				return GPLL_RATE / (div + 1);
++		case 2:
++			return rk3588_b0pll_get_rate();
++		default:
++			return 0;
++		}
++	}
++}
++
++static int clk_scmi_cpub01_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static void clk_scmi_b1pll_disable(void)
++{
++	static bool is_b1pll_disabled;
++
++	if (is_b1pll_disabled != 0)
++		return;
++
++	/* set coreb23 mux gpll */
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0),
++		      CPUB01_CLK_PATH_NOR_GPLL);
++	 /* pll enter slow mode */
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_MODE_CON0, CPU_PLL_PATH_SLOWMODE);
++	/* set pll power down */
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_PLL_CON(9), CRU_PLL_POWER_DOWN);
++
++	is_b1pll_disabled = true;
++}
++
++static int clk_cpub23_set_rate(unsigned long rate, enum pll_type_sel type)
++{
++	struct pvtpll_table *pvtpll;
++	int div;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpub23_table,
++					 sys_clk_info.cpub23_rate_count, rate);
++	if (pvtpll == NULL)
++		return SCMI_INVALID_PARAMETERS;
++
++	/* set b1pll */
++	if (PVTPLL_NEED(type, pvtpll->length)) {
++		/* set clock gating interval */
++		mmio_write_32(BIGCORE1GRF_BASE + RK3588_CPUB_PVTPLL_CON2,
++			      0x00040000);
++		/* set ring sel */
++		mmio_write_32(BIGCORE1GRF_BASE + RK3588_CPUB_PVTPLL_CON0_L,
++			      0x07000000 | (pvtpll->ring_sel << 8));
++		/* set length */
++		mmio_write_32(BIGCORE1GRF_BASE + RK3588_CPUB_PVTPLL_CON0_H,
++			      0x003f0000 | pvtpll->length);
++		/* set cal cnt = 24, T = 1us */
++		mmio_write_32(BIGCORE1GRF_BASE + RK3588_CPUB_PVTPLL_CON1,
++			      0x18);
++		/* enable pvtpll */
++		mmio_write_32(BIGCORE1GRF_BASE + RK3588_CPUB_PVTPLL_CON0_L,
++			      0x00020002);
++		/* start monitor */
++		mmio_write_32(BIGCORE1GRF_BASE + RK3588_CPUB_PVTPLL_CON0_L,
++			      0x00010001);
++		/* set core mux pvtpll */
++		mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(2),
++			      CPUB01_PVTPLL_PATH_PVTPLL);
++		mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0),
++			      CPUB01_CLK_PATH_B0_PVTPLL);
++		mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(1),
++			      CPUB01_CLK_PATH_B1_PVTPLL);
++		goto out;
++	}
++
++	/* set clk coreb23 div */
++	div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0),
++		      CLKDIV_5BITS_SHF(div, 8));
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(1),
++		      CLKDIV_5BITS_SHF(div, 0));
++	/* set coreb23 mux gpll */
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0),
++		      CPUB01_CLK_PATH_NOR_GPLL);
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0),
++		      CPUB01_CLK_PATH_B0PLL);
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(1),
++		      CPUB01_CLK_PATH_B1PLL);
++
++out:
++	clk_scmi_b1pll_disable();
++
++	return 0;
++}
++
++static int clk_scmi_cpub23_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int ret;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	ret = clk_cpub23_set_rate(rate, PLL_SEL_AUTO);
++	if (ret == 0)
++		sys_clk_info.cpub23_rate = rate;
++
++	return ret;
++}
++
++static unsigned long rk3588_b1pll_get_rate(void)
++{
++	unsigned int m, p, s, k;
++	uint64_t rate64 = 24000000, postdiv;
++	int mode;
++
++	mode = (mmio_read_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0)) >> 6) &
++	       0x3;
++
++	if (mode == 0)
++		return rate64;
++
++	m = (mmio_read_32(BIGCORE1CRU_BASE + CRU_PLL_CON(8)) >>
++		 CRU_PLLCON0_M_SHIFT) &
++		CRU_PLLCON0_M_MASK;
++	p = (mmio_read_32(BIGCORE1CRU_BASE + CRU_PLL_CON(9)) >>
++		    CRU_PLLCON1_P_SHIFT) &
++		   CRU_PLLCON1_P_MASK;
++	s = (mmio_read_32(BIGCORE1CRU_BASE + CRU_PLL_CON(9)) >>
++		  CRU_PLLCON1_S_SHIFT) &
++		 CRU_PLLCON1_S_MASK;
++	k = (mmio_read_32(BIGCORE1CRU_BASE + CRU_PLL_CON(10)) >>
++		    CRU_PLLCON2_K_SHIFT) &
++		   CRU_PLLCON2_K_MASK;
++
++	rate64 *= m;
++	rate64 = rate64 / p;
++
++	if (k != 0) {
++		/* fractional mode */
++		uint64_t frac_rate64 = 24000000 * k;
++
++		postdiv = p * 65535;
++		frac_rate64 = frac_rate64 / postdiv;
++		rate64 += frac_rate64;
++	}
++	rate64 = rate64 >> s;
++
++	return (unsigned long)rate64;
++}
++
++static unsigned long clk_scmi_cpub23_get_rate(rk_scmi_clock_t *clock)
++{
++	int value, src, div;
++
++	value = mmio_read_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0));
++	src = (value & 0x6000) >> 13;
++	if (src == 2) {
++		return sys_clk_info.cpub23_rate;
++	} else {
++		src = (value & 0x00c0) >> 6;
++		div = (value & 0x1f00) >> 8;
++		switch (src) {
++		case 0:
++			return 24000000;
++		case 1:
++			/* Make the return rate is equal to the set rate */
++			if (sys_clk_info.cpub23_rate)
++				return sys_clk_info.cpub23_rate;
++			else
++				return GPLL_RATE / (div + 1);
++		case 2:
++			return rk3588_b1pll_get_rate();
++		default:
++			return 0;
++		}
++	}
++}
++
++static int clk_scmi_cpub23_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_dsu_get_rate(rk_scmi_clock_t *clock)
++{
++	int src, div;
++
++	src = mmio_read_32(DSUCRU_BASE + CRU_CLKSEL_CON(1)) & 0x1;
++	if (src != 0) {
++		return sys_clk_info.dsu_rate;
++	} else {
++		src = mmio_read_32(DSUCRU_BASE + CRU_CLKSEL_CON(0)) & 0x3000;
++		src = src >> 12;
++		div = mmio_read_32(DSUCRU_BASE + CRU_CLKSEL_CON(0)) & 0xf80;
++		div = div >> 7;
++		switch (src) {
++		case 0:
++			return rk3588_b0pll_get_rate() / (div + 1);
++		case 1:
++			return rk3588_b1pll_get_rate() / (div + 1);
++		case 2:
++			return rk3588_lpll_get_rate() / (div + 1);
++		case 3:
++			return GPLL_RATE / (div + 1);
++		default:
++			return 0;
++		}
++	}
++}
++
++static void clk_scmi_lpll_disable(void)
++{
++	static bool is_lpll_disabled;
++
++	if (is_lpll_disabled)
++		return;
++
++	/* set corel mux gpll */
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(5),
++		      CPUL_CLK_PATH_NOR_GPLL);
++	/* set dsu mux gpll */
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(0),
++		      SCLK_DSU_PATH_NOR_GPLL);
++	/* pll enter slow mode */
++	mmio_write_32(DSUCRU_BASE + CRU_MODE_CON0, CPU_PLL_PATH_SLOWMODE);
++	/* set pll power down */
++	mmio_write_32(DSUCRU_BASE + CRU_PLL_CON(17), CRU_PLL_POWER_DOWN);
++
++	is_lpll_disabled = true;
++}
++
++static int clk_dsu_set_rate(unsigned long rate, enum pll_type_sel type)
++{
++	struct pvtpll_table *pvtpll;
++	int div;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.cpul_table,
++					 sys_clk_info.cpul_rate_count, rate);
++	if (pvtpll == NULL)
++		return SCMI_INVALID_PARAMETERS;
++
++	/* set pvtpll */
++	if (PVTPLL_NEED(type, pvtpll->length)) {
++		/* set clock gating interval */
++		mmio_write_32(DSUGRF_BASE + RK3588_DSU_PVTPLL_CON2,
++			      0x00040000);
++		/* set ring sel */
++		mmio_write_32(DSUGRF_BASE + RK3588_DSU_PVTPLL_CON0_L,
++			      0x07000000 | (pvtpll->ring_sel << 8));
++		/* set length */
++		mmio_write_32(DSUGRF_BASE + RK3588_DSU_PVTPLL_CON0_H,
++			      0x003f0000 | pvtpll->length);
++		/* set cal cnt = 24, T = 1us */
++		mmio_write_32(DSUGRF_BASE + RK3588_DSU_PVTPLL_CON1,
++			      0x18);
++		/* enable pvtpll */
++		mmio_write_32(DSUGRF_BASE + RK3588_DSU_PVTPLL_CON0_L,
++			      0x00020002);
++		/* start monitor */
++		mmio_write_32(DSUGRF_BASE + RK3588_DSU_PVTPLL_CON0_L,
++			      0x00010001);
++		/* set dsu mux pvtpll */
++		mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(7),
++			      DSU_PVTPLL_PATH_PVTPLL);
++		mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(1),
++			      SCLK_DSU_PATH_PVTPLL);
++		goto out;
++	}
++	/* set dsu div */
++	div = DIV_ROUND_UP(GPLL_RATE, rate) - 1;
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(0),
++		      CLKDIV_5BITS_SHF(div, 7));
++	/* set dsu mux gpll */
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(0),
++		      SCLK_DSU_PATH_NOR_GPLL);
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(1),
++		      SCLK_DSU_PATH_NOR_PLL);
++
++out:
++	clk_scmi_lpll_disable();
++
++	return 0;
++}
++
++static int clk_scmi_dsu_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int ret;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	ret = clk_dsu_set_rate(rate, PLL_SEL_AUTO);
++
++	if (ret == 0)
++		sys_clk_info.dsu_rate = rate;
++	return ret;
++}
++
++static int clk_scmi_dsu_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_gpu_get_rate(rk_scmi_clock_t *clock)
++{
++	int div, src;
++
++	if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(158)) & 0x4000) != 0) {
++		return sys_clk_info.gpu_rate;
++	} else {
++		div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(158)) & 0x1f;
++		src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(158)) & 0x00e0;
++		src = src >> 5;
++		switch (src) {
++		case 0:
++			/* Make the return rate is equal to the set rate */
++			if (sys_clk_info.gpu_rate)
++				return sys_clk_info.gpu_rate;
++			else
++				return GPLL_RATE / (div + 1);
++		case 1:
++			return CPLL_RATE / (div + 1);
++		case 2:
++			return AUPLL_RATE / (div + 1);
++		case 3:
++			return NPLL_RATE / (div + 1);
++		case 4:
++			return SPLL_RATE / (div + 1);
++		default:
++			return 0;
++		}
++	}
++}
++
++static int clk_gpu_set_rate(unsigned long rate, enum pll_type_sel type)
++{
++	struct pvtpll_table *pvtpll;
++	int div;
++
++	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.gpu_table,
++					 sys_clk_info.gpu_rate_count, rate);
++	if (pvtpll == NULL)
++		return SCMI_INVALID_PARAMETERS;
++
++	if (PVTPLL_NEED(type, pvtpll->length)) {
++		/* set clock gating interval */
++		mmio_write_32(GPUGRF_BASE + RK3588_GPU_PVTPLL_CON2,
++			      0x00040000);
++		/* set ring sel */
++		mmio_write_32(GPUGRF_BASE + RK3588_GPU_PVTPLL_CON0_L,
++			      0x07000000 | (pvtpll->ring_sel << 8));
++		/* set length */
++		mmio_write_32(GPUGRF_BASE + RK3588_GPU_PVTPLL_CON0_H,
++			      0x003f0000 | pvtpll->length);
++		/* set cal cnt = 24, T = 1us */
++		mmio_write_32(GPUGRF_BASE + RK3588_GPU_PVTPLL_CON1,
++			      0x18);
++		/* enable pvtpll */
++		mmio_write_32(GPUGRF_BASE + RK3588_GPU_PVTPLL_CON0_L,
++			      0x00020002);
++		/* start monitor */
++		mmio_write_32(GPUGRF_BASE + RK3588_GPU_PVTPLL_CON0_L,
++			      0x00010001);
++		/* set gpu mux pvtpll */
++		mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(158),
++			      GPU_CLK_PATH_PVTPLL);
++		return 0;
++	}
++
++	/* set gpu div */
++	div = DIV_ROUND_UP(GPLL_RATE, rate);
++	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(158),
++		      CLKDIV_5BITS_SHF(div - 1, 0));
++	/* set gpu mux gpll */
++	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(158),
++		      GPU_CLK_PATH_NOR_GPLL);
++	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(158),
++		      GPU_CLK_PATH_NOR_PLL);
++
++	return 0;
++}
++
++static int clk_scmi_gpu_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int ret;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	ret = clk_gpu_set_rate(rate, PLL_SEL_AUTO);
++	if (ret == 0)
++		sys_clk_info.gpu_rate = rate;
++
++	return ret;
++}
++
++static int clk_scmi_gpu_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_npu_get_rate(rk_scmi_clock_t *clock)
++{
++	int div, src;
++
++	if ((mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(74)) & 0x1) != 0) {
++		return sys_clk_info.npu_rate;
++	} else {
++		div = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(73)) & 0x007c;
++		div = div >> 2;
++		src = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(73)) & 0x0380;
++		src = src >> 7;
++		switch (src) {
++		case 0:
++			/* Make the return rate is equal to the set rate */
++			if (sys_clk_info.npu_rate != 0)
++				return sys_clk_info.npu_rate;
++			else
++				return GPLL_RATE / (div + 1);
++		case 1:
++			return CPLL_RATE / (div + 1);
++		case 2:
++			return AUPLL_RATE / (div + 1);
++		case 3:
++			return NPLL_RATE / (div + 1);
++		case 4:
++			return SPLL_RATE / (div + 1);
++		default:
++			return 0;
++		}
++	}
++}
++
++static int clk_npu_set_rate(unsigned long rate, enum pll_type_sel type)
++{
++	struct pvtpll_table *pvtpll;
++	int div;
++
++	pvtpll = rkclk_get_pvtpll_config(sys_clk_info.npu_table,
++					 sys_clk_info.npu_rate_count, rate);
++	if (pvtpll == NULL)
++		return SCMI_INVALID_PARAMETERS;
++
++	if (PVTPLL_NEED(type, pvtpll->length)) {
++		/* set clock gating interval */
++		mmio_write_32(NPUGRF_BASE + RK3588_NPU_PVTPLL_CON2,
++			      0x00040000);
++		/* set ring sel */
++		mmio_write_32(NPUGRF_BASE + RK3588_NPU_PVTPLL_CON0_L,
++			      0x07000000 | (pvtpll->ring_sel << 8));
++		/* set length */
++		mmio_write_32(NPUGRF_BASE + RK3588_NPU_PVTPLL_CON0_H,
++			      0x003f0000 | pvtpll->length);
++		/* set cal cnt = 24, T = 1us */
++		mmio_write_32(NPUGRF_BASE + RK3588_NPU_PVTPLL_CON1,
++			      0x18);
++		/* enable pvtpll */
++		mmio_write_32(NPUGRF_BASE + RK3588_NPU_PVTPLL_CON0_L,
++			      0x00020002);
++		/* start monitor */
++		mmio_write_32(NPUGRF_BASE + RK3588_NPU_PVTPLL_CON0_L,
++			      0x00010001);
++		/* set npu mux pvtpll */
++		mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(74),
++			      NPU_CLK_PATH_PVTPLL);
++		return 0;
++	}
++
++	/* set npu div */
++	div = DIV_ROUND_UP(GPLL_RATE, rate);
++	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(73),
++		      CLKDIV_5BITS_SHF(div - 1, 2));
++	/* set npu mux gpll */
++	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(73),
++		      NPU_CLK_PATH_NOR_GPLL);
++	mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(74),
++		      NPU_CLK_PATH_NOR_PLL);
++
++	return 0;
++}
++
++static int clk_scmi_npu_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int ret;
++
++	if (rate == 0)
++		return SCMI_INVALID_PARAMETERS;
++
++	ret = clk_npu_set_rate(rate, PLL_SEL_AUTO);
++	if (ret == 0)
++		sys_clk_info.npu_rate = rate;
++
++	return ret;
++}
++
++static int clk_scmi_npu_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_sbus_get_rate(rk_scmi_clock_t *clock)
++{
++	int div;
++
++	if ((mmio_read_32(BUSSCRU_BASE + CRU_CLKSEL_CON(0)) & 0x0800) != 0) {
++		div = mmio_read_32(BUSSCRU_BASE + CRU_CLKSEL_CON(0));
++		div = (div & 0x03e0) >> 5;
++		return SPLL_RATE / (div + 1);
++	} else {
++		return OSC_HZ;
++	}
++}
++
++static int clk_scmi_sbus_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int div;
++
++	if (rate == OSC_HZ) {
++		mmio_write_32(BUSSCRU_BASE + CRU_CLKSEL_CON(0),
++			      WMSK_BIT(11));
++		return 0;
++	}
++
++	div = DIV_ROUND_UP(SPLL_RATE, rate);
++	mmio_write_32(BUSSCRU_BASE + CRU_CLKSEL_CON(0),
++		      CLKDIV_5BITS_SHF(div - 1, 5));
++	mmio_write_32(BUSSCRU_BASE + CRU_CLKSEL_CON(0),
++		      BIT_WITH_WMSK(11) | WMSK_BIT(10));
++	return 0;
++}
++
++static int clk_scmi_sbus_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_pclk_sbus_get_rate(rk_scmi_clock_t *clock)
++{
++	int div;
++
++	div = mmio_read_32(BUSSCRU_BASE + CRU_CLKSEL_CON(0));
++	div = div & 0x001f;
++	return SPLL_RATE / (div + 1);
++
++}
++
++static int clk_scmi_pclk_sbus_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int div;
++
++	div = DIV_ROUND_UP(SPLL_RATE, rate);
++	mmio_write_32(BUSSCRU_BASE + CRU_CLKSEL_CON(0),
++		      CLKDIV_5BITS_SHF(div - 1, 0));
++	return 0;
++}
++
++static int clk_scmi_pclk_sbus_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_cclk_sdmmc_get_rate(rk_scmi_clock_t *clock)
++{
++	int div;
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(3)) & 0x3000;
++	src = src >> 12;
++	div = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(3)) & 0x0fc0;
++	div = div >> 6;
++	if (src == 1) {
++		return SPLL_RATE / (div + 1);
++	} else if (src == 2) {
++		return OSC_HZ / (div + 1);
++	} else {
++		return GPLL_RATE / (div + 1);
++	}
++}
++
++static int clk_scmi_cclk_sdmmc_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int div;
++
++	if ((OSC_HZ % rate) == 0) {
++		div = DIV_ROUND_UP(OSC_HZ, rate);
++		mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(3),
++			      CLKDIV_6BITS_SHF(div - 1, 6) |
++			      BITS_WITH_WMASK(2U, 0x3U, 12));
++	} else if ((SPLL_RATE % rate) == 0) {
++		div = DIV_ROUND_UP(SPLL_RATE, rate);
++		mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(3),
++			      CLKDIV_6BITS_SHF(div - 1, 6) |
++			      BITS_WITH_WMASK(1U, 0x3U, 12));
++	} else {
++		div = DIV_ROUND_UP(GPLL_RATE, rate);
++		mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(3),
++			      CLKDIV_6BITS_SHF(div - 1, 6) |
++			      BITS_WITH_WMASK(0U, 0x3U, 12));
++	}
++
++	return 0;
++}
++
++static int clk_scmi_cclk_sdmmc_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(3),
++		      BITS_WITH_WMASK(!status, 0x1U, 4));
++	return 0;
++}
++
++static unsigned long clk_scmi_dclk_sdmmc_get_rate(rk_scmi_clock_t *clock)
++{
++	int div;
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(3)) & 0x0020;
++	div = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(3)) & 0x001f;
++	if (src != 0) {
++		return SPLL_RATE / (div + 1);
++	} else {
++		return GPLL_RATE / (div + 1);
++	}
++}
++
++static int clk_scmi_dclk_sdmmc_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	int div;
++
++	if ((SPLL_RATE % rate) == 0) {
++		div = DIV_ROUND_UP(SPLL_RATE, rate);
++		mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(3),
++			      CLKDIV_5BITS_SHF(div - 1, 0) |
++			      BITS_WITH_WMASK(1U, 0x1U, 5));
++	} else {
++		div = DIV_ROUND_UP(GPLL_RATE, rate);
++		mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(3),
++			      CLKDIV_5BITS_SHF(div - 1, 0) |
++			      BITS_WITH_WMASK(0U, 0x1U, 5));
++	}
++	return 0;
++}
++
++static int clk_scmi_dclk_sdmmc_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(3),
++		      BITS_WITH_WMASK(!status, 0x1U, 1));
++	return 0;
++}
++
++static unsigned long clk_scmi_aclk_secure_ns_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0x0003;
++	switch (src) {
++	case 0:
++		return 350 * MHz;
++	case 1:
++		return 200 * MHz;
++	case 2:
++		return 100 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_aclk_secure_ns_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 350 * MHz)
++		src = 0;
++	else if (rate >= 200 * MHz)
++		src = 1;
++	else if (rate >= 100 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 0));
++
++	return 0;
++}
++
++static int clk_scmi_aclk_secure_ns_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_hclk_secure_ns_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0x000c;
++	src = src >> 2;
++	switch (src) {
++	case 0:
++		return 150 * MHz;
++	case 1:
++		return 100 * MHz;
++	case 2:
++		return 50 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_hclk_secure_ns_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 150 * MHz)
++		src = 0;
++	else if (rate >= 100 * MHz)
++		src = 1;
++	else if (rate >= 50 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 2));
++	return 0;
++}
++
++static int clk_scmi_hclk_secure_ns_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_tclk_wdt_get_rate(rk_scmi_clock_t *clock)
++{
++	return OSC_HZ;
++}
++
++static int clk_scmi_tclk_wdt_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(2),
++		      BITS_WITH_WMASK(!status, 0x1U, 0));
++	return 0;
++}
++
++static unsigned long clk_scmi_keyladder_core_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(2)) & 0x00c0;
++	src = src >> 6;
++	switch (src) {
++	case 0:
++		return 350 * MHz;
++	case 1:
++		return 233 * MHz;
++	case 2:
++		return 116 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_keyladder_core_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 350 * MHz)
++		src = 0;
++	else if (rate >= 233 * MHz)
++		src = 1;
++	else if (rate >= 116 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(2),
++		      BITS_WITH_WMASK(src, 0x3U, 6));
++	return 0;
++}
++
++static int clk_scmi_keyladder_core_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 9));
++	return 0;
++}
++
++static unsigned long clk_scmi_keyladder_rng_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(2)) & 0x0300;
++	src = src >> 8;
++	switch (src) {
++	case 0:
++		return 175 * MHz;
++	case 1:
++		return 116 * MHz;
++	case 2:
++		return 58 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_keyladder_rng_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 175 * MHz)
++		src = 0;
++	else if (rate >= 116 * MHz)
++		src = 1;
++	else if (rate >= 58 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(2),
++		      BITS_WITH_WMASK(src, 0x3U, 8));
++	return 0;
++}
++
++static int clk_scmi_keyladder_rng_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 10));
++	return 0;
++}
++
++static unsigned long clk_scmi_aclk_secure_s_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0x0030;
++	src = src >> 4;
++	switch (src) {
++	case 0:
++		return 350 * MHz;
++	case 1:
++		return 233 * MHz;
++	case 2:
++		return 116 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_aclk_secure_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 350 * MHz)
++		src = 0;
++	else if (rate >= 233 * MHz)
++		src = 1;
++	else if (rate >= 116 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 4));
++	return 0;
++}
++
++static int clk_scmi_aclk_secure_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_hclk_secure_s_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0x00c0;
++	src = src >> 6;
++	switch (src) {
++	case 0:
++		return 175 * MHz;
++	case 1:
++		return 116 * MHz;
++	case 2:
++		return 58 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_hclk_secure_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 175 * MHz)
++		src = 0;
++	else if (rate >= 116 * MHz)
++		src = 1;
++	else if (rate >= 58 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 6));
++	return 0;
++}
++
++static int clk_scmi_hclk_secure_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_pclk_secure_s_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0x0300;
++	src = src >> 8;
++	switch (src) {
++	case 0:
++		return 116 * MHz;
++	case 1:
++		return 58 * MHz;
++	case 2:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_pclk_secure_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 116 * MHz)
++		src = 0;
++	else if (rate >= 58 * MHz)
++		src = 1;
++	else
++		src = 2;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 8));
++	return 0;
++}
++
++static int clk_scmi_pclk_secure_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_crypto_rng_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0xc000;
++	src = src >> 14;
++	switch (src) {
++	case 0:
++		return 175 * MHz;
++	case 1:
++		return 116 * MHz;
++	case 2:
++		return 58 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_crypto_rng_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 175 * MHz)
++		src = 0;
++	else if (rate >= 116 * MHz)
++		src = 1;
++	else if (rate >= 58 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 14));
++	return 0;
++}
++
++static int clk_scmi_crypto_rng_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 1));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_crypto_core_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0x0c00;
++	src = src >> 10;
++	switch (src) {
++	case 0:
++		return 350 * MHz;
++	case 1:
++		return 233 * MHz;
++	case 2:
++		return 116 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_crypto_core_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 350 * MHz)
++		src = 0;
++	else if (rate >= 233 * MHz)
++		src = 1;
++	else if (rate >= 116 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 10));
++	return 0;
++}
++
++static int clk_scmi_crypto_core_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(0),
++		      BITS_WITH_WMASK(!status, 0x1U, 15));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_crypto_pka_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(1)) & 0x3000;
++	src = src >> 12;
++	switch (src) {
++	case 0:
++		return 350 * MHz;
++	case 1:
++		return 233 * MHz;
++	case 2:
++		return 116 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_crypto_pka_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 350 * MHz)
++		src = 0;
++	else if (rate >= 233 * MHz)
++		src = 1;
++	else if (rate >= 116 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(1),
++		      BITS_WITH_WMASK(src, 0x3U, 12));
++	return 0;
++}
++
++static int clk_scmi_crypto_pka_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 0));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_spll_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(BUSSCRU_BASE + CRU_MODE_CON0) & 0x3;
++	switch (src) {
++	case 0:
++		return OSC_HZ;
++	case 1:
++		return 702 * MHz;
++	case 2:
++		return 32768;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_spll_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 700 * MHz)
++		src = 1;
++	else
++		src = 0;
++
++	mmio_write_32(BUSSCRU_BASE + CRU_MODE_CON0,
++		      BITS_WITH_WMASK(0, 0x3U, 0));
++	mmio_write_32(BUSSCRU_BASE + CRU_PLL_CON(137),
++		      BITS_WITH_WMASK(2, 0x7U, 6));
++
++	mmio_write_32(BUSSCRU_BASE + CRU_MODE_CON0,
++		      BITS_WITH_WMASK(src, 0x3U, 0));
++	return 0;
++}
++
++static int clk_scmi_spll_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	return 0;
++}
++
++static unsigned long clk_scmi_hclk_sd_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_hclk_secure_ns_get_rate(clock);
++}
++
++static int clk_scmi_hclk_sd_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(3),
++		      BITS_WITH_WMASK(!status, 0x1U, 2));
++	return 0;
++}
++
++static unsigned long clk_scmi_crypto_rng_s_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(2)) & 0x0030;
++	src = src >> 4;
++	switch (src) {
++	case 0:
++		return 175 * MHz;
++	case 1:
++		return 116 * MHz;
++	case 2:
++		return 58 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_crypto_rng_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 175 * MHz)
++		src = 0;
++	else if (rate >= 116 * MHz)
++		src = 1;
++	else if (rate >= 58 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(2),
++		      BITS_WITH_WMASK(src, 0x3U, 4));
++	return 0;
++}
++
++static int clk_scmi_crypto_rng_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 6));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_crypto_core_s_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(2)) & 0x3;
++	src = src >> 0;
++	switch (src) {
++	case 0:
++		return 350 * MHz;
++	case 1:
++		return 233 * MHz;
++	case 2:
++		return 116 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_crypto_core_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 350 * MHz)
++		src = 0;
++	else if (rate >= 233 * MHz)
++		src = 1;
++	else if (rate >= 116 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(2),
++		      BITS_WITH_WMASK(src, 0x3U, 0));
++	return 0;
++}
++
++static int clk_scmi_crypto_core_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 4));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_crypto_pka_s_get_rate(rk_scmi_clock_t *clock)
++{
++	uint32_t src;
++
++	src = mmio_read_32(SCRU_BASE + CRU_CLKSEL_CON(2)) & 0x000c;
++	src = src >> 2;
++	switch (src) {
++	case 0:
++		return 350 * MHz;
++	case 1:
++		return 233 * MHz;
++	case 2:
++		return 116 * MHz;
++	case 3:
++		return OSC_HZ;
++	default:
++		return 0;
++	}
++}
++
++static int clk_scmi_crypto_pka_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	uint32_t src;
++
++	if (rate >= 350 * MHz)
++		src = 0;
++	else if (rate >= 233 * MHz)
++		src = 1;
++	else if (rate >= 116 * MHz)
++		src = 2;
++	else
++		src = 3;
++
++	mmio_write_32(SCRU_BASE + CRU_CLKSEL_CON(2),
++		      BITS_WITH_WMASK(src, 0x3U, 2));
++	return 0;
++}
++
++static int clk_scmi_crypto_pka_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 5));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_a_crypto_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_aclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_a_crypto_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_aclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_a_crypto_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 7));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_h_crypto_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_hclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_h_crypto_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_hclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_h_crypto_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 8));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_p_crypto_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_pclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_p_crypto_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_pclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_p_crypto_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(2),
++		      BITS_WITH_WMASK(!status, 0x1U, 13));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_a_keylad_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_aclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_a_keylad_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_aclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_a_keylad_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 11));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_h_keylad_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_hclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_h_keylad_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_hclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_h_keylad_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 12));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_p_keylad_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_pclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_p_keylad_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_pclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_p_keylad_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(2),
++		      BITS_WITH_WMASK(!status, 0x1U, 14));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_trng_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_hclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_trng_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_hclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_trng_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(3),
++		      BITS_WITH_WMASK(!status, 0x1U, 6));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_h_trng_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_hclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_h_trng_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_hclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_h_trng_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(2),
++		      BITS_WITH_WMASK(!status, 0x1U, 15));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_p_otpc_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return clk_scmi_pclk_secure_s_get_rate(clock);
++}
++
++static int clk_scmi_p_otpc_s_set_rate(rk_scmi_clock_t *clock, unsigned long rate)
++{
++	return clk_scmi_pclk_secure_s_set_rate(clock, rate);
++}
++
++static int clk_scmi_p_otpc_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 13));
++
++	return 0;
++}
++
++static unsigned long clk_scmi_otpc_s_get_rate(rk_scmi_clock_t *clock)
++{
++	return OSC_HZ;
++}
++
++static int clk_scmi_otpc_s_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(SCRU_BASE + CRU_CLKGATE_CON(1),
++		      BITS_WITH_WMASK(!status, 0x1U, 14));
++	return 0;
++}
++
++static unsigned long clk_scmi_otp_phy_get_rate(rk_scmi_clock_t *clock)
++{
++	return OSC_HZ;
++}
++
++static int clk_scmi_otp_phy_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
++		      BITS_WITH_WMASK(!status, 0x1U, 13));
++	return 0;
++}
++
++static unsigned long clk_scmi_otpc_rd_get_rate(rk_scmi_clock_t *clock)
++{
++	return OSC_HZ;
++}
++
++static int clk_scmi_otpc_rd_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
++		      BITS_WITH_WMASK(!status, 0x1U, 12));
++	return 0;
++}
++
++static unsigned long clk_scmi_otpc_arb_get_rate(rk_scmi_clock_t *clock)
++{
++	return OSC_HZ;
++}
++
++static int clk_scmi_otpc_arb_set_status(rk_scmi_clock_t *clock, bool status)
++{
++	mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18),
++		      BITS_WITH_WMASK(!status, 0x1U, 11));
++	return 0;
++}
++
++static const struct rk_clk_ops clk_scmi_cpul_ops = {
++	.get_rate = clk_scmi_cpul_get_rate,
++	.set_rate = clk_scmi_cpul_set_rate,
++	.set_status = clk_scmi_cpul_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_dsu_ops = {
++	.get_rate = clk_scmi_dsu_get_rate,
++	.set_rate = clk_scmi_dsu_set_rate,
++	.set_status = clk_scmi_dsu_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_cpub01_ops = {
++	.get_rate = clk_scmi_cpub01_get_rate,
++	.set_rate = clk_scmi_cpub01_set_rate,
++	.set_status = clk_scmi_cpub01_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_cpub23_ops = {
++	.get_rate = clk_scmi_cpub23_get_rate,
++	.set_rate = clk_scmi_cpub23_set_rate,
++	.set_status = clk_scmi_cpub23_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_gpu_ops = {
++	.get_rate = clk_scmi_gpu_get_rate,
++	.set_rate = clk_scmi_gpu_set_rate,
++	.set_status = clk_scmi_gpu_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_npu_ops = {
++	.get_rate = clk_scmi_npu_get_rate,
++	.set_rate = clk_scmi_npu_set_rate,
++	.set_status = clk_scmi_npu_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_sbus_ops = {
++	.get_rate = clk_scmi_sbus_get_rate,
++	.set_rate = clk_scmi_sbus_set_rate,
++	.set_status = clk_scmi_sbus_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_pclk_sbus_ops = {
++	.get_rate = clk_scmi_pclk_sbus_get_rate,
++	.set_rate = clk_scmi_pclk_sbus_set_rate,
++	.set_status = clk_scmi_pclk_sbus_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_cclk_sdmmc_ops = {
++	.get_rate = clk_scmi_cclk_sdmmc_get_rate,
++	.set_rate = clk_scmi_cclk_sdmmc_set_rate,
++	.set_status = clk_scmi_cclk_sdmmc_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_dclk_sdmmc_ops = {
++	.get_rate = clk_scmi_dclk_sdmmc_get_rate,
++	.set_rate = clk_scmi_dclk_sdmmc_set_rate,
++	.set_status = clk_scmi_dclk_sdmmc_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_aclk_secure_ns_ops = {
++	.get_rate = clk_scmi_aclk_secure_ns_get_rate,
++	.set_rate = clk_scmi_aclk_secure_ns_set_rate,
++	.set_status = clk_scmi_aclk_secure_ns_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_hclk_secure_ns_ops = {
++	.get_rate = clk_scmi_hclk_secure_ns_get_rate,
++	.set_rate = clk_scmi_hclk_secure_ns_set_rate,
++	.set_status = clk_scmi_hclk_secure_ns_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_tclk_wdt_ops = {
++	.get_rate = clk_scmi_tclk_wdt_get_rate,
++	.set_status = clk_scmi_tclk_wdt_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_keyladder_core_ops = {
++	.get_rate = clk_scmi_keyladder_core_get_rate,
++	.set_rate = clk_scmi_keyladder_core_set_rate,
++	.set_status = clk_scmi_keyladder_core_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_keyladder_rng_ops = {
++	.get_rate = clk_scmi_keyladder_rng_get_rate,
++	.set_rate = clk_scmi_keyladder_rng_set_rate,
++	.set_status = clk_scmi_keyladder_rng_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_aclk_secure_s_ops = {
++	.get_rate = clk_scmi_aclk_secure_s_get_rate,
++	.set_rate = clk_scmi_aclk_secure_s_set_rate,
++	.set_status = clk_scmi_aclk_secure_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_hclk_secure_s_ops = {
++	.get_rate = clk_scmi_hclk_secure_s_get_rate,
++	.set_rate = clk_scmi_hclk_secure_s_set_rate,
++	.set_status = clk_scmi_hclk_secure_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_pclk_secure_s_ops = {
++	.get_rate = clk_scmi_pclk_secure_s_get_rate,
++	.set_rate = clk_scmi_pclk_secure_s_set_rate,
++	.set_status = clk_scmi_pclk_secure_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_crypto_rng_ops = {
++	.get_rate = clk_scmi_crypto_rng_get_rate,
++	.set_rate = clk_scmi_crypto_rng_set_rate,
++	.set_status = clk_scmi_crypto_rng_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_crypto_core_ops = {
++	.get_rate = clk_scmi_crypto_core_get_rate,
++	.set_rate = clk_scmi_crypto_core_set_rate,
++	.set_status = clk_scmi_crypto_core_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_crypto_pka_ops = {
++	.get_rate = clk_scmi_crypto_pka_get_rate,
++	.set_rate = clk_scmi_crypto_pka_set_rate,
++	.set_status = clk_scmi_crypto_pka_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_spll_ops = {
++	.get_rate = clk_scmi_spll_get_rate,
++	.set_rate = clk_scmi_spll_set_rate,
++	.set_status = clk_scmi_spll_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_hclk_sd_ops = {
++	.get_rate = clk_scmi_hclk_sd_get_rate,
++	.set_status = clk_scmi_hclk_sd_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_crypto_rng_s_ops = {
++	.get_rate = clk_scmi_crypto_rng_s_get_rate,
++	.set_rate = clk_scmi_crypto_rng_s_set_rate,
++	.set_status = clk_scmi_crypto_rng_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_crypto_core_s_ops = {
++	.get_rate = clk_scmi_crypto_core_s_get_rate,
++	.set_rate = clk_scmi_crypto_core_s_set_rate,
++	.set_status = clk_scmi_crypto_core_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_crypto_pka_s_ops = {
++	.get_rate = clk_scmi_crypto_pka_s_get_rate,
++	.set_rate = clk_scmi_crypto_pka_s_set_rate,
++	.set_status = clk_scmi_crypto_pka_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_a_crypto_s_ops = {
++	.get_rate = clk_scmi_a_crypto_s_get_rate,
++	.set_rate = clk_scmi_a_crypto_s_set_rate,
++	.set_status = clk_scmi_a_crypto_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_h_crypto_s_ops = {
++	.get_rate = clk_scmi_h_crypto_s_get_rate,
++	.set_rate = clk_scmi_h_crypto_s_set_rate,
++	.set_status = clk_scmi_h_crypto_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_p_crypto_s_ops = {
++	.get_rate = clk_scmi_p_crypto_s_get_rate,
++	.set_rate = clk_scmi_p_crypto_s_set_rate,
++	.set_status = clk_scmi_p_crypto_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_a_keylad_s_ops = {
++	.get_rate = clk_scmi_a_keylad_s_get_rate,
++	.set_rate = clk_scmi_a_keylad_s_set_rate,
++	.set_status = clk_scmi_a_keylad_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_h_keylad_s_ops = {
++	.get_rate = clk_scmi_h_keylad_s_get_rate,
++	.set_rate = clk_scmi_h_keylad_s_set_rate,
++	.set_status = clk_scmi_h_keylad_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_p_keylad_s_ops = {
++	.get_rate = clk_scmi_p_keylad_s_get_rate,
++	.set_rate = clk_scmi_p_keylad_s_set_rate,
++	.set_status = clk_scmi_p_keylad_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_trng_s_ops = {
++	.get_rate = clk_scmi_trng_s_get_rate,
++	.set_rate = clk_scmi_trng_s_set_rate,
++	.set_status = clk_scmi_trng_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_h_trng_s_ops = {
++	.get_rate = clk_scmi_h_trng_s_get_rate,
++	.set_rate = clk_scmi_h_trng_s_set_rate,
++	.set_status = clk_scmi_h_trng_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_p_otpc_s_ops = {
++	.get_rate = clk_scmi_p_otpc_s_get_rate,
++	.set_rate = clk_scmi_p_otpc_s_set_rate,
++	.set_status = clk_scmi_p_otpc_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_otpc_s_ops = {
++	.get_rate = clk_scmi_otpc_s_get_rate,
++	.set_status = clk_scmi_otpc_s_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_otp_phy_ops = {
++	.get_rate = clk_scmi_otp_phy_get_rate,
++	.set_status = clk_scmi_otp_phy_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_otpc_rd_ops = {
++	.get_rate = clk_scmi_otpc_rd_get_rate,
++	.set_status = clk_scmi_otpc_rd_set_status,
++};
++
++static const struct rk_clk_ops clk_scmi_otpc_arb_ops = {
++	.get_rate = clk_scmi_otpc_arb_get_rate,
++	.set_status = clk_scmi_otpc_arb_set_status,
++};
++
++rk_scmi_clock_t clock_table[] = {
++	RK3588_SCMI_CLOCK(SCMI_CLK_CPUL, "scmi_clk_cpul", &clk_scmi_cpul_ops, rk3588_cpul_rates, ARRAY_SIZE(rk3588_cpul_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CLK_DSU, "scmi_clk_dsu", &clk_scmi_dsu_ops, rk3588_cpul_rates, ARRAY_SIZE(rk3588_cpul_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CLK_CPUB01, "scmi_clk_cpub01", &clk_scmi_cpub01_ops, rk3588_cpub_rates, ARRAY_SIZE(rk3588_cpub_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CLK_CPUB23, "scmi_clk_cpub23", &clk_scmi_cpub23_ops, rk3588_cpub_rates, ARRAY_SIZE(rk3588_cpub_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CLK_DDR, "scmi_clk_ddr", NULL, NULL, 0, false),
++	RK3588_SCMI_CLOCK(SCMI_CLK_GPU, "scmi_clk_gpu", &clk_scmi_gpu_ops, rk3588_gpu_rates, ARRAY_SIZE(rk3588_gpu_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CLK_NPU, "scmi_clk_npu", &clk_scmi_npu_ops, rk3588_gpu_rates, ARRAY_SIZE(rk3588_gpu_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CLK_SBUS, "scmi_clk_sbus", &clk_scmi_sbus_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_PCLK_SBUS, "scmi_pclk_sbus", &clk_scmi_pclk_sbus_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_CCLK_SD, "scmi_cclk_sd", &clk_scmi_cclk_sdmmc_ops, rk3588_sdmmc_rates, ARRAY_SIZE(rk3588_sdmmc_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_DCLK_SD, "scmi_dclk_sd", &clk_scmi_dclk_sdmmc_ops, rk3588_sdmmc_rates, ARRAY_SIZE(rk3588_sdmmc_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_ACLK_SECURE_NS, "scmi_aclk_se_ns", &clk_scmi_aclk_secure_ns_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_HCLK_SECURE_NS, "scmi_hclk_se_ns", &clk_scmi_hclk_secure_ns_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_TCLK_WDT, "scmi_tclk_wdt", &clk_scmi_tclk_wdt_ops, NULL, 0, false),
++	RK3588_SCMI_CLOCK(SCMI_KEYLADDER_CORE, "scmi_keylad_c", &clk_scmi_keyladder_core_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_KEYLADDER_RNG, "scmi_keylad_r", &clk_scmi_keyladder_rng_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_ACLK_SECURE_S, "scmi_aclk_se_s", &clk_scmi_aclk_secure_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_HCLK_SECURE_S, "scmi_hclk_se_s", &clk_scmi_hclk_secure_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_PCLK_SECURE_S, "scmi_pclk_se_s", &clk_scmi_pclk_secure_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_CRYPTO_RNG, "scmi_crypto_r", &clk_scmi_crypto_rng_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CRYPTO_CORE, "scmi_crypto_c", &clk_scmi_crypto_core_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_CRYPTO_PKA, "scmi_crypto_p", &clk_scmi_crypto_pka_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_SPLL, "scmi_spll", &clk_scmi_spll_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), false),
++	RK3588_SCMI_CLOCK(SCMI_HCLK_SD, "scmi_hclk_sd", &clk_scmi_hclk_sd_ops, NULL, 0, false),
++	RK3588_SCMI_CLOCK(SCMI_CRYPTO_RNG_S, "scmi_crypto_r_s", &clk_scmi_crypto_rng_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_CRYPTO_CORE_S, "scmi_crypto_c_s", &clk_scmi_crypto_core_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_CRYPTO_PKA_S, "scmi_crypto_p_s", &clk_scmi_crypto_pka_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_A_CRYPTO_S, "scmi_a_crypto_s", &clk_scmi_a_crypto_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_H_CRYPTO_S, "scmi_h_crypto_s", &clk_scmi_h_crypto_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_P_CRYPTO_S, "scmi_p_crypto_s", &clk_scmi_p_crypto_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_A_KEYLADDER_S, "scmi_a_keylad_s", &clk_scmi_a_keylad_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_H_KEYLADDER_S, "scmi_h_keylad_s", &clk_scmi_h_keylad_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_P_KEYLADDER_S, "scmi_p_keylad_s", &clk_scmi_p_keylad_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_TRNG_S, "scmi_trng_s", &clk_scmi_trng_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_H_TRNG_S, "scmi_h_trng_s", &clk_scmi_h_trng_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_P_OTPC_S, "scmi_p_otpc_s", &clk_scmi_p_otpc_s_ops, rk3588_sbus_rates, ARRAY_SIZE(rk3588_sbus_rates), true),
++	RK3588_SCMI_CLOCK(SCMI_OTPC_S, "scmi_otpc_s", &clk_scmi_otpc_s_ops, NULL, 0, true),
++	RK3588_SCMI_CLOCK(SCMI_OTP_PHY, "scmi_otp_phy", &clk_scmi_otp_phy_ops, NULL, 0, false),
++	RK3588_SCMI_CLOCK(SCMI_OTPC_AUTO_RD, "scmi_otpc_rd", &clk_scmi_otpc_rd_ops, NULL, 0, false),
++	RK3588_SCMI_CLOCK(SCMI_OTPC_ARB, "scmi_otpc_arb", &clk_scmi_otpc_arb_ops, NULL, 0, false),
++};
++
++size_t rockchip_scmi_clock_count(unsigned int agent_id __unused)
++{
++	return ARRAY_SIZE(clock_table);
++}
++
++rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id __unused,
++					 uint32_t clock_id)
++{
++	rk_scmi_clock_t *table = NULL;
++
++	if (clock_id < ARRAY_SIZE(clock_table))
++		table = &clock_table[clock_id];
++
++	if (table && !table->is_security)
++		return table;
++	else
++		return NULL;
++}
++
++void pvtplls_suspend(void)
++{
++	clk_cpul_set_rate(408000000, PLL_SEL_NOR);
++	clk_dsu_set_rate(408000000, PLL_SEL_NOR);
++	clk_cpub01_set_rate(408000000, PLL_SEL_NOR);
++	clk_cpub23_set_rate(408000000, PLL_SEL_NOR);
++}
++
++void pvtplls_resume(void)
++{
++	clk_cpul_set_rate(sys_clk_info.cpul_rate, PLL_SEL_AUTO);
++	clk_dsu_set_rate(sys_clk_info.dsu_rate, PLL_SEL_AUTO);
++	clk_cpub01_set_rate(sys_clk_info.cpub01_rate, PLL_SEL_AUTO);
++	clk_cpub23_set_rate(sys_clk_info.cpub23_rate, PLL_SEL_AUTO);
++}
++
++void sys_reset_pvtplls_prepare(void)
++{
++	clk_gpu_set_rate(100000000, PLL_SEL_NOR);
++	clk_npu_set_rate(100000000, PLL_SEL_NOR);
++	clk_cpul_set_rate(408000000, PLL_SEL_NOR);
++	clk_cpub01_set_rate(408000000, PLL_SEL_NOR);
++	clk_cpub23_set_rate(408000000, PLL_SEL_NOR);
++	clk_dsu_set_rate(408000000, PLL_SEL_NOR);
++}
++
++void rockchip_clock_init(void)
++{
++	/* set gpll src div to 0 for cpul */
++	mmio_write_32(DSUCRU_BASE + CRU_CLKSEL_CON(5), CLKDIV_5BITS_SHF(0U, 9));
++	/* set gpll src div to 0 for cpub01 */
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(0),
++		      CLKDIV_5BITS_SHF(0U, 1));
++	/* set gpll src div to 0 for cpu23 */
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(0),
++		      CLKDIV_5BITS_SHF(0U, 1));
++
++	mmio_write_32(BIGCORE0CRU_BASE + CRU_CLKSEL_CON(2),
++		      CPUB_PCLK_PATH_50M);
++	mmio_write_32(BIGCORE1CRU_BASE + CRU_CLKSEL_CON(2),
++		      CPUB_PCLK_PATH_50M);
++
++	mmio_write_32(DSUCRU_BASE + DSUCRU_CLKSEL_CON(4),
++		      CLKDIV_5BITS_SHF(5U, 0));
++	mmio_write_32(DSUCRU_BASE + DSUCRU_CLKSEL_CON(4),
++		      BITS_WITH_WMASK(PCLK_DSU_ROOT_SEL_GPLL,
++				      PCLK_DSU_ROOT_SEL_MASK,
++				      PCLK_DSU_ROOT_SEL_SHIFT));
++
++	sys_clk_info.cpul_table = rk3588_cpul_pvtpll_table;
++	sys_clk_info.cpul_rate_count = ARRAY_SIZE(rk3588_cpul_pvtpll_table);
++	sys_clk_info.cpub01_table = rk3588_cpub0_pvtpll_table;
++	sys_clk_info.cpub01_rate_count = ARRAY_SIZE(rk3588_cpub0_pvtpll_table);
++	sys_clk_info.cpub23_table = rk3588_cpub1_pvtpll_table;
++	sys_clk_info.cpub23_rate_count = ARRAY_SIZE(rk3588_cpub1_pvtpll_table);
++	memcpy(sys_clk_info.cpub23_table, sys_clk_info.cpub01_table,
++	       sys_clk_info.cpub01_rate_count * sizeof(*sys_clk_info.cpub01_table));
++	sys_clk_info.gpu_table = rk3588_gpu_pvtpll_table;
++	sys_clk_info.gpu_rate_count = ARRAY_SIZE(rk3588_gpu_pvtpll_table);
++	sys_clk_info.npu_table = rk3588_npu_pvtpll_table;
++	sys_clk_info.npu_rate_count = ARRAY_SIZE(rk3588_npu_pvtpll_table);
++}
+diff --git a/plat/rockchip/rk3588/drivers/scmi/rk3588_clk.h b/plat/rockchip/rk3588/drivers/scmi/rk3588_clk.h
+new file mode 100644
+index 000000000..66fddaa39
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/scmi/rk3588_clk.h
+@@ -0,0 +1,104 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#ifndef __CLOCK_H__
++#define __CLOCK_H__
++
++/* scmi-clocks indices */
++
++#define SCMI_CLK_CPUL			0
++#define SCMI_CLK_DSU			1
++#define SCMI_CLK_CPUB01			2
++#define SCMI_CLK_CPUB23			3
++#define SCMI_CLK_DDR			4
++#define SCMI_CLK_GPU			5
++#define SCMI_CLK_NPU			6
++#define SCMI_CLK_SBUS			7
++#define SCMI_PCLK_SBUS			8
++#define SCMI_CCLK_SD			9
++#define SCMI_DCLK_SD			10
++#define SCMI_ACLK_SECURE_NS		11
++#define SCMI_HCLK_SECURE_NS		12
++#define SCMI_TCLK_WDT			13
++#define SCMI_KEYLADDER_CORE		14
++#define SCMI_KEYLADDER_RNG		15
++#define SCMI_ACLK_SECURE_S		16
++#define SCMI_HCLK_SECURE_S		17
++#define SCMI_PCLK_SECURE_S		18
++#define SCMI_CRYPTO_RNG			19
++#define SCMI_CRYPTO_CORE		20
++#define SCMI_CRYPTO_PKA			21
++#define SCMI_SPLL			22
++#define SCMI_HCLK_SD			23
++#define SCMI_CRYPTO_RNG_S		24
++#define SCMI_CRYPTO_CORE_S		25
++#define SCMI_CRYPTO_PKA_S		26
++#define SCMI_A_CRYPTO_S			27
++#define SCMI_H_CRYPTO_S			28
++#define SCMI_P_CRYPTO_S			29
++#define SCMI_A_KEYLADDER_S		30
++#define SCMI_H_KEYLADDER_S		31
++#define SCMI_P_KEYLADDER_S		32
++#define SCMI_TRNG_S			33
++#define SCMI_H_TRNG_S			34
++#define SCMI_P_OTPC_S			35
++#define SCMI_OTPC_S			36
++#define SCMI_OTP_PHY			37
++#define SCMI_OTPC_AUTO_RD		38
++#define SCMI_OTPC_ARB			39
++
++/******** DSUCRU **************************************/
++#define DSUCRU_CLKSEL_CON(n)		(0x0300 + (n) * 4)
++
++/********Name=DSUCRU_CLKSEL_CON04,Offset=0x310********/
++#define PCLK_DSU_ROOT_SEL_SHIFT		5
++#define PCLK_DSU_ROOT_SEL_MASK		0x3
++#define PCLK_DSU_ROOT_SEL_GPLL		0x3
++
++/********Name=SECURE_SOFTRST_CON00,Offset=0xA00********/
++#define SRST_A_SECURE_NS_BIU		10
++#define SRST_H_SECURE_NS_BIU		11
++#define SRST_A_SECURE_S_BIU		12
++#define SRST_H_SECURE_S_BIU		13
++#define SRST_P_SECURE_S_BIU		14
++#define SRST_CRYPTO_CORE		15
++/********Name=SECURE_SOFTRST_CON01,Offset=0xA04********/
++#define SRST_CRYPTO_PKA			16
++#define SRST_CRYPTO_RNG			17
++#define SRST_A_CRYPTO			18
++#define SRST_H_CRYPTO			19
++#define SRST_KEYLADDER_CORE		25
++#define SRST_KEYLADDER_RNG		26
++#define SRST_A_KEYLADDER		27
++#define SRST_H_KEYLADDER		28
++#define SRST_P_OTPC_S			29
++#define SRST_OTPC_S			30
++#define SRST_WDT_S			31
++/********Name=SECURE_SOFTRST_CON02,Offset=0xA08********/
++#define SRST_T_WDT_S			32
++#define SRST_H_BOOTROM			33
++#define SRST_A_DCF			34
++#define SRST_P_DCF			35
++#define SRST_H_BOOTROM_NS		37
++#define SRST_P_KEYLADDER		46
++#define SRST_H_TRNG_S			47
++/********Name=SECURE_SOFTRST_CON03,Offset=0xA0C********/
++#define SRST_H_TRNG_NS			48
++#define SRST_D_SDMMC_BUFFER		49
++#define SRST_H_SDMMC			50
++#define SRST_H_SDMMC_BUFFER		51
++#define SRST_SDMMC			52
++#define SRST_P_TRNG_CHK			53
++#define SRST_TRNG_S			54
++
++#define SRST_INVALID			55
++
++void pvtplls_suspend(void);
++void pvtplls_resume(void);
++
++void rockchip_clock_init(void);
++
++#endif
+diff --git a/plat/rockchip/rk3588/drivers/scmi/rk3588_rstd.c b/plat/rockchip/rk3588/drivers/scmi/rk3588_rstd.c
+new file mode 100644
+index 000000000..50b99e727
+--- /dev/null
++++ b/plat/rockchip/rk3588/drivers/scmi/rk3588_rstd.c
+@@ -0,0 +1,96 @@
++/*
++ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ */
++
++#include <assert.h>
++#include <errno.h>
++
++#include <drivers/delay_timer.h>
++#include <drivers/scmi.h>
++#include <lib/mmio.h>
++#include <platform_def.h>
++
++#include <plat_private.h>
++#include "rk3588_clk.h"
++#include <scmi_rstd.h>
++#include <soc.h>
++
++#define DEFAULT_RESET_DOM_ATTRIBUTE	0
++
++#define RK3588_SCMI_RESET(_id, _name, _attribute, _ops)		\
++{								\
++	.id = _id,						\
++	.name = _name,						\
++	.attribute = _attribute,				\
++	.rstd_ops = _ops,					\
++}
++
++static int rk3588_reset_explicit(rk_scmi_rstd_t *reset_domain,
++				 bool assert_not_deassert)
++{
++	int bank = reset_domain->id / 16;
++	int offset = reset_domain->id % 16;
++
++	mmio_write_32(SCRU_BASE + CRU_SOFTRST_CON(bank),
++		      BITS_WITH_WMASK(assert_not_deassert, 0x1U, offset));
++	return SCMI_SUCCESS;
++}
++
++static struct rk_scmi_rstd_ops rk3588_reset_domain_ops = {
++	.reset_explicit = rk3588_reset_explicit,
++};
++
++static rk_scmi_rstd_t rk3588_reset_domain_table[] = {
++	RK3588_SCMI_RESET(SRST_CRYPTO_CORE, "scmi_sr_cy_core", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_CRYPTO_PKA, "scmi_sr_cy_pka", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_CRYPTO_RNG, "scmi_sr_cy_rng", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_A_CRYPTO, "scmi_sr_a_cy", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_H_CRYPTO, "scmi_sr_h_cy", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_KEYLADDER_CORE, "scmi_sr_k_core", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_KEYLADDER_RNG, "scmi_sr_k_rng", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_P_OTPC_S, "scmi_sr_p_otp", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_OTPC_S, "scmi_sr_otp", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_WDT_S, "scmi_sr_wdt", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_T_WDT_S, "scmi_sr_t_wdt", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_H_BOOTROM, "scmi_sr_h_boot", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_P_KEYLADDER, "scmi_sr_p_ky", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_H_TRNG_S, "scmi_sr_h_trng", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_H_TRNG_NS, "scmi_sr_t_trng", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_D_SDMMC_BUFFER, "scmi_sr_d_sd", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_H_SDMMC, "scmi_sr_h_sd", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_H_SDMMC_BUFFER, "scmi_sr_h_sd_b", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_SDMMC, "scmi_sr_sd", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_P_TRNG_CHK, "scmi_sr_p_trng", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_TRNG_S, "scmi_sr_trng", DEFAULT_RESET_DOM_ATTRIBUTE, &rk3588_reset_domain_ops),
++	RK3588_SCMI_RESET(SRST_INVALID, "scmi_sr_invalid", DEFAULT_RESET_DOM_ATTRIBUTE, NULL),
++};
++
++static rk_scmi_rstd_t *
++rockchip_get_reset_domain_table(int id)
++{
++	rk_scmi_rstd_t *reset = rk3588_reset_domain_table;
++	int i = 0, cnt = ARRAY_SIZE(rk3588_reset_domain_table);
++
++	for (i = 0; i < cnt; i++) {
++		if (reset->id == id)
++			return &rk3588_reset_domain_table[i];
++		reset++;
++	}
++
++	return &rk3588_reset_domain_table[cnt - 1];
++}
++
++rk_scmi_rstd_t *rockchip_scmi_get_rstd(unsigned int agent_id,
++				       unsigned int scmi_id)
++
++{
++	return rockchip_get_reset_domain_table(scmi_id);
++}
++
++size_t rockchip_scmi_rstd_count(unsigned int agent_id)
++{
++	return SRST_TRNG_S;
++}
++
+diff --git a/plat/rockchip/rk3588/drivers/soc/soc.c b/plat/rockchip/rk3588/drivers/soc/soc.c
+index a2768594c..6db81eeba 100644
+--- a/plat/rockchip/rk3588/drivers/soc/soc.c
++++ b/plat/rockchip/rk3588/drivers/soc/soc.c
+@@ -19,6 +19,7 @@
+ #include <pmu.h>
+ 
+ #include <plat_private.h>
++#include <rk3588_clk.h>
+ #include <secure.h>
+ #include <soc.h>
+ 
+@@ -89,8 +90,10 @@ static void system_reset_init(void)
+ 
+ void plat_rockchip_soc_init(void)
+ {
++	rockchip_clock_init();
+ 	secure_timer_init();
+ 	timer_hp_init();
+ 	system_reset_init();
+ 	sgrf_init();
++	rockchip_init_scmi_server();
+ }
+diff --git a/plat/rockchip/rk3588/plat_sip_calls.c b/plat/rockchip/rk3588/plat_sip_calls.c
+index 57f5de507..496e8d751 100644
+--- a/plat/rockchip/rk3588/plat_sip_calls.c
++++ b/plat/rockchip/rk3588/plat_sip_calls.c
+@@ -6,6 +6,7 @@
+ 
+ #include <common/debug.h>
+ #include <common/runtime_svc.h>
++#include <drivers/scmi-msg.h>
+ 
+ #include <plat_sip_calls.h>
+ #include <rockchip_sip_svc.h>
+@@ -20,6 +21,10 @@ uintptr_t rockchip_plat_sip_handler(uint32_t smc_fid,
+ 				    u_register_t flags)
+ {
+ 	switch (smc_fid) {
++	case RK_SIP_SCMI_AGENT0:
++		scmi_smt_fastcall_smc_entry(0);
++		SMC_RET1(handle, 0);
++
+ 	default:
+ 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+ 		SMC_RET1(handle, SMC_UNK);
+diff --git a/plat/rockchip/rk3588/platform.mk b/plat/rockchip/rk3588/platform.mk
+index f98781530..07eda400e 100644
+--- a/plat/rockchip/rk3588/platform.mk
++++ b/plat/rockchip/rk3588/platform.mk
+@@ -21,13 +21,16 @@ include drivers/arm/gic/v3/gicv3.mk
+ 
+ PLAT_INCLUDES		:=	-Iinclude/plat/common				\
+ 				-Idrivers/arm/gic/v3/				\
++				-Idrivers/scmi-msg/				\
+ 				-I${RK_PLAT_COMMON}/				\
+ 				-I${RK_PLAT_COMMON}/drivers/pmu/		\
+ 				-I${RK_PLAT_COMMON}/drivers/parameter/		\
+ 				-I${RK_PLAT_COMMON}/include/			\
+ 				-I${RK_PLAT_COMMON}/pmusram/			\
++				-I${RK_PLAT_COMMON}/scmi/			\
+ 				-I${RK_PLAT_SOC}/				\
+ 				-I${RK_PLAT_SOC}/drivers/pmu/			\
++				-I${RK_PLAT_SOC}/drivers/scmi/			\
+ 				-I${RK_PLAT_SOC}/drivers/secure/		\
+ 				-I${RK_PLAT_SOC}/drivers/soc/			\
+ 				-I${RK_PLAT_SOC}/include/
+@@ -50,6 +53,11 @@ BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
+ 				drivers/ti/uart/aarch64/16550_console.S		\
+ 				drivers/delay_timer/delay_timer.c		\
+ 				drivers/delay_timer/generic_delay_timer.c	\
++				drivers/scmi-msg/base.c				\
++				drivers/scmi-msg/clock.c			\
++				drivers/scmi-msg/entry.c			\
++				drivers/scmi-msg/reset_domain.c			\
++				drivers/scmi-msg/smt.c				\
+ 				lib/cpus/aarch64/cortex_a55.S			\
+ 				lib/cpus/aarch64/cortex_a76.S			\
+ 				${RK_PLAT_COMMON}/aarch64/plat_helpers.S	\
+@@ -61,11 +69,16 @@ BL31_SOURCES		+=	${RK_GIC_SOURCES}				\
+ 				${RK_PLAT_COMMON}/params_setup.c                \
+ 				${RK_PLAT_COMMON}/pmusram/cpus_on_fixed_addr.S	\
+ 				${RK_PLAT_COMMON}/rockchip_sip_svc.c		\
++				${RK_PLAT_COMMON}/scmi/scmi.c			\
++				${RK_PLAT_COMMON}/scmi/scmi_clock.c		\
++				${RK_PLAT_COMMON}/scmi/scmi_rstd.c		\
+ 				${RK_PLAT_SOC}/plat_sip_calls.c         	\
+ 				${RK_PLAT_SOC}/drivers/secure/secure.c		\
+ 				${RK_PLAT_SOC}/drivers/soc/soc.c		\
+ 				${RK_PLAT_SOC}/drivers/pmu/pmu.c		\
+-				${RK_PLAT_SOC}/drivers/pmu/pm_pd_regs.c
++				${RK_PLAT_SOC}/drivers/pmu/pm_pd_regs.c		\
++				${RK_PLAT_SOC}/drivers/scmi/rk3588_clk.c	\
++				${RK_PLAT_SOC}/drivers/scmi/rk3588_rstd.c
+ 
+ CTX_INCLUDE_AARCH32_REGS :=     0
+ ENABLE_PLAT_COMPAT	:=	0
+diff --git a/plat/rockchip/rk3588/rk3588_def.h b/plat/rockchip/rk3588/rk3588_def.h
+index 75b685a0a..412495a8b 100644
+--- a/plat/rockchip/rk3588/rk3588_def.h
++++ b/plat/rockchip/rk3588/rk3588_def.h
+@@ -162,6 +162,9 @@
+ #define	SCMI_SHARE_MEM_BASE	(SHARE_MEM_BASE + SHARE_MEM_SIZE)
+ #define	SCMI_SHARE_MEM_SIZE	SIZE_K(4)
+ 
++#define SMT_BUFFER_BASE		SCMI_SHARE_MEM_BASE
++#define SMT_BUFFER0_BASE	SMT_BUFFER_BASE
++
+ /**************************************************************************
+  * UART related constants
+  **************************************************************************/
+-- 
+2.46.0
+
+
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fix-gcc-locations.patch b/fix-gcc-locations.patch new file mode 100644 index 0000000000000000000000000000000000000000..51d4a89d54f0ce5479cf1cd3012b498c50a5be74 --- /dev/null +++ b/fix-gcc-locations.patch @@ -0,0 +1,27 @@ +From 732c6bbe2839f78e58ee2757580998dda1f0c0ac Mon Sep 17 00:00:00 2001 +From: Chris Kay +Date: Wed, 04 Sep 2024 14:04:44 +0000 +Subject: [PATCH] build: use `ar` over `gcc-ar` + +It has been a sufficiently long time since the last release of binutils +did not automatically enable the LTO plugin. Migrate to `ar` rather than +using the `gcc-ar` build wrapper, which saves us some pain trying to +locate the proper archiver. + +Change-Id: I6f8b895d6a470d2b7cd5b98ccb23c54b35d7ad12 +Signed-off-by: Chris Kay +--- + +diff --git a/make_helpers/toolchain.mk b/make_helpers/toolchain.mk +index 96e43a8..9a06a9c 100644 +--- a/make_helpers/toolchain.mk ++++ b/make_helpers/toolchain.mk +@@ -289,7 +289,7 @@ + guess-gnu-gcc-ld = $(1) + guess-gnu-gcc-oc = $(shell $(1) --print-prog-name objcopy 2>$(nul)) + guess-gnu-gcc-od = $(shell $(1) --print-prog-name objdump 2>$(nul)) +- guess-gnu-gcc-ar = $(call which,$(call decompat-path,$(patsubst %$(call file-name,$(1)),%$(subst gcc,gcc-ar,$(call file-name,$(1))),$(call compat-path,$(1))))) ++ guess-gnu-gcc-ar = $(shell $(1) --print-prog-name ar 2>$(nul)) + + define toolchain-warn-unrecognized + $$(warning ) diff --git a/v2.8.tar.gz b/v2.11.0.tar.gz similarity index 44% rename from v2.8.tar.gz rename to v2.11.0.tar.gz index 191e6e2d3238cff2262d16f947a6e702d0c077f6..48621939059061bc1814e6baf65ef8bb75bc5bfa 100644 Binary files a/v2.8.tar.gz and b/v2.11.0.tar.gz differ