From 0ea6a6560e38121242dfe5298071d3cdedb63a09 Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Mon, 26 Jun 2023 16:43:30 +0800 Subject: [PATCH] feat(rk3588): support rk3588 rk3588 is a eight-core soc and 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 Change-Id: I598109f15a2efd5b33aedd176cf708c08cb1dcf4 --- diff --git a/docs/plat/rockchip.rst b/docs/plat/rockchip.rst index 53f63b5..384cd73 100644 --- a/docs/plat/rockchip.rst +++ b/docs/plat/rockchip.rst @@ -11,6 +11,7 @@ - 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/rk3588/drivers/pmu/plat_pmu_macros.S b/plat/rockchip/rk3588/drivers/pmu/plat_pmu_macros.S new file mode 100644 index 0000000..c278899 --- /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 +#include +#include + +.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 0000000..78e8500 --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 0000000..8baf69a --- /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 + +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 0000000..83d6cad --- /dev/null +++ b/plat/rockchip/rk3588/drivers/pmu/pmu.c @@ -0,0 +1,1439 @@ +/* + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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)); + + 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 + + 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 0000000..7d8288c --- /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 + +#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/scmi/plat_scmi_def.h b/plat/rockchip/rk3588/drivers/scmi/plat_scmi_def.h new file mode 100644 index 0000000..0b9ca72 --- /dev/null +++ b/plat/rockchip/rk3588/drivers/scmi/plat_scmi_def.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_SCMI_DEF_H +#define PLAT_SCMI_DEF_H + +#include + +#define SMT_BUFFER_BASE SCMI_SHARE_MEM_BASE +#define SMT_BUFFER0_BASE SMT_BUFFER_BASE + +void rockchip_init_scmi_server(void); + +#endif /* PLAT_SCMI_DEF_H */ 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 0000000..ab3af5f --- /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 +#include + +#include +#include +#include +#include + +#include +#include "rk3588_clk.h" +#include +#include +#include + +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 0000000..66fddaa --- /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 0000000..f1f26d3 --- /dev/null +++ b/plat/rockchip/rk3588/drivers/scmi/rk3588_rstd.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "rk3588_clk.h" +#include +#include + +#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/secure/secure.c b/plat/rockchip/rk3588/drivers/secure/secure.c new file mode 100644 index 0000000..fc9f211 --- /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 +#include + +#include + +#include +#include + +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 0000000..d9c234f --- /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 0000000..06c784c --- /dev/null +++ b/plat/rockchip/rk3588/drivers/soc/soc.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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) +{ + rockchip_clock_init(); + secure_timer_init(); + timer_hp_init(); + system_reset_init(); + sgrf_init(); + rockchip_init_scmi_server(); +} diff --git a/plat/rockchip/rk3588/drivers/soc/soc.h b/plat/rockchip/rk3588/drivers/soc/soc.h new file mode 100644 index 0000000..9af179a --- /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 0000000..e3ea9cc --- /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 0000000..bc4455f --- /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 0000000..5946af0 --- /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 +#include + +#include + +#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 0000000..496e8d7 --- /dev/null +++ b/plat/rockchip/rk3588/plat_sip_calls.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024, Rockchip, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include + +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) { + 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 new file mode 100644 index 0000000..07eda40 --- /dev/null +++ b/plat/rockchip/rk3588/platform.mk @@ -0,0 +1,98 @@ +# +# 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/ \ + -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/ + +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 \ + 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 \ + ${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_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/scmi/rk3588_clk.c \ + ${RK_PLAT_SOC}/drivers/scmi/rk3588_rstd.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 0000000..75b685a --- /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__ */